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 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_bool_t taken
= FALSE
;
59 static pa_thread
*thread
;
60 static int pipe_fd
[2] = { -1, -1 };
62 static void destroy_mutex(void) PA_GCC_DESTRUCTOR
;
64 static int ref(void) {
68 pa_assert(pipe_fd
[0] >= 0);
69 pa_assert(pipe_fd
[1] >= 0);
76 pa_assert(lock_fd
< 0);
77 pa_assert(!lock_fd_mutex
);
80 pa_assert(pipe_fd
[0] < 0);
81 pa_assert(pipe_fd
[1] < 0);
83 if (pipe(pipe_fd
) < 0)
86 lock_fd_mutex
= pa_mutex_new(FALSE
, FALSE
);
88 pa_make_fd_cloexec(pipe_fd
[0]);
89 pa_make_fd_cloexec(pipe_fd
[1]);
91 pa_make_fd_nonblock(pipe_fd
[1]);
92 pa_make_fd_nonblock(pipe_fd
[0]);
98 static void unref(pa_bool_t after_fork
) {
100 pa_assert(n_ref
> 0);
101 pa_assert(pipe_fd
[0] >= 0);
102 pa_assert(pipe_fd
[1] >= 0);
103 pa_assert(lock_fd_mutex
);
113 pa_thread_free(thread
);
117 pa_mutex_lock(lock_fd_mutex
);
125 if (!(lf
= pa_runtime_path(AUTOSPAWN_LOCK
)))
126 pa_log_warn(_("Cannot access autospawn lock."));
128 pa_unlock_lockfile(lf
, lock_fd
);
134 pa_mutex_unlock(lock_fd_mutex
);
136 pa_mutex_free(lock_fd_mutex
);
137 lock_fd_mutex
= NULL
;
139 pa_close(pipe_fd
[0]);
140 pa_close(pipe_fd
[1]);
141 pipe_fd
[0] = pipe_fd
[1] = -1;
144 static void ping(void) {
147 pa_assert(pipe_fd
[1] >= 0);
152 if ((s
= write(pipe_fd
[1], &x
, 1)) == 1)
160 pa_assert(errno
== EINTR
);
164 static void wait_for_ping(void) {
170 pa_assert(pipe_fd
[0] >= 0);
172 memset(&pfd
, 0, sizeof(pfd
));
176 if ((k
= poll(&pfd
, 1, -1)) != 1) {
178 pa_assert(errno
== EINTR
);
179 } else if ((s
= read(pipe_fd
[0], &x
, 1)) != 1) {
181 pa_assert(errno
== EAGAIN
);
185 static void empty_pipe(void) {
189 pa_assert(pipe_fd
[0] >= 0);
191 if ((s
= read(pipe_fd
[0], &x
, sizeof(x
))) < 1) {
193 pa_assert(errno
== EAGAIN
);
197 static void thread_func(void *u
) {
202 /* No signals in this thread please */
203 sigfillset(&fullset
);
204 pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
);
206 if (!(lf
= pa_runtime_path(AUTOSPAWN_LOCK
))) {
207 pa_log_warn(_("Cannot access autospawn lock."));
211 if ((fd
= pa_lock_lockfile(lf
)) < 0)
214 pa_mutex_lock(lock_fd_mutex
);
215 pa_assert(lock_fd
< 0);
217 pa_mutex_unlock(lock_fd_mutex
);
225 static int start_thread(void) {
228 if (!(thread
= pa_thread_new(thread_func
, NULL
)))
234 static void create_mutex(void) {
236 mutex
= pa_mutex_new(FALSE
, FALSE
);
240 static void destroy_mutex(void) {
243 pa_mutex_free(mutex
);
247 int pa_autospawn_lock_init(void) {
251 pa_mutex_lock(mutex
);
258 pa_mutex_unlock(mutex
);
263 int pa_autospawn_lock_acquire(pa_bool_t block
) {
267 pa_mutex_lock(mutex
);
268 pa_assert(n_ref
>= 1);
270 pa_mutex_lock(lock_fd_mutex
);
276 if (lock_fd
>= 0 && !taken
) {
283 if (start_thread() < 0)
291 pa_mutex_unlock(lock_fd_mutex
);
292 pa_mutex_unlock(mutex
);
296 pa_mutex_lock(mutex
);
297 pa_mutex_lock(lock_fd_mutex
);
300 pa_mutex_unlock(lock_fd_mutex
);
302 pa_mutex_unlock(mutex
);
307 void pa_autospawn_lock_release(void) {
310 pa_mutex_lock(mutex
);
311 pa_assert(n_ref
>= 1);
318 pa_mutex_unlock(mutex
);
321 void pa_autospawn_lock_done(pa_bool_t after_fork
) {
324 pa_mutex_lock(mutex
);
325 pa_assert(n_ref
>= 1);
329 pa_mutex_unlock(mutex
);