]>
code.delx.au - pulseaudio/blob - src/pulsecore/lock-autospawn.c
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
34 #include <pulse/gccmacro.h>
35 #include <pulse/xmalloc.h>
37 #include <pulsecore/i18n.h>
38 #include <pulsecore/poll.h>
39 #include <pulsecore/mutex.h>
40 #include <pulsecore/thread.h>
41 #include <pulsecore/core-util.h>
43 #include "lock-autospawn.h"
45 /* So, why do we have this complex code here with threads and pipes
46 * and stuff? For two reasons: POSIX file locks are per-process, not
47 * per-file descriptor. That means that two contexts within the same
48 * process that try to create the autospawn lock might end up assuming
49 * they both managed to lock the file. And then, POSIX locking
50 * operations are synchronous. If two contexts run from the same event
51 * loop it must be made sure that they do not block each other, but
52 * that the locking operation can happen asynchronously. */
54 #define AUTOSPAWN_LOCK "autospawn.lock"
56 static pa_mutex
*mutex
;
58 static unsigned n_ref
= 0;
59 static int lock_fd
= -1;
60 static pa_mutex
*lock_fd_mutex
= NULL
;
61 static pa_thread
*thread
= NULL
;
62 static int pipe_fd
[2] = { -1, -1 };
71 static void destroy_mutex(void) PA_GCC_DESTRUCTOR
;
73 static int ref(void) {
77 pa_assert(pipe_fd
[0] >= 0);
78 pa_assert(pipe_fd
[1] >= 0);
79 pa_assert(lock_fd_mutex
);
86 pa_assert(!lock_fd_mutex
);
87 pa_assert(state
== STATE_IDLE
);
88 pa_assert(lock_fd
< 0);
90 pa_assert(pipe_fd
[0] < 0);
91 pa_assert(pipe_fd
[1] < 0);
93 if (pa_pipe_cloexec(pipe_fd
) < 0)
96 pa_make_fd_nonblock(pipe_fd
[1]);
97 pa_make_fd_nonblock(pipe_fd
[0]);
99 lock_fd_mutex
= pa_mutex_new(false, false);
105 static void unref(bool after_fork
) {
107 pa_assert(n_ref
> 0);
108 pa_assert(pipe_fd
[0] >= 0);
109 pa_assert(pipe_fd
[1] >= 0);
110 pa_assert(lock_fd_mutex
);
117 /* Join threads only in the process the new thread was created in
118 * to avoid undefined behaviour.
119 * POSIX.1-2008 XSH 2.9.2 Thread IDs: "applications should only assume
120 * that thread IDs are usable and unique within a single process." */
123 pa_thread_free_nojoin(thread
);
125 pa_thread_free(thread
);
129 pa_mutex_lock(lock_fd_mutex
);
131 pa_assert(state
!= STATE_TAKEN
);
133 if (state
== STATE_OWNING
) {
135 pa_assert(lock_fd
>= 0);
142 if (!(lf
= pa_runtime_path(AUTOSPAWN_LOCK
)))
143 pa_log_warn(_("Cannot access autospawn lock."));
145 pa_unlock_lockfile(lf
, lock_fd
);
153 pa_mutex_unlock(lock_fd_mutex
);
155 pa_mutex_free(lock_fd_mutex
);
156 lock_fd_mutex
= NULL
;
158 pa_close(pipe_fd
[0]);
159 pa_close(pipe_fd
[1]);
160 pipe_fd
[0] = pipe_fd
[1] = -1;
163 static void ping(void) {
166 pa_assert(pipe_fd
[1] >= 0);
171 if ((s
= pa_write(pipe_fd
[1], &x
, 1, NULL
)) == 1)
179 pa_assert(errno
== EINTR
);
183 static void wait_for_ping(void) {
189 pa_assert(pipe_fd
[0] >= 0);
191 memset(&pfd
, 0, sizeof(pfd
));
195 if ((k
= pa_poll(&pfd
, 1, -1)) != 1) {
197 pa_assert(errno
== EINTR
);
198 } else if ((s
= pa_read(pipe_fd
[0], &x
, 1, NULL
)) != 1) {
200 pa_assert(errno
== EAGAIN
);
204 static void empty_pipe(void) {
208 pa_assert(pipe_fd
[0] >= 0);
210 if ((s
= pa_read(pipe_fd
[0], &x
, sizeof(x
), NULL
)) < 1) {
212 pa_assert(errno
== EAGAIN
);
216 static void thread_func(void *u
) {
223 /* No signals in this thread please */
224 sigfillset(&fullset
);
225 pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
);
228 if (!(lf
= pa_runtime_path(AUTOSPAWN_LOCK
))) {
229 pa_log_warn(_("Cannot access autospawn lock."));
233 if ((fd
= pa_lock_lockfile(lf
)) < 0)
236 pa_mutex_lock(lock_fd_mutex
);
237 pa_assert(state
== STATE_IDLE
);
239 state
= STATE_OWNING
;
240 pa_mutex_unlock(lock_fd_mutex
);
245 pa_mutex_lock(lock_fd_mutex
);
246 pa_assert(state
== STATE_IDLE
);
247 state
= STATE_FAILED
;
248 pa_mutex_unlock(lock_fd_mutex
);
256 static int start_thread(void) {
259 if (!(thread
= pa_thread_new("autospawn", thread_func
, NULL
)))
265 static void create_mutex(void) {
267 mutex
= pa_mutex_new(false, false);
271 static void destroy_mutex(void) {
273 pa_mutex_free(mutex
);
276 int pa_autospawn_lock_init(void) {
280 pa_mutex_lock(mutex
);
287 pa_mutex_unlock(mutex
);
292 int pa_autospawn_lock_acquire(bool block
) {
296 pa_mutex_lock(mutex
);
297 pa_assert(n_ref
>= 1);
299 pa_mutex_lock(lock_fd_mutex
);
305 if (state
== STATE_OWNING
) {
311 if (state
== STATE_FAILED
) {
316 if (state
== STATE_IDLE
)
317 if (start_thread() < 0)
325 pa_mutex_unlock(lock_fd_mutex
);
326 pa_mutex_unlock(mutex
);
330 pa_mutex_lock(mutex
);
331 pa_mutex_lock(lock_fd_mutex
);
334 pa_mutex_unlock(lock_fd_mutex
);
336 pa_mutex_unlock(mutex
);
341 void pa_autospawn_lock_release(void) {
344 pa_mutex_lock(mutex
);
345 pa_assert(n_ref
>= 1);
347 pa_assert(state
== STATE_TAKEN
);
348 state
= STATE_OWNING
;
352 pa_mutex_unlock(mutex
);
355 void pa_autospawn_lock_done(bool after_fork
) {
358 pa_mutex_lock(mutex
);
359 pa_assert(n_ref
>= 1);
363 pa_mutex_unlock(mutex
);