]> code.delx.au - pulseaudio/blob - src/polyp/thread-mainloop.c
unhide padsp
[pulseaudio] / src / polyp / thread-mainloop.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio 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 polypaudio 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 polypaudio; 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 "../polypcore/poll.h"
34 #endif
35
36 #ifdef HAVE_PTHREAD
37 #include <pthread.h>
38 #endif
39
40 #ifdef HAVE_WINDOWS_H
41 #include <windows.h>
42 #endif
43
44 #include <polyp/xmalloc.h>
45
46 #include <polypcore/log.h>
47 #include <polypcore/hashmap.h>
48
49 #include "mainloop.h"
50 #include "thread-mainloop.h"
51
52 #if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32)
53
54 struct pa_threaded_mainloop {
55 pa_mainloop *real_mainloop;
56 int n_waiting;
57 int thread_running;
58
59 #ifdef OS_IS_WIN32
60 DWORD thread_id;
61 HANDLE thread;
62 CRITICAL_SECTION mutex;
63 pa_hashmap *cond_events;
64 HANDLE accept_cond;
65 #else
66 pthread_t thread_id;
67 pthread_mutex_t mutex;
68 pthread_cond_t cond, accept_cond;
69 #endif
70 };
71
72 static inline int in_worker(pa_threaded_mainloop *m) {
73 #ifdef OS_IS_WIN32
74 return GetCurrentThreadId() == m->thread_id;
75 #else
76 return pthread_equal(pthread_self(), m->thread_id);
77 #endif
78 }
79
80 static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
81 #ifdef OS_IS_WIN32
82 CRITICAL_SECTION *mutex = userdata;
83 #else
84 pthread_mutex_t *mutex = userdata;
85 #endif
86
87 int r;
88
89 assert(mutex);
90
91 /* Before entering poll() we unlock the mutex, so that
92 * avahi_simple_poll_quit() can succeed from another thread. */
93
94 #ifdef OS_IS_WIN32
95 LeaveCriticalSection(mutex);
96 #else
97 pthread_mutex_unlock(mutex);
98 #endif
99
100 r = poll(ufds, nfds, timeout);
101
102 #ifdef OS_IS_WIN32
103 EnterCriticalSection(mutex);
104 #else
105 pthread_mutex_lock(mutex);
106 #endif
107
108 return r;
109 }
110
111 #ifdef OS_IS_WIN32
112 static DWORD WINAPI thread(void *userdata) {
113 #else
114 static void* thread(void *userdata) {
115 #endif
116 pa_threaded_mainloop *m = userdata;
117
118 #ifndef OS_IS_WIN32
119 sigset_t mask;
120
121 /* Make sure that signals are delivered to the main thread */
122 sigfillset(&mask);
123 pthread_sigmask(SIG_BLOCK, &mask, NULL);
124 #endif
125
126 #ifdef OS_IS_WIN32
127 EnterCriticalSection(&m->mutex);
128 #else
129 pthread_mutex_lock(&m->mutex);
130 #endif
131
132 pa_mainloop_run(m->real_mainloop, NULL);
133
134 #ifdef OS_IS_WIN32
135 LeaveCriticalSection(&m->mutex);
136 #else
137 pthread_mutex_unlock(&m->mutex);
138 #endif
139
140 #ifdef OS_IS_WIN32
141 return 0;
142 #else
143 return NULL;
144 #endif
145 }
146
147 pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
148 pa_threaded_mainloop *m;
149 #ifndef OS_IS_WIN32
150 pthread_mutexattr_t a;
151 #endif
152
153 m = pa_xnew(pa_threaded_mainloop, 1);
154
155 if (!(m->real_mainloop = pa_mainloop_new())) {
156 pa_xfree(m);
157 return NULL;
158 }
159
160 pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex);
161
162 #ifdef OS_IS_WIN32
163 InitializeCriticalSection(&m->mutex);
164
165 m->cond_events = pa_hashmap_new(NULL, NULL);
166 assert(m->cond_events);
167 m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL);
168 assert(m->accept_cond);
169 #else
170 pthread_mutexattr_init(&a);
171 pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
172 pthread_mutex_init(&m->mutex, &a);
173 pthread_mutexattr_destroy(&a);
174
175 pthread_cond_init(&m->cond, NULL);
176 pthread_cond_init(&m->accept_cond, NULL);
177 #endif
178
179 m->thread_running = 0;
180 m->n_waiting = 0;
181
182 return m;
183 }
184
185 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
186 assert(m);
187
188 /* Make sure that this function is not called from the helper thread */
189 assert(!m->thread_running || !in_worker(m));
190
191 if (m->thread_running)
192 pa_threaded_mainloop_stop(m);
193
194 if (m->real_mainloop)
195 pa_mainloop_free(m->real_mainloop);
196
197 #ifdef OS_IS_WIN32
198 pa_hashmap_free(m->cond_events, NULL, NULL);
199 CloseHandle(m->accept_cond);
200 #else
201 pthread_mutex_destroy(&m->mutex);
202 pthread_cond_destroy(&m->cond);
203 pthread_cond_destroy(&m->accept_cond);
204 #endif
205
206 pa_xfree(m);
207 }
208
209 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
210 assert(m);
211
212 assert(!m->thread_running);
213
214 #ifdef OS_IS_WIN32
215
216 EnterCriticalSection(&m->mutex);
217
218 m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id);
219 if (!m->thread) {
220 LeaveCriticalSection(&m->mutex);
221 return -1;
222 }
223
224 #else
225
226 pthread_mutex_lock(&m->mutex);
227
228 if (pthread_create(&m->thread_id, NULL, thread, m) < 0) {
229 pthread_mutex_unlock(&m->mutex);
230 return -1;
231 }
232
233 #endif
234
235 m->thread_running = 1;
236
237 #ifdef OS_IS_WIN32
238 LeaveCriticalSection(&m->mutex);
239 #else
240 pthread_mutex_unlock(&m->mutex);
241 #endif
242
243 return 0;
244 }
245
246 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
247 assert(m);
248
249 if (!m->thread_running)
250 return;
251
252 /* Make sure that this function is not called from the helper thread */
253 assert(!in_worker(m));
254
255 #ifdef OS_IS_WIN32
256 EnterCriticalSection(&m->mutex);
257 #else
258 pthread_mutex_lock(&m->mutex);
259 #endif
260
261 pa_mainloop_quit(m->real_mainloop, 0);
262
263 #ifdef OS_IS_WIN32
264 LeaveCriticalSection(&m->mutex);
265 #else
266 pthread_mutex_unlock(&m->mutex);
267 #endif
268
269 #ifdef OS_IS_WIN32
270 WaitForSingleObject(m->thread, INFINITE);
271 CloseHandle(m->thread);
272 #else
273 pthread_join(m->thread_id, NULL);
274 #endif
275
276 m->thread_running = 0;
277
278 return;
279 }
280
281 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
282 assert(m);
283
284 /* Make sure that this function is not called from the helper thread */
285 assert(!m->thread_running || !in_worker(m));
286
287 #ifdef OS_IS_WIN32
288 EnterCriticalSection(&m->mutex);
289 #else
290 pthread_mutex_lock(&m->mutex);
291 #endif
292 }
293
294 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
295 assert(m);
296
297 /* Make sure that this function is not called from the helper thread */
298 assert(!m->thread_running || !in_worker(m));
299
300 #ifdef OS_IS_WIN32
301 LeaveCriticalSection(&m->mutex);
302 #else
303 pthread_mutex_unlock(&m->mutex);
304 #endif
305 }
306
307 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) {
308 #ifdef OS_IS_WIN32
309 void *iter;
310 const void *key;
311 HANDLE event;
312 #endif
313
314 assert(m);
315
316 #ifdef OS_IS_WIN32
317
318 iter = NULL;
319 while (1) {
320 pa_hashmap_iterate(m->cond_events, &iter, &key);
321 if (key == NULL)
322 break;
323 event = (HANDLE)pa_hashmap_get(m->cond_events, key);
324 SetEvent(event);
325 }
326
327 #else
328
329 pthread_cond_broadcast(&m->cond);
330
331 #endif
332
333 if (wait_for_accept && m->n_waiting > 0) {
334
335 #ifdef OS_IS_WIN32
336
337 /* This is just to make sure it's unsignaled */
338 WaitForSingleObject(m->accept_cond, 0);
339
340 LeaveCriticalSection(&m->mutex);
341
342 WaitForSingleObject(m->accept_cond, INFINITE);
343
344 EnterCriticalSection(&m->mutex);
345
346 #else
347
348 pthread_cond_wait(&m->accept_cond, &m->mutex);
349
350 #endif
351
352 }
353 }
354
355 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
356 #ifdef OS_IS_WIN32
357 HANDLE event;
358 DWORD result;
359 #endif
360
361 assert(m);
362
363 /* Make sure that this function is not called from the helper thread */
364 assert(!m->thread_running || !in_worker(m));
365
366 m->n_waiting ++;
367
368 #ifdef OS_IS_WIN32
369
370 event = CreateEvent(NULL, FALSE, FALSE, NULL);
371 assert(event);
372
373 pa_hashmap_put(m->cond_events, event, event);
374
375 LeaveCriticalSection(&m->mutex);
376
377 result = WaitForSingleObject(event, INFINITE);
378 assert(result == WAIT_OBJECT_0);
379
380 EnterCriticalSection(&m->mutex);
381
382 pa_hashmap_remove(m->cond_events, event);
383
384 CloseHandle(event);
385
386 #else
387
388 pthread_cond_wait(&m->cond, &m->mutex);
389
390 #endif
391
392 assert(m->n_waiting > 0);
393 m->n_waiting --;
394 }
395
396 void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) {
397 assert(m);
398
399 /* Make sure that this function is not called from the helper thread */
400 assert(!m->thread_running || !in_worker(m));
401
402 #ifdef OS_IS_WIN32
403 SetEvent(m->accept_cond);
404 #else
405 pthread_cond_signal(&m->accept_cond);
406 #endif
407 }
408
409 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
410 assert(m);
411
412 return pa_mainloop_get_retval(m->real_mainloop);
413 }
414
415 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
416 assert(m);
417
418 return pa_mainloop_get_api(m->real_mainloop);
419 }
420
421 #else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */
422
423 pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
424 pa_log_error(__FILE__": Threaded main loop not supported on this platform");
425 return NULL;
426 }
427
428 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
429 assert(0);
430 }
431
432 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
433 assert(0);
434 return -1;
435 }
436
437 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
438 assert(0);
439 }
440
441 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
442 assert(0);
443 }
444
445 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
446 assert(0);
447 }
448
449 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
450 assert(0);
451 }
452
453 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) {
454 assert(0);
455 }
456
457 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
458 assert(0);
459 }
460
461 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
462 assert(0);
463 return NULL;
464 }
465
466 #endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */