]> code.delx.au - pulseaudio/blob - src/pulse/thread-mainloop.c
Handle when threaded mainloop is freed before it is started.
[pulseaudio] / src / pulse / thread-mainloop.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <signal.h>
28 #include <stdio.h>
29
30 #ifdef HAVE_SYS_POLL_H
31 #include <sys/poll.h>
32 #else
33 #include "../pulsecore/poll.h"
34 #endif
35
36 #include <pulse/xmalloc.h>
37
38 #include <pulsecore/log.h>
39 #include <pulsecore/hashmap.h>
40 #include <pulsecore/thread.h>
41 #include <pulsecore/mutex.h>
42
43 #include "mainloop.h"
44 #include "thread-mainloop.h"
45
46 struct pa_threaded_mainloop {
47 pa_mainloop *real_mainloop;
48 int n_waiting;
49
50 pa_thread* thread;
51 pa_mutex* mutex;
52 pa_cond* cond, *accept_cond;
53 };
54
55 static inline int in_worker(pa_threaded_mainloop *m) {
56 return pa_thread_self() == m->thread;
57 }
58
59 static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
60 pa_mutex *mutex = userdata;
61 int r;
62
63 assert(mutex);
64
65 /* Before entering poll() we unlock the mutex, so that
66 * avahi_simple_poll_quit() can succeed from another thread. */
67
68 pa_mutex_unlock(mutex);
69 r = poll(ufds, nfds, timeout);
70 pa_mutex_lock(mutex);
71
72 return r;
73 }
74
75 static void thread(void *userdata) {
76 pa_threaded_mainloop *m = userdata;
77
78 #ifndef OS_IS_WIN32
79 sigset_t mask;
80
81 /* Make sure that signals are delivered to the main thread */
82 sigfillset(&mask);
83 pthread_sigmask(SIG_BLOCK, &mask, NULL);
84 #endif
85
86 pa_mutex_lock(m->mutex);
87
88 pa_mainloop_run(m->real_mainloop, NULL);
89
90 pa_mutex_unlock(m->mutex);
91 }
92
93 pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
94 pa_threaded_mainloop *m;
95
96 m = pa_xnew(pa_threaded_mainloop, 1);
97
98 if (!(m->real_mainloop = pa_mainloop_new())) {
99 pa_xfree(m);
100 return NULL;
101 }
102
103 m->mutex = pa_mutex_new(1);
104 m->cond = pa_cond_new();
105 m->accept_cond = pa_cond_new();
106 m->thread = NULL;
107
108 pa_mainloop_set_poll_func(m->real_mainloop, poll_func, m->mutex);
109
110 m->n_waiting = 0;
111
112 return m;
113 }
114
115 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
116 assert(m);
117
118 /* Make sure that this function is not called from the helper thread */
119 assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m));
120
121 pa_threaded_mainloop_stop(m);
122
123 if (m->thread)
124 pa_thread_free(m->thread);
125
126 pa_mainloop_free(m->real_mainloop);
127
128 pa_mutex_free(m->mutex);
129 pa_cond_free(m->cond);
130 pa_cond_free(m->accept_cond);
131
132 pa_xfree(m);
133 }
134
135 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
136 assert(m);
137
138 assert(!m->thread || !pa_thread_is_running(m->thread));
139
140 if (!(m->thread = pa_thread_new(thread, m)))
141 return -1;
142
143 return 0;
144 }
145
146 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
147 assert(m);
148
149 if (!m->thread || !pa_thread_is_running(m->thread))
150 return;
151
152 /* Make sure that this function is not called from the helper thread */
153 assert(!in_worker(m));
154
155 pa_mutex_lock(m->mutex);
156 pa_mainloop_quit(m->real_mainloop, 0);
157 pa_mutex_unlock(m->mutex);
158
159 pa_thread_join(m->thread);
160 }
161
162 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
163 assert(m);
164
165 /* Make sure that this function is not called from the helper thread */
166 assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
167
168 pa_mutex_lock(m->mutex);
169 }
170
171 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
172 assert(m);
173
174 /* Make sure that this function is not called from the helper thread */
175 assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
176
177 pa_mutex_unlock(m->mutex);
178 }
179
180 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) {
181 assert(m);
182
183 pa_cond_signal(m->cond, 1);
184
185 if (wait_for_accept && m->n_waiting > 0)
186 pa_cond_wait(m->accept_cond, m->mutex);
187 }
188
189 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
190 assert(m);
191
192 /* Make sure that this function is not called from the helper thread */
193 assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
194
195 m->n_waiting ++;
196
197 pa_cond_wait(m->cond, m->mutex);
198
199 assert(m->n_waiting > 0);
200 m->n_waiting --;
201 }
202
203 void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) {
204 assert(m);
205
206 /* Make sure that this function is not called from the helper thread */
207 assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
208
209 pa_cond_signal(m->accept_cond, 0);
210 }
211
212 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
213 assert(m);
214
215 return pa_mainloop_get_retval(m->real_mainloop);
216 }
217
218 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
219 assert(m);
220
221 return pa_mainloop_get_api(m->real_mainloop);
222 }