Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2006 Lennart Poettering
5 : :
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
8 : : published by the Free Software Foundation; either version 2.1 of the
9 : : License, or (at your option) any later version.
10 : :
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 : : Lesser General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public
17 : : License 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 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #ifdef HAVE_SYS_SYSCALL_H
27 : : #include <sys/syscall.h>
28 : : #endif
29 : :
30 : : #include <unistd.h>
31 : : #include <errno.h>
32 : :
33 : : #include <pulsecore/atomic.h>
34 : : #include <pulsecore/log.h>
35 : : #include <pulsecore/macro.h>
36 : : #include <pulsecore/core-util.h>
37 : : #include <pulsecore/core-error.h>
38 : : #include <pulse/xmalloc.h>
39 : :
40 : : #ifndef HAVE_PIPE
41 : : #include <pulsecore/pipe.h>
42 : : #endif
43 : :
44 : : #ifdef HAVE_SYS_EVENTFD_H
45 : : #include <sys/eventfd.h>
46 : : #endif
47 : :
48 : : #include "fdsem.h"
49 : :
50 : : struct pa_fdsem {
51 : : int fds[2];
52 : : #ifdef HAVE_SYS_EVENTFD_H
53 : : int efd;
54 : : #endif
55 : :
56 : : pa_fdsem_data *data;
57 : : };
58 : :
59 : 4 : pa_fdsem *pa_fdsem_new(void) {
60 : : pa_fdsem *f;
61 : :
62 : 4 : f = pa_xmalloc(PA_ALIGN(sizeof(pa_fdsem)) + PA_ALIGN(sizeof(pa_fdsem_data)));
63 : :
64 : : #ifdef HAVE_SYS_EVENTFD_H
65 [ + - ]: 4 : if ((f->efd = eventfd(0, EFD_CLOEXEC)) >= 0)
66 : 4 : f->fds[0] = f->fds[1] = -1;
67 : : else
68 : : #endif
69 : : {
70 [ # # ]: 0 : if (pa_pipe_cloexec(f->fds) < 0) {
71 : 0 : pa_xfree(f);
72 : 0 : return NULL;
73 : : }
74 : : }
75 : :
76 : 4 : f->data = (pa_fdsem_data*) ((uint8_t*) f + PA_ALIGN(sizeof(pa_fdsem)));
77 : :
78 : 4 : pa_atomic_store(&f->data->waiting, 0);
79 : 4 : pa_atomic_store(&f->data->signalled, 0);
80 : 4 : pa_atomic_store(&f->data->in_pipe, 0);
81 : :
82 : 4 : return f;
83 : : }
84 : :
85 : 0 : pa_fdsem *pa_fdsem_open_shm(pa_fdsem_data *data, int event_fd) {
86 : 0 : pa_fdsem *f = NULL;
87 : :
88 [ # # ]: 0 : pa_assert(data);
89 [ # # ]: 0 : pa_assert(event_fd >= 0);
90 : :
91 : : #ifdef HAVE_SYS_EVENTFD_H
92 : 0 : f = pa_xnew(pa_fdsem, 1);
93 : :
94 : 0 : f->efd = event_fd;
95 : 0 : pa_make_fd_cloexec(f->efd);
96 : 0 : f->fds[0] = f->fds[1] = -1;
97 : 0 : f->data = data;
98 : : #endif
99 : :
100 : 0 : return f;
101 : : }
102 : :
103 : 0 : pa_fdsem *pa_fdsem_new_shm(pa_fdsem_data *data, int* event_fd) {
104 : 0 : pa_fdsem *f = NULL;
105 : :
106 [ # # ]: 0 : pa_assert(data);
107 [ # # ]: 0 : pa_assert(event_fd);
108 : :
109 : : #ifdef HAVE_SYS_EVENTFD_H
110 : :
111 : 0 : f = pa_xnew(pa_fdsem, 1);
112 : :
113 [ # # ]: 0 : if ((f->efd = eventfd(0, EFD_CLOEXEC)) < 0) {
114 : 0 : pa_xfree(f);
115 : 0 : return NULL;
116 : : }
117 : :
118 : 0 : f->fds[0] = f->fds[1] = -1;
119 : 0 : f->data = data;
120 : :
121 : 0 : pa_atomic_store(&f->data->waiting, 0);
122 : 0 : pa_atomic_store(&f->data->signalled, 0);
123 : 0 : pa_atomic_store(&f->data->in_pipe, 0);
124 : :
125 : : #endif
126 : :
127 : 0 : return f;
128 : : }
129 : :
130 : 4 : void pa_fdsem_free(pa_fdsem *f) {
131 [ - + ]: 4 : pa_assert(f);
132 : :
133 : : #ifdef HAVE_SYS_EVENTFD_H
134 [ + - ]: 4 : if (f->efd >= 0)
135 : 4 : pa_close(f->efd);
136 : : #endif
137 : 4 : pa_close_pipe(f->fds);
138 : :
139 : 4 : pa_xfree(f);
140 : 4 : }
141 : :
142 : 4 : static void flush(pa_fdsem *f) {
143 : : ssize_t r;
144 [ - + ]: 4 : pa_assert(f);
145 : :
146 [ - + ]: 4 : if (pa_atomic_load(&f->data->in_pipe) <= 0)
147 : 4 : return;
148 : :
149 : : do {
150 : : char x[10];
151 : :
152 : : #ifdef HAVE_SYS_EVENTFD_H
153 [ # # ]: 0 : if (f->efd >= 0) {
154 : : uint64_t u;
155 : :
156 [ # # ]: 0 : if ((r = pa_read(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
157 : :
158 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
159 [ # # ]: 0 : pa_log_error("Invalid read from eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
160 : 0 : pa_assert_not_reached();
161 : : }
162 : :
163 : 0 : continue;
164 : : }
165 : 0 : r = (ssize_t) u;
166 : : } else
167 : : #endif
168 : :
169 [ # # ]: 0 : if ((r = pa_read(f->fds[0], &x, sizeof(x), NULL)) <= 0) {
170 : :
171 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
172 [ # # ]: 0 : pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
173 : 0 : pa_assert_not_reached();
174 : : }
175 : :
176 : 0 : continue;
177 : : }
178 : :
179 [ # # ]: 0 : } while (pa_atomic_sub(&f->data->in_pipe, (int) r) > (int) r);
180 : : }
181 : :
182 : 2008 : void pa_fdsem_post(pa_fdsem *f) {
183 [ - + ]: 2008 : pa_assert(f);
184 : :
185 [ + + ]: 2008 : if (pa_atomic_cmpxchg(&f->data->signalled, 0, 1)) {
186 : :
187 [ + + ]: 7 : if (pa_atomic_load(&f->data->waiting)) {
188 : : ssize_t r;
189 : 5 : char x = 'x';
190 : :
191 : 5 : pa_atomic_inc(&f->data->in_pipe);
192 : :
193 : : for (;;) {
194 : :
195 : : #ifdef HAVE_SYS_EVENTFD_H
196 [ + - ]: 5 : if (f->efd >= 0) {
197 : 5 : uint64_t u = 1;
198 : :
199 [ - + ]: 5 : if ((r = pa_write(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
200 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
201 [ # # ]: 0 : pa_log_error("Invalid write to eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
202 : 0 : pa_assert_not_reached();
203 : : }
204 : :
205 : 0 : continue;
206 : : }
207 : : } else
208 : : #endif
209 : :
210 [ # # ]: 0 : if ((r = pa_write(f->fds[1], &x, 1, NULL)) != 1) {
211 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
212 [ # # ]: 0 : pa_log_error("Invalid write to pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
213 : 0 : pa_assert_not_reached();
214 : : }
215 : :
216 : 0 : continue;
217 : : }
218 : :
219 : : break;
220 : : }
221 : : }
222 : : }
223 : 2008 : }
224 : :
225 : 4 : void pa_fdsem_wait(pa_fdsem *f) {
226 [ - + ]: 4 : pa_assert(f);
227 : :
228 : 4 : flush(f);
229 : :
230 [ + - ]: 4 : if (pa_atomic_cmpxchg(&f->data->signalled, 1, 0))
231 : 4 : return;
232 : :
233 : 4 : pa_atomic_inc(&f->data->waiting);
234 : :
235 [ + + ]: 8 : while (!pa_atomic_cmpxchg(&f->data->signalled, 1, 0)) {
236 : : char x[10];
237 : : ssize_t r;
238 : :
239 : : #ifdef HAVE_SYS_EVENTFD_H
240 [ + - ]: 4 : if (f->efd >= 0) {
241 : : uint64_t u;
242 : :
243 [ - + ]: 4 : if ((r = pa_read(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
244 : :
245 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
246 [ # # ]: 0 : pa_log_error("Invalid read from eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
247 : 0 : pa_assert_not_reached();
248 : : }
249 : :
250 : 0 : continue;
251 : : }
252 : :
253 : 4 : r = (ssize_t) u;
254 : : } else
255 : : #endif
256 : :
257 [ # # ]: 0 : if ((r = pa_read(f->fds[0], &x, sizeof(x), NULL)) <= 0) {
258 : :
259 [ # # ][ # # ]: 0 : if (r >= 0 || errno != EINTR) {
260 [ # # ]: 0 : pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
261 : 0 : pa_assert_not_reached();
262 : : }
263 : :
264 : 0 : continue;
265 : : }
266 : :
267 : 4 : pa_atomic_sub(&f->data->in_pipe, (int) r);
268 : : }
269 : :
270 [ - + ]: 4 : pa_assert_se(pa_atomic_dec(&f->data->waiting) >= 1);
271 : : }
272 : :
273 : 0 : int pa_fdsem_try(pa_fdsem *f) {
274 [ # # ]: 0 : pa_assert(f);
275 : :
276 : 0 : flush(f);
277 : :
278 [ # # ]: 0 : if (pa_atomic_cmpxchg(&f->data->signalled, 1, 0))
279 : : return 1;
280 : :
281 : 0 : return 0;
282 : : }
283 : :
284 : 0 : int pa_fdsem_get(pa_fdsem *f) {
285 [ # # ]: 0 : pa_assert(f);
286 : :
287 : : #ifdef HAVE_SYS_EVENTFD_H
288 [ # # ]: 0 : if (f->efd >= 0)
289 : 0 : return f->efd;
290 : : #endif
291 : :
292 : 0 : return f->fds[0];
293 : : }
294 : :
295 : 0 : int pa_fdsem_before_poll(pa_fdsem *f) {
296 [ # # ]: 0 : pa_assert(f);
297 : :
298 : 0 : flush(f);
299 : :
300 [ # # ]: 0 : if (pa_atomic_cmpxchg(&f->data->signalled, 1, 0))
301 : : return -1;
302 : :
303 : 0 : pa_atomic_inc(&f->data->waiting);
304 : :
305 [ # # ]: 0 : if (pa_atomic_cmpxchg(&f->data->signalled, 1, 0)) {
306 [ # # ]: 0 : pa_assert_se(pa_atomic_dec(&f->data->waiting) >= 1);
307 : : return -1;
308 : : }
309 : : return 0;
310 : : }
311 : :
312 : 0 : int pa_fdsem_after_poll(pa_fdsem *f) {
313 [ # # ]: 0 : pa_assert(f);
314 : :
315 [ # # ]: 0 : pa_assert_se(pa_atomic_dec(&f->data->waiting) >= 1);
316 : :
317 : 0 : flush(f);
318 : :
319 [ # # ]: 0 : if (pa_atomic_cmpxchg(&f->data->signalled, 1, 0))
320 : : return 1;
321 : :
322 : 0 : return 0;
323 : : }
|