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, see <http://www.gnu.org/licenses/>.
32
#include <pulse/gccmacro.h>
33
#include <pulse/xmalloc.h>
35
#include <pulsecore/i18n.h>
36
#include <pulsecore/poll.h>
37
#include <pulsecore/mutex.h>
38
#include <pulsecore/thread.h>
39
#include <pulsecore/core-util.h>
41
#include "lock-autospawn.h"
43
/* So, why do we have this complex code here with threads and pipes
44
* and stuff? For two reasons: POSIX file locks are per-process, not
45
* per-file descriptor. That means that two contexts within the same
46
* process that try to create the autospawn lock might end up assuming
47
* they both managed to lock the file. And then, POSIX locking
48
* operations are synchronous. If two contexts run from the same event
49
* loop it must be made sure that they do not block each other, but
50
* that the locking operation can happen asynchronously. */
52
#define AUTOSPAWN_LOCK "autospawn.lock"
54
static pa_mutex *mutex;
56
static unsigned n_ref = 0;
57
static int lock_fd = -1;
58
static pa_mutex *lock_fd_mutex = NULL;
59
static pa_thread *thread = NULL;
60
static int pipe_fd[2] = { -1, -1 };
69
static void destroy_mutex(void) PA_GCC_DESTRUCTOR;
71
static int ref(void) {
75
pa_assert(pipe_fd[0] >= 0);
76
pa_assert(pipe_fd[1] >= 0);
77
pa_assert(lock_fd_mutex);
84
pa_assert(!lock_fd_mutex);
85
pa_assert(state == STATE_IDLE);
86
pa_assert(lock_fd < 0);
88
pa_assert(pipe_fd[0] < 0);
89
pa_assert(pipe_fd[1] < 0);
91
if (pa_pipe_cloexec(pipe_fd) < 0)
94
pa_make_fd_nonblock(pipe_fd[1]);
95
pa_make_fd_nonblock(pipe_fd[0]);
97
lock_fd_mutex = pa_mutex_new(false, false);
103
static void unref(bool after_fork) {
105
pa_assert(n_ref > 0);
106
pa_assert(pipe_fd[0] >= 0);
107
pa_assert(pipe_fd[1] >= 0);
108
pa_assert(lock_fd_mutex);
115
/* Join threads only in the process the new thread was created in
116
* to avoid undefined behaviour.
117
* POSIX.1-2008 XSH 2.9.2 Thread IDs: "applications should only assume
118
* that thread IDs are usable and unique within a single process." */
121
pa_thread_free_nojoin(thread);
123
pa_thread_free(thread);
127
pa_mutex_lock(lock_fd_mutex);
129
pa_assert(state != STATE_TAKEN);
131
if (state == STATE_OWNING) {
133
pa_assert(lock_fd >= 0);
140
if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
141
pa_log_warn(_("Cannot access autospawn lock."));
143
pa_unlock_lockfile(lf, lock_fd);
151
pa_mutex_unlock(lock_fd_mutex);
153
pa_mutex_free(lock_fd_mutex);
154
lock_fd_mutex = NULL;
156
pa_close(pipe_fd[0]);
157
pa_close(pipe_fd[1]);
158
pipe_fd[0] = pipe_fd[1] = -1;
161
static void ping(void) {
164
pa_assert(pipe_fd[1] >= 0);
169
if ((s = pa_write(pipe_fd[1], &x, 1, NULL)) == 1)
177
pa_assert(errno == EINTR);
181
static void wait_for_ping(void) {
187
pa_assert(pipe_fd[0] >= 0);
189
memset(&pfd, 0, sizeof(pfd));
193
if ((k = pa_poll(&pfd, 1, -1)) != 1) {
195
pa_assert(errno == EINTR);
196
} else if ((s = pa_read(pipe_fd[0], &x, 1, NULL)) != 1) {
198
pa_assert(errno == EAGAIN);
202
static void empty_pipe(void) {
206
pa_assert(pipe_fd[0] >= 0);
208
if ((s = pa_read(pipe_fd[0], &x, sizeof(x), NULL)) < 1) {
210
pa_assert(errno == EAGAIN);
214
static void thread_func(void *u) {
221
/* No signals in this thread please */
222
sigfillset(&fullset);
223
pthread_sigmask(SIG_BLOCK, &fullset, NULL);
226
if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
227
pa_log_warn(_("Cannot access autospawn lock."));
231
if ((fd = pa_lock_lockfile(lf)) < 0)
234
pa_mutex_lock(lock_fd_mutex);
235
pa_assert(state == STATE_IDLE);
237
state = STATE_OWNING;
238
pa_mutex_unlock(lock_fd_mutex);
243
pa_mutex_lock(lock_fd_mutex);
244
pa_assert(state == STATE_IDLE);
245
state = STATE_FAILED;
246
pa_mutex_unlock(lock_fd_mutex);
254
static int start_thread(void) {
257
if (!(thread = pa_thread_new("autospawn", thread_func, NULL)))
263
static void create_mutex(void) {
265
mutex = pa_mutex_new(false, false);
269
static void destroy_mutex(void) {
271
pa_mutex_free(mutex);
274
int pa_autospawn_lock_init(void) {
278
pa_mutex_lock(mutex);
285
pa_mutex_unlock(mutex);
290
int pa_autospawn_lock_acquire(bool block) {
294
pa_mutex_lock(mutex);
295
pa_assert(n_ref >= 1);
297
pa_mutex_lock(lock_fd_mutex);
303
if (state == STATE_OWNING) {
309
if (state == STATE_FAILED) {
314
if (state == STATE_IDLE)
315
if (start_thread() < 0)
323
pa_mutex_unlock(lock_fd_mutex);
324
pa_mutex_unlock(mutex);
328
pa_mutex_lock(mutex);
329
pa_mutex_lock(lock_fd_mutex);
332
pa_mutex_unlock(lock_fd_mutex);
334
pa_mutex_unlock(mutex);
339
void pa_autospawn_lock_release(void) {
342
pa_mutex_lock(mutex);
343
pa_assert(n_ref >= 1);
345
pa_assert(state == STATE_TAKEN);
346
state = STATE_OWNING;
350
pa_mutex_unlock(mutex);
353
void pa_autospawn_lock_done(bool after_fork) {
356
pa_mutex_lock(mutex);
357
pa_assert(n_ref >= 1);
361
pa_mutex_unlock(mutex);