Remove u->channels and u->rates, since it's redundant info
[pulseaudio-mirror.git] / src / pulsecore / lock-autospawn.c
blobd36b669ea536584d7c3d4e0bc0a5884e49e1f165
1 /***
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
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <sys/poll.h>
30 #include <signal.h>
31 #include <pthread.h>
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) {
66 if (n_ref > 0) {
68 pa_assert(pipe_fd[0] >= 0);
69 pa_assert(pipe_fd[1] >= 0);
71 n_ref++;
73 return 0;
76 pa_assert(lock_fd < 0);
77 pa_assert(!lock_fd_mutex);
78 pa_assert(!taken);
79 pa_assert(!thread);
80 pa_assert(pipe_fd[0] < 0);
81 pa_assert(pipe_fd[1] < 0);
83 if (pipe(pipe_fd) < 0)
84 return -1;
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]);
94 n_ref = 1;
95 return 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);
105 n_ref--;
107 if (n_ref > 0)
108 return;
110 pa_assert(!taken);
112 if (thread) {
113 pa_thread_free(thread);
114 thread = NULL;
117 pa_mutex_lock(lock_fd_mutex);
118 if (lock_fd >= 0) {
120 if (after_fork)
121 pa_close(lock_fd);
122 else {
123 char *lf;
125 if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
126 pa_log_warn(_("Cannot access autospawn lock."));
128 pa_unlock_lockfile(lf, lock_fd);
129 pa_xfree(lf);
131 lock_fd = -1;
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) {
145 ssize_t s;
147 pa_assert(pipe_fd[1] >= 0);
149 for (;;) {
150 char x = 'x';
152 if ((s = write(pipe_fd[1], &x, 1)) == 1)
153 break;
155 pa_assert(s < 0);
157 if (errno == EAGAIN)
158 break;
160 pa_assert(errno == EINTR);
164 static void wait_for_ping(void) {
165 ssize_t s;
166 char x;
167 struct pollfd pfd;
168 int k;
170 pa_assert(pipe_fd[0] >= 0);
172 memset(&pfd, 0, sizeof(pfd));
173 pfd.fd = pipe_fd[0];
174 pfd.events = POLLIN;
176 if ((k = poll(&pfd, 1, -1)) != 1) {
177 pa_assert(k < 0);
178 pa_assert(errno == EINTR);
179 } else if ((s = read(pipe_fd[0], &x, 1)) != 1) {
180 pa_assert(s < 0);
181 pa_assert(errno == EAGAIN);
185 static void empty_pipe(void) {
186 char x[16];
187 ssize_t s;
189 pa_assert(pipe_fd[0] >= 0);
191 if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) {
192 pa_assert(s < 0);
193 pa_assert(errno == EAGAIN);
197 static void thread_func(void *u) {
198 int fd;
199 char *lf;
200 sigset_t fullset;
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."));
208 goto finish;
211 if ((fd = pa_lock_lockfile(lf)) < 0)
212 goto finish;
214 pa_mutex_lock(lock_fd_mutex);
215 pa_assert(lock_fd < 0);
216 lock_fd = fd;
217 pa_mutex_unlock(lock_fd_mutex);
219 finish:
220 pa_xfree(lf);
222 ping();
225 static int start_thread(void) {
227 if (!thread)
228 if (!(thread = pa_thread_new(thread_func, NULL)))
229 return -1;
231 return 0;
234 static void create_mutex(void) {
235 PA_ONCE_BEGIN {
236 mutex = pa_mutex_new(FALSE, FALSE);
237 } PA_ONCE_END;
240 static void destroy_mutex(void) {
242 if (mutex)
243 pa_mutex_free(mutex);
247 int pa_autospawn_lock_init(void) {
248 int ret = -1;
250 create_mutex();
251 pa_mutex_lock(mutex);
253 if (ref() < 0)
254 ret = -1;
255 else
256 ret = pipe_fd[0];
258 pa_mutex_unlock(mutex);
260 return ret;
263 int pa_autospawn_lock_acquire(pa_bool_t block) {
264 int ret = -1;
266 create_mutex();
267 pa_mutex_lock(mutex);
268 pa_assert(n_ref >= 1);
270 pa_mutex_lock(lock_fd_mutex);
272 for (;;) {
274 empty_pipe();
276 if (lock_fd >= 0 && !taken) {
277 taken = TRUE;
278 ret = 1;
279 break;
282 if (lock_fd < 0)
283 if (start_thread() < 0)
284 break;
286 if (!block) {
287 ret = 0;
288 break;
291 pa_mutex_unlock(lock_fd_mutex);
292 pa_mutex_unlock(mutex);
294 wait_for_ping();
296 pa_mutex_lock(mutex);
297 pa_mutex_lock(lock_fd_mutex);
300 pa_mutex_unlock(lock_fd_mutex);
302 pa_mutex_unlock(mutex);
304 return ret;
307 void pa_autospawn_lock_release(void) {
309 create_mutex();
310 pa_mutex_lock(mutex);
311 pa_assert(n_ref >= 1);
313 pa_assert(taken);
314 taken = FALSE;
316 ping();
318 pa_mutex_unlock(mutex);
321 void pa_autospawn_lock_done(pa_bool_t after_fork) {
323 create_mutex();
324 pa_mutex_lock(mutex);
325 pa_assert(n_ref >= 1);
327 unref(after_fork);
329 pa_mutex_unlock(mutex);