From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/thread-mainloop.c | 466 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 src/pulse/thread-mainloop.c (limited to 'src/pulse/thread-mainloop.c') diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c new file mode 100644 index 00000000..34f0f250 --- /dev/null +++ b/src/pulse/thread-mainloop.c @@ -0,0 +1,466 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + 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, + 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 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "../pulsecore/poll.h" +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include + +#include +#include + +#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 +}; + +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 +} + +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 + + int r; + + 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 + + return r; +} + +#ifdef OS_IS_WIN32 +static DWORD WINAPI thread(void *userdata) { +#else +static void* thread(void *userdata) { +#endif + pa_threaded_mainloop *m = userdata; + +#ifndef OS_IS_WIN32 + sigset_t mask; + + /* Make sure that signals are delivered to the main thread */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); +#endif + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else + pthread_mutex_lock(&m->mutex); +#endif + + 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_threaded_mainloop *pa_threaded_mainloop_new(void) { + pa_threaded_mainloop *m; +#ifndef OS_IS_WIN32 + pthread_mutexattr_t a; +#endif + + m = pa_xnew(pa_threaded_mainloop, 1); + + if (!(m->real_mainloop = pa_mainloop_new())) { + pa_xfree(m); + 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->thread_running = 0; + m->n_waiting = 0; + + return m; +} + +void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + + if (m->thread_running) + pa_threaded_mainloop_stop(m); + + if (m->real_mainloop) + pa_mainloop_free(m->real_mainloop); + +#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); + +#ifdef OS_IS_WIN32 + + EnterCriticalSection(&m->mutex); + + m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); + if (!m->thread) { + LeaveCriticalSection(&m->mutex); + 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); + + if (!m->thread_running) + 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_mainloop_quit(m->real_mainloop, 0); + +#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; +} + +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else + pthread_mutex_lock(&m->mutex); +#endif +} + +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else + pthread_mutex_unlock(&m->mutex); +#endif +} + +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); + +#else + + pthread_cond_wait(&m->accept_cond, &m->mutex); + +#endif + + } +} + +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { +#ifdef OS_IS_WIN32 + HANDLE event; + DWORD result; +#endif + + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !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_hashmap_remove(m->cond_events, event); + + CloseHandle(event); + +#else + + pthread_cond_wait(&m->cond, &m->mutex); + +#endif + + assert(m->n_waiting > 0); + m->n_waiting --; +} + +void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + SetEvent(m->accept_cond); +#else + pthread_cond_signal(&m->accept_cond); +#endif +} + +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { + assert(m); + + return pa_mainloop_get_retval(m->real_mainloop); +} + +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { + 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); +} + +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { + assert(0); +} + +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) */ -- cgit