From 821dc1797faa903618c7585d3c053fd7ae6e93db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 8 Sep 2008 17:22:27 +0300 Subject: move autospawn lock to pulsecore/ since we don't need it in the client anymore --- src/Makefile.am | 7 +- src/daemon/main.c | 2 +- src/pulse/lock-autospawn.c | 330 ---------------------------------------- src/pulse/lock-autospawn.h | 32 ---- src/pulsecore/lock-autospawn.c | 330 ++++++++++++++++++++++++++++++++++++++++ src/pulsecore/lock-autospawn.h | 32 ++++ src/tests/lock-autospawn-test.c | 2 +- 7 files changed, 367 insertions(+), 368 deletions(-) delete mode 100644 src/pulse/lock-autospawn.c delete mode 100644 src/pulse/lock-autospawn.h create mode 100644 src/pulsecore/lock-autospawn.c create mode 100644 src/pulsecore/lock-autospawn.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 3ee53722..1663d66d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -541,8 +541,7 @@ libpulse_la_SOURCES = \ pulse/xmalloc.c pulse/xmalloc.h \ pulse/proplist.c pulse/proplist.h \ pulse/ext-stream-restore.c pulse/ext-stream-restore.h \ - pulse/i18n.c pulse/i18n.h \ - pulse/lock-autospawn.c pulse/lock-autospawn.h + pulse/i18n.c pulse/i18n.h # Internal stuff that is shared with libpulsecore libpulse_la_SOURCES += \ @@ -740,8 +739,7 @@ libpulsecore_la_SOURCES = \ pulse/volume.c pulse/volume.h \ pulse/xmalloc.c pulse/xmalloc.h \ pulse/proplist.c pulse/proplist.h \ - pulse/i18n.c pulse/i18n.h \ - pulse/lock-autospawn.c pulse/lock-autospawn.h + pulse/i18n.c pulse/i18n.h # Pure core stuff (some are shared in libpulse though). libpulsecore_la_SOURCES += \ @@ -811,6 +809,7 @@ libpulsecore_la_SOURCES += \ pulsecore/start-child.c pulsecore/start-child.h \ pulsecore/envelope.c pulsecore/envelope.h \ pulsecore/proplist-util.c pulsecore/proplist-util.h \ + pulsecore/lock-autospawn.c pulsecore/lock-autospawn.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 diff --git a/src/daemon/main.c b/src/daemon/main.c index f91573b4..a9e8ed46 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -65,8 +65,8 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/pulse/lock-autospawn.c b/src/pulse/lock-autospawn.c deleted file mode 100644 index d36b669e..00000000 --- a/src/pulse/lock-autospawn.c +++ /dev/null @@ -1,330 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2008 Lennart Poettering - - 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 -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "lock-autospawn.h" - -/* So, why do we have this complex code here with threads and pipes - * and stuff? For two reasons: POSIX file locks are per-process, not - * per-file descriptor. That means that two contexts within the same - * process that try to create the autospawn lock might end up assuming - * they both managed to lock the file. And then, POSIX locking - * operations are synchronous. If two contexts run from the same event - * loop it must be made sure that they do not block each other, but - * that the locking operation can happen asynchronously. */ - -#define AUTOSPAWN_LOCK "autospawn.lock" - -static pa_mutex *mutex; - -static unsigned n_ref = 0; -static int lock_fd = -1; -static pa_mutex *lock_fd_mutex = NULL; -static pa_bool_t taken = FALSE; -static pa_thread *thread; -static int pipe_fd[2] = { -1, -1 }; - -static void destroy_mutex(void) PA_GCC_DESTRUCTOR; - -static int ref(void) { - - if (n_ref > 0) { - - pa_assert(pipe_fd[0] >= 0); - pa_assert(pipe_fd[1] >= 0); - - n_ref++; - - return 0; - } - - pa_assert(lock_fd < 0); - pa_assert(!lock_fd_mutex); - pa_assert(!taken); - pa_assert(!thread); - pa_assert(pipe_fd[0] < 0); - pa_assert(pipe_fd[1] < 0); - - if (pipe(pipe_fd) < 0) - return -1; - - lock_fd_mutex = pa_mutex_new(FALSE, FALSE); - - pa_make_fd_cloexec(pipe_fd[0]); - pa_make_fd_cloexec(pipe_fd[1]); - - pa_make_fd_nonblock(pipe_fd[1]); - pa_make_fd_nonblock(pipe_fd[0]); - - n_ref = 1; - return 0; -} - -static void unref(pa_bool_t after_fork) { - - pa_assert(n_ref > 0); - pa_assert(pipe_fd[0] >= 0); - pa_assert(pipe_fd[1] >= 0); - pa_assert(lock_fd_mutex); - - n_ref--; - - if (n_ref > 0) - return; - - pa_assert(!taken); - - if (thread) { - pa_thread_free(thread); - thread = NULL; - } - - pa_mutex_lock(lock_fd_mutex); - if (lock_fd >= 0) { - - if (after_fork) - pa_close(lock_fd); - else { - char *lf; - - if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) - pa_log_warn(_("Cannot access autospawn lock.")); - - pa_unlock_lockfile(lf, lock_fd); - pa_xfree(lf); - - lock_fd = -1; - } - } - pa_mutex_unlock(lock_fd_mutex); - - pa_mutex_free(lock_fd_mutex); - lock_fd_mutex = NULL; - - pa_close(pipe_fd[0]); - pa_close(pipe_fd[1]); - pipe_fd[0] = pipe_fd[1] = -1; -} - -static void ping(void) { - ssize_t s; - - pa_assert(pipe_fd[1] >= 0); - - for (;;) { - char x = 'x'; - - if ((s = write(pipe_fd[1], &x, 1)) == 1) - break; - - pa_assert(s < 0); - - if (errno == EAGAIN) - break; - - pa_assert(errno == EINTR); - } -} - -static void wait_for_ping(void) { - ssize_t s; - char x; - struct pollfd pfd; - int k; - - pa_assert(pipe_fd[0] >= 0); - - memset(&pfd, 0, sizeof(pfd)); - pfd.fd = pipe_fd[0]; - pfd.events = POLLIN; - - if ((k = poll(&pfd, 1, -1)) != 1) { - pa_assert(k < 0); - pa_assert(errno == EINTR); - } else if ((s = read(pipe_fd[0], &x, 1)) != 1) { - pa_assert(s < 0); - pa_assert(errno == EAGAIN); - } -} - -static void empty_pipe(void) { - char x[16]; - ssize_t s; - - pa_assert(pipe_fd[0] >= 0); - - if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) { - pa_assert(s < 0); - pa_assert(errno == EAGAIN); - } -} - -static void thread_func(void *u) { - int fd; - char *lf; - sigset_t fullset; - - /* No signals in this thread please */ - sigfillset(&fullset); - pthread_sigmask(SIG_BLOCK, &fullset, NULL); - - if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { - pa_log_warn(_("Cannot access autospawn lock.")); - goto finish; - } - - if ((fd = pa_lock_lockfile(lf)) < 0) - goto finish; - - pa_mutex_lock(lock_fd_mutex); - pa_assert(lock_fd < 0); - lock_fd = fd; - pa_mutex_unlock(lock_fd_mutex); - -finish: - pa_xfree(lf); - - ping(); -} - -static int start_thread(void) { - - if (!thread) - if (!(thread = pa_thread_new(thread_func, NULL))) - return -1; - - return 0; -} - -static void create_mutex(void) { - PA_ONCE_BEGIN { - mutex = pa_mutex_new(FALSE, FALSE); - } PA_ONCE_END; -} - -static void destroy_mutex(void) { - - if (mutex) - pa_mutex_free(mutex); -} - - -int pa_autospawn_lock_init(void) { - int ret = -1; - - create_mutex(); - pa_mutex_lock(mutex); - - if (ref() < 0) - ret = -1; - else - ret = pipe_fd[0]; - - pa_mutex_unlock(mutex); - - return ret; -} - -int pa_autospawn_lock_acquire(pa_bool_t block) { - int ret = -1; - - create_mutex(); - pa_mutex_lock(mutex); - pa_assert(n_ref >= 1); - - pa_mutex_lock(lock_fd_mutex); - - for (;;) { - - empty_pipe(); - - if (lock_fd >= 0 && !taken) { - taken = TRUE; - ret = 1; - break; - } - - if (lock_fd < 0) - if (start_thread() < 0) - break; - - if (!block) { - ret = 0; - break; - } - - pa_mutex_unlock(lock_fd_mutex); - pa_mutex_unlock(mutex); - - wait_for_ping(); - - pa_mutex_lock(mutex); - pa_mutex_lock(lock_fd_mutex); - } - - pa_mutex_unlock(lock_fd_mutex); - - pa_mutex_unlock(mutex); - - return ret; -} - -void pa_autospawn_lock_release(void) { - - create_mutex(); - pa_mutex_lock(mutex); - pa_assert(n_ref >= 1); - - pa_assert(taken); - taken = FALSE; - - ping(); - - pa_mutex_unlock(mutex); -} - -void pa_autospawn_lock_done(pa_bool_t after_fork) { - - create_mutex(); - pa_mutex_lock(mutex); - pa_assert(n_ref >= 1); - - unref(after_fork); - - pa_mutex_unlock(mutex); -} diff --git a/src/pulse/lock-autospawn.h b/src/pulse/lock-autospawn.h deleted file mode 100644 index c04c4bd1..00000000 --- a/src/pulse/lock-autospawn.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef foopulselockautospawnhfoo -#define foopulselockautospawnhfoo - -/*** - This file is part of PulseAudio. - - Copyright 2008 Lennart Poettering - - 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.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 - Lesser 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. -***/ - -#include - -int pa_autospawn_lock_init(void); -int pa_autospawn_lock_acquire(pa_bool_t block); -void pa_autospawn_lock_release(void); -void pa_autospawn_lock_done(pa_bool_t after_fork); - -#endif diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c new file mode 100644 index 00000000..d36b669e --- /dev/null +++ b/src/pulsecore/lock-autospawn.c @@ -0,0 +1,330 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "lock-autospawn.h" + +/* So, why do we have this complex code here with threads and pipes + * and stuff? For two reasons: POSIX file locks are per-process, not + * per-file descriptor. That means that two contexts within the same + * process that try to create the autospawn lock might end up assuming + * they both managed to lock the file. And then, POSIX locking + * operations are synchronous. If two contexts run from the same event + * loop it must be made sure that they do not block each other, but + * that the locking operation can happen asynchronously. */ + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static pa_mutex *mutex; + +static unsigned n_ref = 0; +static int lock_fd = -1; +static pa_mutex *lock_fd_mutex = NULL; +static pa_bool_t taken = FALSE; +static pa_thread *thread; +static int pipe_fd[2] = { -1, -1 }; + +static void destroy_mutex(void) PA_GCC_DESTRUCTOR; + +static int ref(void) { + + if (n_ref > 0) { + + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + + n_ref++; + + return 0; + } + + pa_assert(lock_fd < 0); + pa_assert(!lock_fd_mutex); + pa_assert(!taken); + pa_assert(!thread); + pa_assert(pipe_fd[0] < 0); + pa_assert(pipe_fd[1] < 0); + + if (pipe(pipe_fd) < 0) + return -1; + + lock_fd_mutex = pa_mutex_new(FALSE, FALSE); + + pa_make_fd_cloexec(pipe_fd[0]); + pa_make_fd_cloexec(pipe_fd[1]); + + pa_make_fd_nonblock(pipe_fd[1]); + pa_make_fd_nonblock(pipe_fd[0]); + + n_ref = 1; + return 0; +} + +static void unref(pa_bool_t after_fork) { + + pa_assert(n_ref > 0); + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + pa_assert(lock_fd_mutex); + + n_ref--; + + if (n_ref > 0) + return; + + pa_assert(!taken); + + if (thread) { + pa_thread_free(thread); + thread = NULL; + } + + pa_mutex_lock(lock_fd_mutex); + if (lock_fd >= 0) { + + if (after_fork) + pa_close(lock_fd); + else { + char *lf; + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) + pa_log_warn(_("Cannot access autospawn lock.")); + + pa_unlock_lockfile(lf, lock_fd); + pa_xfree(lf); + + lock_fd = -1; + } + } + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_free(lock_fd_mutex); + lock_fd_mutex = NULL; + + pa_close(pipe_fd[0]); + pa_close(pipe_fd[1]); + pipe_fd[0] = pipe_fd[1] = -1; +} + +static void ping(void) { + ssize_t s; + + pa_assert(pipe_fd[1] >= 0); + + for (;;) { + char x = 'x'; + + if ((s = write(pipe_fd[1], &x, 1)) == 1) + break; + + pa_assert(s < 0); + + if (errno == EAGAIN) + break; + + pa_assert(errno == EINTR); + } +} + +static void wait_for_ping(void) { + ssize_t s; + char x; + struct pollfd pfd; + int k; + + pa_assert(pipe_fd[0] >= 0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = pipe_fd[0]; + pfd.events = POLLIN; + + if ((k = poll(&pfd, 1, -1)) != 1) { + pa_assert(k < 0); + pa_assert(errno == EINTR); + } else if ((s = read(pipe_fd[0], &x, 1)) != 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void empty_pipe(void) { + char x[16]; + ssize_t s; + + pa_assert(pipe_fd[0] >= 0); + + if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void thread_func(void *u) { + int fd; + char *lf; + sigset_t fullset; + + /* No signals in this thread please */ + sigfillset(&fullset); + pthread_sigmask(SIG_BLOCK, &fullset, NULL); + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { + pa_log_warn(_("Cannot access autospawn lock.")); + goto finish; + } + + if ((fd = pa_lock_lockfile(lf)) < 0) + goto finish; + + pa_mutex_lock(lock_fd_mutex); + pa_assert(lock_fd < 0); + lock_fd = fd; + pa_mutex_unlock(lock_fd_mutex); + +finish: + pa_xfree(lf); + + ping(); +} + +static int start_thread(void) { + + if (!thread) + if (!(thread = pa_thread_new(thread_func, NULL))) + return -1; + + return 0; +} + +static void create_mutex(void) { + PA_ONCE_BEGIN { + mutex = pa_mutex_new(FALSE, FALSE); + } PA_ONCE_END; +} + +static void destroy_mutex(void) { + + if (mutex) + pa_mutex_free(mutex); +} + + +int pa_autospawn_lock_init(void) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + + if (ref() < 0) + ret = -1; + else + ret = pipe_fd[0]; + + pa_mutex_unlock(mutex); + + return ret; +} + +int pa_autospawn_lock_acquire(pa_bool_t block) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_mutex_lock(lock_fd_mutex); + + for (;;) { + + empty_pipe(); + + if (lock_fd >= 0 && !taken) { + taken = TRUE; + ret = 1; + break; + } + + if (lock_fd < 0) + if (start_thread() < 0) + break; + + if (!block) { + ret = 0; + break; + } + + pa_mutex_unlock(lock_fd_mutex); + pa_mutex_unlock(mutex); + + wait_for_ping(); + + pa_mutex_lock(mutex); + pa_mutex_lock(lock_fd_mutex); + } + + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_unlock(mutex); + + return ret; +} + +void pa_autospawn_lock_release(void) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_assert(taken); + taken = FALSE; + + ping(); + + pa_mutex_unlock(mutex); +} + +void pa_autospawn_lock_done(pa_bool_t after_fork) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + unref(after_fork); + + pa_mutex_unlock(mutex); +} diff --git a/src/pulsecore/lock-autospawn.h b/src/pulsecore/lock-autospawn.h new file mode 100644 index 00000000..c04c4bd1 --- /dev/null +++ b/src/pulsecore/lock-autospawn.h @@ -0,0 +1,32 @@ +#ifndef foopulselockautospawnhfoo +#define foopulselockautospawnhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + 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.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 + Lesser 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. +***/ + +#include + +int pa_autospawn_lock_init(void); +int pa_autospawn_lock_acquire(pa_bool_t block); +void pa_autospawn_lock_release(void); +void pa_autospawn_lock_done(pa_bool_t after_fork); + +#endif diff --git a/src/tests/lock-autospawn-test.c b/src/tests/lock-autospawn-test.c index cb3dc87c..80cfda6a 100644 --- a/src/tests/lock-autospawn-test.c +++ b/src/tests/lock-autospawn-test.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include static void thread_func(void*k) { -- cgit