]>
code.delx.au - pulseaudio/blob - src/polyp/thread-mainloop.c
d036a23275392f18029f9656e5b688202d003510
4 This file is part of polypaudio.
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.
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.
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
30 #ifdef HAVE_SYS_POLL_H
33 #include "../polypcore/poll.h"
44 #include <polyp/xmalloc.h>
46 #include <polypcore/log.h>
47 #include <polypcore/hashmap.h>
50 #include "thread-mainloop.h"
52 #if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32)
54 struct pa_threaded_mainloop
{
55 pa_mainloop
*real_mainloop
;
62 CRITICAL_SECTION mutex
;
63 pa_hashmap
*cond_events
;
67 pthread_mutex_t mutex
;
68 pthread_cond_t cond
, accept_cond
;
72 static inline int in_worker(pa_threaded_mainloop
*m
) {
74 return GetCurrentThreadId() == m
->thread_id
;
76 return pthread_equal(pthread_self(), m
->thread_id
);
80 static int poll_func(struct pollfd
*ufds
, unsigned long nfds
, int timeout
, void *userdata
) {
82 CRITICAL_SECTION
*mutex
= userdata
;
84 pthread_mutex_t
*mutex
= userdata
;
91 /* Before entering poll() we unlock the mutex, so that
92 * avahi_simple_poll_quit() can succeed from another thread. */
95 LeaveCriticalSection(mutex
);
97 pthread_mutex_unlock(mutex
);
100 r
= poll(ufds
, nfds
, timeout
);
103 EnterCriticalSection(mutex
);
105 pthread_mutex_lock(mutex
);
112 static DWORD WINAPI
thread(void *userdata
) {
114 static void* thread(void *userdata
) {
116 pa_threaded_mainloop
*m
= userdata
;
121 /* Make sure that signals are delivered to the main thread */
123 pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
127 EnterCriticalSection(&m
->mutex
);
129 pthread_mutex_lock(&m
->mutex
);
132 pa_mainloop_run(m
->real_mainloop
, NULL
);
135 LeaveCriticalSection(&m
->mutex
);
137 pthread_mutex_unlock(&m
->mutex
);
147 pa_threaded_mainloop
*pa_threaded_mainloop_new(void) {
148 pa_threaded_mainloop
*m
;
150 pthread_mutexattr_t a
;
153 m
= pa_xnew(pa_threaded_mainloop
, 1);
155 if (!(m
->real_mainloop
= pa_mainloop_new())) {
160 pa_mainloop_set_poll_func(m
->real_mainloop
, poll_func
, &m
->mutex
);
163 InitializeCriticalSection(&m
->mutex
);
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
);
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
);
175 pthread_cond_init(&m
->cond
, NULL
);
176 pthread_cond_init(&m
->accept_cond
, NULL
);
179 m
->thread_running
= 0;
185 void pa_threaded_mainloop_free(pa_threaded_mainloop
* m
) {
188 /* Make sure that this function is not called from the helper thread */
189 assert(!m
->thread_running
|| !in_worker(m
));
191 if (m
->thread_running
)
192 pa_threaded_mainloop_stop(m
);
194 if (m
->real_mainloop
)
195 pa_mainloop_free(m
->real_mainloop
);
198 pa_hashmap_free(m
->cond_events
, NULL
, NULL
);
199 CloseHandle(m
->accept_cond
);
201 pthread_mutex_destroy(&m
->mutex
);
202 pthread_cond_destroy(&m
->cond
);
203 pthread_cond_destroy(&m
->accept_cond
);
209 int pa_threaded_mainloop_start(pa_threaded_mainloop
*m
) {
212 assert(!m
->thread_running
);
216 EnterCriticalSection(&m
->mutex
);
218 m
->thread
= CreateThread(NULL
, 0, thread
, m
, 0, &m
->thread_id
);
220 LeaveCriticalSection(&m
->mutex
);
226 pthread_mutex_lock(&m
->mutex
);
228 if (pthread_create(&m
->thread_id
, NULL
, thread
, m
) < 0) {
229 pthread_mutex_unlock(&m
->mutex
);
235 m
->thread_running
= 1;
238 LeaveCriticalSection(&m
->mutex
);
240 pthread_mutex_unlock(&m
->mutex
);
246 void pa_threaded_mainloop_stop(pa_threaded_mainloop
*m
) {
249 if (!m
->thread_running
)
252 /* Make sure that this function is not called from the helper thread */
253 assert(!in_worker(m
));
256 EnterCriticalSection(&m
->mutex
);
258 pthread_mutex_lock(&m
->mutex
);
261 pa_mainloop_quit(m
->real_mainloop
, 0);
264 LeaveCriticalSection(&m
->mutex
);
266 pthread_mutex_unlock(&m
->mutex
);
270 WaitForSingleObject(m
->thread
, INFINITE
);
271 CloseHandle(m
->thread
);
273 pthread_join(m
->thread_id
, NULL
);
276 m
->thread_running
= 0;
281 void pa_threaded_mainloop_lock(pa_threaded_mainloop
*m
) {
284 /* Make sure that this function is not called from the helper thread */
285 assert(!m
->thread_running
|| !in_worker(m
));
288 EnterCriticalSection(&m
->mutex
);
290 pthread_mutex_lock(&m
->mutex
);
294 void pa_threaded_mainloop_unlock(pa_threaded_mainloop
*m
) {
297 /* Make sure that this function is not called from the helper thread */
298 assert(!m
->thread_running
|| !in_worker(m
));
301 LeaveCriticalSection(&m
->mutex
);
303 pthread_mutex_unlock(&m
->mutex
);
307 void pa_threaded_mainloop_signal(pa_threaded_mainloop
*m
, int wait_for_accept
) {
320 pa_hashmap_iterate(m
->cond_events
, &iter
, &key
);
323 event
= (HANDLE
)pa_hashmap_get(m
->cond_events
, key
);
329 pthread_cond_broadcast(&m
->cond
);
333 if (wait_for_accept
&& m
->n_waiting
> 0) {
337 /* This is just to make sure it's unsignaled */
338 WaitForSingleObject(m
->accept_cond
, 0);
340 LeaveCriticalSection(&m
->mutex
);
342 WaitForSingleObject(m
->accept_cond
, INFINITE
);
344 EnterCriticalSection(&m
->mutex
);
348 pthread_cond_wait(&m
->accept_cond
, &m
->mutex
);
355 void pa_threaded_mainloop_wait(pa_threaded_mainloop
*m
) {
363 /* Make sure that this function is not called from the helper thread */
364 assert(!m
->thread_running
|| !in_worker(m
));
370 event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
373 pa_hashmap_put(m
->cond_events
, event
, event
);
375 LeaveCriticalSection(&m
->mutex
);
377 result
= WaitForSingleObject(event
, INFINITE
);
378 assert(result
== WAIT_OBJECT_0
);
380 EnterCriticalSection(&m
->mutex
);
382 pa_hashmap_remove(m
->cond_events
, event
);
388 pthread_cond_wait(&m
->cond
, &m
->mutex
);
392 assert(m
->n_waiting
> 0);
396 void pa_threaded_mainloop_accept(pa_threaded_mainloop
*m
) {
399 /* Make sure that this function is not called from the helper thread */
400 assert(!m
->thread_running
|| !in_worker(m
));
403 SetEvent(m
->accept_cond
);
405 pthread_cond_signal(&m
->accept_cond
);
409 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop
*m
) {
412 return pa_mainloop_get_retval(m
->real_mainloop
);
415 pa_mainloop_api
* pa_threaded_mainloop_get_api(pa_threaded_mainloop
*m
) {
418 return pa_mainloop_get_api(m
->real_mainloop
);
421 #else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */
423 pa_threaded_mainloop
*pa_threaded_mainloop_new(void) {
424 pa_log_error(__FILE__
": Threaded main loop not supported on this platform");
428 void pa_threaded_mainloop_free(pa_threaded_mainloop
* m
) {
432 int pa_threaded_mainloop_start(pa_threaded_mainloop
*m
) {
437 void pa_threaded_mainloop_stop(pa_threaded_mainloop
*m
) {
441 void pa_threaded_mainloop_lock(pa_threaded_mainloop
*m
) {
445 void pa_threaded_mainloop_unlock(pa_threaded_mainloop
*m
) {
449 void pa_threaded_mainloop_wait(pa_threaded_mainloop
*m
) {
453 void pa_threaded_mainloop_signal(pa_threaded_mainloop
*m
, int wait_for_release
) {
457 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop
*m
) {
461 pa_mainloop_api
* pa_threaded_mainloop_get_api(pa_threaded_mainloop
*m
) {
466 #endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */