add new threaded main loop implementation (with test/example)

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@823 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2006-04-30 23:34:17 +00:00
parent f2fbceb333
commit 9e60bad5c3
4 changed files with 342 additions and 0 deletions

View file

@ -181,6 +181,7 @@ pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
noinst_PROGRAMS = \ noinst_PROGRAMS = \
mainloop-test \ mainloop-test \
thread-mainloop-test \
mcalign-test \ mcalign-test \
pacat-simple \ pacat-simple \
parec-simple \ parec-simple \
@ -211,6 +212,11 @@ mainloop_test_CFLAGS = $(AM_CFLAGS)
mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la
mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
thread_mainloop_test_SOURCES = tests/thread-mainloop-test.c
thread_mainloop_test_CFLAGS = $(AM_CFLAGS)
thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la
thread_mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_SOURCES = tests/mcalign-test.c
mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_CFLAGS = $(AM_CFLAGS)
mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la
@ -290,6 +296,7 @@ polypinclude_HEADERS = \
polyp/mainloop.h \ polyp/mainloop.h \
polyp/mainloop-api.h \ polyp/mainloop-api.h \
polyp/mainloop-signal.h \ polyp/mainloop-signal.h \
polyp/thread-mainloop.h \
polyp/polypaudio.h \ polyp/polypaudio.h \
polyp/context.h \ polyp/context.h \
polyp/def.h \ polyp/def.h \
@ -348,6 +355,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \
polyp/volume.c polyp/volume.h \ polyp/volume.c polyp/volume.h \
polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop.c polyp/mainloop.h \
polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \
polyp/thread-mainloop.c polyp/thread-mainloop.h \
polypcore/poll.c polypcore/poll.h polypcore/poll.c polypcore/poll.h
# Internal stuff that is shared with libpolypcore # Internal stuff that is shared with libpolypcore

203
src/polyp/thread-mainloop.c Normal file
View file

@ -0,0 +1,203 @@
/* $Id$ */
/***
This file is part of polypaudio.
polypaudio 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.
polypaudio 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 polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pthread.h>
#include <assert.h>
#include <signal.h>
#include <sys/poll.h>
#include <stdio.h>
#include <polypcore/xmalloc.h>
#include "mainloop.h"
#include "thread-mainloop.h"
struct pa_threaded_mainloop {
pa_mainloop *real_mainloop;
pthread_t thread_id;
pthread_mutex_t mutex;
pthread_cond_t cond;
int thread_running;
};
static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
pthread_mutex_t *mutex = userdata;
int r;
assert(mutex);
/* Before entering poll() we unlock the mutex, so that
* avahi_simple_poll_quit() can succeed from another thread. */
pthread_mutex_unlock(mutex);
r = poll(ufds, nfds, timeout);
pthread_mutex_lock(mutex);
return r;
}
static void* thread(void *userdata){
pa_threaded_mainloop *m = userdata;
sigset_t mask;
/* Make sure that signals are delivered to the main thread */
sigfillset(&mask);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
pthread_mutex_lock(&m->mutex);
pa_mainloop_run(m->real_mainloop, NULL);
pthread_mutex_unlock(&m->mutex);
return NULL;
}
pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
pa_threaded_mainloop *m;
pthread_mutexattr_t a;
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);
pthread_mutexattr_init(&a);
pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m->mutex, NULL);
pthread_mutexattr_destroy(&a);
pthread_cond_init(&m->cond, NULL);
m->thread_running = 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 || !pthread_equal(pthread_self(), m->thread_id));
if (m->thread_running)
pa_threaded_mainloop_stop(m);
if (m->real_mainloop)
pa_mainloop_free(m->real_mainloop);
pthread_mutex_destroy(&m->mutex);
pthread_cond_destroy(&m->cond);
pa_xfree(m);
}
int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
assert(m);
assert(!m->thread_running);
pthread_mutex_lock(&m->mutex);
if (pthread_create(&m->thread_id, NULL, thread, m) < 0) {
pthread_mutex_unlock(&m->mutex);
return -1;
}
m->thread_running = 1;
pthread_mutex_unlock(&m->mutex);
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(!pthread_equal(pthread_self(), m->thread_id));
pthread_mutex_lock(&m->mutex);
pa_mainloop_quit(m->real_mainloop, 0);
pthread_mutex_unlock(&m->mutex);
pthread_join(m->thread_id, NULL);
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 || !pthread_equal(pthread_self(), m->thread_id));
pthread_mutex_lock(&m->mutex);
}
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 || !pthread_equal(pthread_self(), m->thread_id));
pthread_mutex_unlock(&m->mutex);
}
void pa_threaded_mainloop_signal(pa_threaded_mainloop *m) {
assert(m);
/* Make sure that this function is called from the helper thread */
assert(m->thread_running && pthread_equal(pthread_self(), m->thread_id));
pthread_cond_broadcast(&m->cond);
}
void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
assert(m);
/* Make sure that this function is not called from the helper thread */
assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id));
pthread_cond_wait(&m->cond, &m->mutex);
}
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);
}

View file

@ -0,0 +1,58 @@
#ifndef foothreadmainloophfoo
#define foothreadmainloophfoo
/* $Id$ */
/***
This file is part of polypaudio.
polypaudio 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.
polypaudio 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 polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include <polyp/mainloop-api.h>
#include <polyp/cdecl.h>
PA_C_DECL_BEGIN
/** \file
*
* A thread based main loop implementation based on pa_mainloop.*/
/** An opaque main loop object */
typedef struct pa_threaded_mainloop pa_threaded_mainloop;
/** Allocate a new main loop object */
pa_threaded_mainloop *pa_threaded_mainloop_new(void);
/** Free a main loop object */
void pa_threaded_mainloop_free(pa_threaded_mainloop* m);
int pa_threaded_mainloop_start(pa_threaded_mainloop *m);
void pa_threaded_mainloop_stop(pa_threaded_mainloop *m);
void pa_threaded_mainloop_lock(pa_threaded_mainloop *m);
void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m);
void pa_threaded_mainloop_signal(pa_threaded_mainloop *m);
void pa_threaded_mainloop_wait(pa_threaded_mainloop *m);
/** Return the return value as specified with the main loop's quit() routine. */
int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m);
/** Return the abstract main loop abstraction layer vtable for this main loop. */
pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m);
PA_C_DECL_END
#endif

View file

@ -0,0 +1,73 @@
/* $Id$ */
/***
This file is part of polypaudio.
polypaudio 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.
polypaudio 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 polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <polypcore/gccmacro.h>
#include <polypcore/util.h>
#include <polyp/thread-mainloop.h>
static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
fprintf(stderr, "TIME EVENT\n");
pa_threaded_mainloop_signal(userdata);
}
int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) {
pa_mainloop_api *a;
pa_threaded_mainloop *m;
struct timeval tv;
m = pa_threaded_mainloop_new();
assert(m);
a = pa_threaded_mainloop_get_api(m);
assert(a);
pa_threaded_mainloop_start(m);
pa_threaded_mainloop_lock(m);
pa_gettimeofday(&tv);
tv.tv_sec += 5;
a->time_new(a, &tv, tcb, m);
fprintf(stderr, "waiting 5s (signal)\n");
pa_threaded_mainloop_wait(m);
fprintf(stderr, "wait completed\n");
pa_threaded_mainloop_unlock(m);
fprintf(stderr, "waiting 5s (sleep)\n");
sleep(5);
fprintf(stderr, "shutting down\n");
pa_threaded_mainloop_stop(m);
pa_threaded_mainloop_free(m);
return 0;
}