2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
6 PulseAudio 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.1 of the License,
9 or (at your option) any later version.
11 PulseAudio 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 PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #include <pulse/i18n.h>
34 #include <pulse/xmalloc.h>
36 #include <pulsecore/mutex.h>
37 #include <pulsecore/thread.h>
38 #include <pulsecore/core-util.h>
40 #include "lock-autospawn.h"
42 /* So, why do we have this complex code here with threads and pipes
43 * and stuff? For two reasons: POSIX file locks are per-process, not
44 * per-file descriptor. That means that two contexts within the same
45 * process that try to create the autospawn lock might end up assuming
46 * they both managed to lock the file. And then, POSIX locking
47 * operations are synchronous. If two contexts run from the same event
48 * loop it must be made sure that they do not block each other, but
49 * that the locking operation can happen asynchronously. */
51 #define AUTOSPAWN_LOCK "autospawn.lock"
53 static pa_mutex *mutex;
55 static unsigned n_ref = 0;
56 static int lock_fd = -1;
57 static pa_mutex *lock_fd_mutex = NULL;
58 static pa_thread *thread = NULL;
59 static int pipe_fd[2] = { -1, -1 };
68 static void destroy_mutex(void) PA_GCC_DESTRUCTOR;
70 static int ref(void) {
74 pa_assert(pipe_fd[0] >= 0);
75 pa_assert(pipe_fd[1] >= 0);
76 pa_assert(lock_fd_mutex);
83 pa_assert(!lock_fd_mutex);
84 pa_assert(state == STATE_IDLE);
85 pa_assert(lock_fd < 0);
87 pa_assert(pipe_fd[0] < 0);
88 pa_assert(pipe_fd[1] < 0);
90 if (pa_pipe_cloexec(pipe_fd) < 0)
93 pa_make_fd_nonblock(pipe_fd[1]);
94 pa_make_fd_nonblock(pipe_fd[0]);
96 lock_fd_mutex = pa_mutex_new(FALSE, FALSE);
102 static void unref(pa_bool_t after_fork) {
104 pa_assert(n_ref > 0);
105 pa_assert(pipe_fd[0] >= 0);
106 pa_assert(pipe_fd[1] >= 0);
107 pa_assert(lock_fd_mutex);
115 pa_thread_free(thread);
119 pa_mutex_lock(lock_fd_mutex);
121 pa_assert(state != STATE_TAKEN);
123 if (state == STATE_OWNING) {
125 pa_assert(lock_fd >= 0);
132 if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
133 pa_log_warn(_("Cannot access autospawn lock."));
135 pa_unlock_lockfile(lf, lock_fd);
143 pa_mutex_unlock(lock_fd_mutex);
145 pa_mutex_free(lock_fd_mutex);
146 lock_fd_mutex = NULL;
148 pa_close(pipe_fd[0]);
149 pa_close(pipe_fd[1]);
150 pipe_fd[0] = pipe_fd[1] = -1;
153 static void ping(void) {
156 pa_assert(pipe_fd[1] >= 0);
161 if ((s = write(pipe_fd[1], &x, 1)) == 1)
169 pa_assert(errno == EINTR);
173 static void wait_for_ping(void) {
179 pa_assert(pipe_fd[0] >= 0);
181 memset(&pfd, 0, sizeof(pfd));
185 if ((k = poll(&pfd, 1, -1)) != 1) {
187 pa_assert(errno == EINTR);
188 } else if ((s = read(pipe_fd[0], &x, 1)) != 1) {
190 pa_assert(errno == EAGAIN);
194 static void empty_pipe(void) {
198 pa_assert(pipe_fd[0] >= 0);
200 if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) {
202 pa_assert(errno == EAGAIN);
206 static void thread_func(void *u) {
211 /* No signals in this thread please */
212 sigfillset(&fullset);
213 pthread_sigmask(SIG_BLOCK, &fullset, NULL);
215 if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
216 pa_log_warn(_("Cannot access autospawn lock."));
220 if ((fd = pa_lock_lockfile(lf)) < 0)
223 pa_mutex_lock(lock_fd_mutex);
224 pa_assert(state == STATE_IDLE);
226 state = STATE_OWNING;
227 pa_mutex_unlock(lock_fd_mutex);
232 pa_mutex_lock(lock_fd_mutex);
233 pa_assert(state == STATE_IDLE);
234 state = STATE_FAILED;
235 pa_mutex_unlock(lock_fd_mutex);
243 static int start_thread(void) {
246 if (!(thread = pa_thread_new(thread_func, NULL)))
252 static void create_mutex(void) {
254 mutex = pa_mutex_new(FALSE, FALSE);
258 static void destroy_mutex(void) {
260 pa_mutex_free(mutex);
263 int pa_autospawn_lock_init(void) {
267 pa_mutex_lock(mutex);
274 pa_mutex_unlock(mutex);
279 int pa_autospawn_lock_acquire(pa_bool_t block) {
283 pa_mutex_lock(mutex);
284 pa_assert(n_ref >= 1);
286 pa_mutex_lock(lock_fd_mutex);
292 if (state == STATE_OWNING) {
298 if (state == STATE_FAILED) {
303 if (state == STATE_IDLE)
304 if (start_thread() < 0)
312 pa_mutex_unlock(lock_fd_mutex);
313 pa_mutex_unlock(mutex);
317 pa_mutex_lock(mutex);
318 pa_mutex_lock(lock_fd_mutex);
321 pa_mutex_unlock(lock_fd_mutex);
323 pa_mutex_unlock(mutex);
328 void pa_autospawn_lock_release(void) {
331 pa_mutex_lock(mutex);
332 pa_assert(n_ref >= 1);
334 pa_assert(state == STATE_TAKEN);
335 state = STATE_OWNING;
339 pa_mutex_unlock(mutex);
342 void pa_autospawn_lock_done(pa_bool_t after_fork) {
345 pa_mutex_lock(mutex);
346 pa_assert(n_ref >= 1);
350 pa_mutex_unlock(mutex);