diff options
Diffstat (limited to 'src/pulse/thread-mainloop.c')
| -rw-r--r-- | src/pulse/thread-mainloop.c | 409 |
1 files changed, 92 insertions, 317 deletions
diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 34f0f250..b07ad789 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -1,18 +1,19 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -23,96 +24,55 @@ #include <config.h> #endif -#include <assert.h> -#include <signal.h> -#include <stdio.h> - -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#else -#include "../pulsecore/poll.h" -#endif - -#ifdef HAVE_PTHREAD +#ifndef OS_IS_WIN32 #include <pthread.h> #endif -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif +#include <signal.h> +#include <stdio.h> #include <pulse/xmalloc.h> +#include <pulse/mainloop.h> +#include <pulse/i18n.h> #include <pulsecore/log.h> -#include <pulsecore/hashmap.h> +#include <pulsecore/thread.h> +#include <pulsecore/mutex.h> +#include <pulsecore/macro.h> +#include <pulsecore/poll.h> -#include "mainloop.h" #include "thread-mainloop.h" -#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) - struct pa_threaded_mainloop { pa_mainloop *real_mainloop; - int n_waiting; - int thread_running; - -#ifdef OS_IS_WIN32 - DWORD thread_id; - HANDLE thread; - CRITICAL_SECTION mutex; - pa_hashmap *cond_events; - HANDLE accept_cond; -#else - pthread_t thread_id; - pthread_mutex_t mutex; - pthread_cond_t cond, accept_cond; -#endif + volatile int n_waiting, n_waiting_for_accept; + + pa_thread* thread; + pa_mutex* mutex; + pa_cond* cond, *accept_cond; }; static inline int in_worker(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - return GetCurrentThreadId() == m->thread_id; -#else - return pthread_equal(pthread_self(), m->thread_id); -#endif + return pa_thread_self() == m->thread; } static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { -#ifdef OS_IS_WIN32 - CRITICAL_SECTION *mutex = userdata; -#else - pthread_mutex_t *mutex = userdata; -#endif - + pa_mutex *mutex = userdata; int r; - assert(mutex); + pa_assert(mutex); /* Before entering poll() we unlock the mutex, so that * avahi_simple_poll_quit() can succeed from another thread. */ -#ifdef OS_IS_WIN32 - LeaveCriticalSection(mutex); -#else - pthread_mutex_unlock(mutex); -#endif - - r = poll(ufds, nfds, timeout); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(mutex); -#else - pthread_mutex_lock(mutex); -#endif + pa_mutex_unlock(mutex); + r = pa_poll(ufds, nfds, timeout); + pa_mutex_lock(mutex); return r; } -#ifdef OS_IS_WIN32 -static DWORD WINAPI thread(void *userdata) { -#else -static void* thread(void *userdata) { -#endif +static void thread(void *userdata) { pa_threaded_mainloop *m = userdata; #ifndef OS_IS_WIN32 @@ -123,32 +83,17 @@ static void* thread(void *userdata) { pthread_sigmask(SIG_BLOCK, &mask, NULL); #endif -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif + pa_mutex_lock(m->mutex); pa_mainloop_run(m->real_mainloop, NULL); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - return 0; -#else - return NULL; -#endif + pa_mutex_unlock(m->mutex); } pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pa_threaded_mainloop *m; -#ifndef OS_IS_WIN32 - pthread_mutexattr_t a; -#endif + + pa_init_i18n(); m = pa_xnew(pa_threaded_mainloop, 1); @@ -157,310 +102,140 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { return NULL; } - pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); - -#ifdef OS_IS_WIN32 - InitializeCriticalSection(&m->mutex); - - m->cond_events = pa_hashmap_new(NULL, NULL); - assert(m->cond_events); - m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(m->accept_cond); -#else - pthread_mutexattr_init(&a); - pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->mutex, &a); - pthread_mutexattr_destroy(&a); - - pthread_cond_init(&m->cond, NULL); - pthread_cond_init(&m->accept_cond, NULL); -#endif + m->mutex = pa_mutex_new(TRUE, TRUE); + m->cond = pa_cond_new(); + m->accept_cond = pa_cond_new(); + m->thread = NULL; + + pa_mainloop_set_poll_func(m->real_mainloop, poll_func, m->mutex); - m->thread_running = 0; m->n_waiting = 0; + m->n_waiting_for_accept = 0; return m; } void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + pa_assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m)); - if (m->thread_running) - pa_threaded_mainloop_stop(m); + pa_threaded_mainloop_stop(m); - if (m->real_mainloop) - pa_mainloop_free(m->real_mainloop); + if (m->thread) + pa_thread_free(m->thread); + + pa_mainloop_free(m->real_mainloop); + + pa_mutex_free(m->mutex); + pa_cond_free(m->cond); + pa_cond_free(m->accept_cond); -#ifdef OS_IS_WIN32 - pa_hashmap_free(m->cond_events, NULL, NULL); - CloseHandle(m->accept_cond); -#else - pthread_mutex_destroy(&m->mutex); - pthread_cond_destroy(&m->cond); - pthread_cond_destroy(&m->accept_cond); -#endif - pa_xfree(m); } int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(m); - - assert(!m->thread_running); + pa_assert(m); -#ifdef OS_IS_WIN32 + pa_assert(!m->thread || !pa_thread_is_running(m->thread)); - EnterCriticalSection(&m->mutex); - - m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); - if (!m->thread) { - LeaveCriticalSection(&m->mutex); + if (!(m->thread = pa_thread_new("threaded-ml", thread, m))) return -1; - } - -#else - - pthread_mutex_lock(&m->mutex); - - if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { - pthread_mutex_unlock(&m->mutex); - return -1; - } - -#endif - - m->thread_running = 1; - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif return 0; } void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); - if (!m->thread_running) + if (!m->thread || !pa_thread_is_running(m->thread)) return; /* Make sure that this function is not called from the helper thread */ - assert(!in_worker(m)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif + pa_assert(!in_worker(m)); + pa_mutex_lock(m->mutex); pa_mainloop_quit(m->real_mainloop, 0); + pa_mutex_unlock(m->mutex); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - WaitForSingleObject(m->thread, INFINITE); - CloseHandle(m->thread); -#else - pthread_join(m->thread_id, NULL); -#endif - - m->thread_running = 0; - - return; + pa_thread_join(m->thread); } void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(m); - + pa_assert(m); + /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif + pa_mutex_lock(m->mutex); } void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(m); - + pa_assert(m); + /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif + pa_mutex_unlock(m->mutex); } +/* Called with the lock taken */ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { -#ifdef OS_IS_WIN32 - void *iter; - const void *key; - HANDLE event; -#endif - - assert(m); - -#ifdef OS_IS_WIN32 - - iter = NULL; - while (1) { - pa_hashmap_iterate(m->cond_events, &iter, &key); - if (key == NULL) - break; - event = (HANDLE)pa_hashmap_get(m->cond_events, key); - SetEvent(event); - } - -#else - - pthread_cond_broadcast(&m->cond); - -#endif - - if (wait_for_accept && m->n_waiting > 0) { - -#ifdef OS_IS_WIN32 - - /* This is just to make sure it's unsignaled */ - WaitForSingleObject(m->accept_cond, 0); - - LeaveCriticalSection(&m->mutex); - - WaitForSingleObject(m->accept_cond, INFINITE); - - EnterCriticalSection(&m->mutex); + pa_assert(m); -#else + pa_cond_signal(m->cond, 1); - pthread_cond_wait(&m->accept_cond, &m->mutex); - -#endif + if (wait_for_accept) { + m->n_waiting_for_accept ++; + while (m->n_waiting_for_accept > 0) + pa_cond_wait(m->accept_cond, m->mutex); } } +/* Called with the lock taken */ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - HANDLE event; - DWORD result; -#endif + pa_assert(m); - assert(m); - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); m->n_waiting ++; -#ifdef OS_IS_WIN32 - - event = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(event); - - pa_hashmap_put(m->cond_events, event, event); - - LeaveCriticalSection(&m->mutex); - - result = WaitForSingleObject(event, INFINITE); - assert(result == WAIT_OBJECT_0); - - EnterCriticalSection(&m->mutex); + pa_cond_wait(m->cond, m->mutex); - pa_hashmap_remove(m->cond_events, event); - - CloseHandle(event); - -#else - - pthread_cond_wait(&m->cond, &m->mutex); - -#endif - - assert(m->n_waiting > 0); + pa_assert(m->n_waiting > 0); m->n_waiting --; } +/* Called with the lock taken */ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { - assert(m); - + pa_assert(m); + /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - SetEvent(m->accept_cond); -#else - pthread_cond_signal(&m->accept_cond); -#endif + pa_assert(m->n_waiting_for_accept > 0); + m->n_waiting_for_accept --; + + pa_cond_signal(m->accept_cond, 0); } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); return pa_mainloop_get_retval(m->real_mainloop); } pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(m); + pa_assert(m); return pa_mainloop_get_api(m->real_mainloop); } -#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_log_error(__FILE__": Threaded main loop not supported on this platform"); - return NULL; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(0); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(0); - return -1; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { - assert(0); -} +int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) { + pa_assert(m); -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { - assert(0); + return m->thread && pa_thread_self() == m->thread; } - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(0); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(0); - return NULL; -} - -#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ |
