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);