Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <stdio.h>
28 : : #include <unistd.h>
29 : : #include <stdlib.h>
30 : : #include <fcntl.h>
31 : : #include <errno.h>
32 : :
33 : : #ifndef HAVE_PIPE
34 : : #include <pulsecore/pipe.h>
35 : : #endif
36 : :
37 : : #include <pulse/rtclock.h>
38 : : #include <pulse/timeval.h>
39 : : #include <pulse/xmalloc.h>
40 : :
41 : : #include <pulsecore/poll.h>
42 : : #include <pulsecore/core-rtclock.h>
43 : : #include <pulsecore/core-util.h>
44 : : #include <pulsecore/i18n.h>
45 : : #include <pulsecore/llist.h>
46 : : #include <pulsecore/log.h>
47 : : #include <pulsecore/core-error.h>
48 : : #include <pulsecore/socket.h>
49 : : #include <pulsecore/macro.h>
50 : :
51 : : #include "mainloop.h"
52 : : #include "internal.h"
53 : :
54 : : struct pa_io_event {
55 : : pa_mainloop *mainloop;
56 : : pa_bool_t dead:1;
57 : :
58 : : int fd;
59 : : pa_io_event_flags_t events;
60 : : struct pollfd *pollfd;
61 : :
62 : : pa_io_event_cb_t callback;
63 : : void *userdata;
64 : : pa_io_event_destroy_cb_t destroy_callback;
65 : :
66 : : PA_LLIST_FIELDS(pa_io_event);
67 : : };
68 : :
69 : : struct pa_time_event {
70 : : pa_mainloop *mainloop;
71 : : pa_bool_t dead:1;
72 : :
73 : : pa_bool_t enabled:1;
74 : : pa_bool_t use_rtclock:1;
75 : : pa_usec_t time;
76 : :
77 : : pa_time_event_cb_t callback;
78 : : void *userdata;
79 : : pa_time_event_destroy_cb_t destroy_callback;
80 : :
81 : : PA_LLIST_FIELDS(pa_time_event);
82 : : };
83 : :
84 : : struct pa_defer_event {
85 : : pa_mainloop *mainloop;
86 : : pa_bool_t dead:1;
87 : :
88 : : pa_bool_t enabled:1;
89 : :
90 : : pa_defer_event_cb_t callback;
91 : : void *userdata;
92 : : pa_defer_event_destroy_cb_t destroy_callback;
93 : :
94 : : PA_LLIST_FIELDS(pa_defer_event);
95 : : };
96 : :
97 : : struct pa_mainloop {
98 : : PA_LLIST_HEAD(pa_io_event, io_events);
99 : : PA_LLIST_HEAD(pa_time_event, time_events);
100 : : PA_LLIST_HEAD(pa_defer_event, defer_events);
101 : :
102 : : unsigned n_enabled_defer_events, n_enabled_time_events, n_io_events;
103 : : unsigned io_events_please_scan, time_events_please_scan, defer_events_please_scan;
104 : :
105 : : pa_bool_t rebuild_pollfds:1;
106 : : struct pollfd *pollfds;
107 : : unsigned max_pollfds, n_pollfds;
108 : :
109 : : pa_usec_t prepared_timeout;
110 : : pa_time_event *cached_next_time_event;
111 : :
112 : : pa_mainloop_api api;
113 : :
114 : : int retval;
115 : : pa_bool_t quit:1;
116 : :
117 : : pa_bool_t wakeup_requested:1;
118 : : int wakeup_pipe[2];
119 : : int wakeup_pipe_type;
120 : :
121 : : enum {
122 : : STATE_PASSIVE,
123 : : STATE_PREPARED,
124 : : STATE_POLLING,
125 : : STATE_POLLED,
126 : : STATE_QUIT
127 : : } state;
128 : :
129 : : pa_poll_func poll_func;
130 : : void *poll_func_userdata;
131 : : int poll_func_ret;
132 : : };
133 : :
134 : : static short map_flags_to_libc(pa_io_event_flags_t flags) {
135 [ - + ][ + - ]: 1 : return (short)
[ + - ][ # # ]
[ # # ][ # # ]
136 : 1 : ((flags & PA_IO_EVENT_INPUT ? POLLIN : 0) |
137 : 1 : (flags & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) |
138 : : (flags & PA_IO_EVENT_ERROR ? POLLERR : 0) |
139 : 1 : (flags & PA_IO_EVENT_HANGUP ? POLLHUP : 0));
140 : : }
141 : :
142 : : static pa_io_event_flags_t map_flags_from_libc(short flags) {
143 : 0 : return
144 : 0 : (flags & POLLIN ? PA_IO_EVENT_INPUT : 0) |
145 [ # # ]: 0 : (flags & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) |
146 : 0 : (flags & POLLERR ? PA_IO_EVENT_ERROR : 0) |
147 [ # # ]: 0 : (flags & POLLHUP ? PA_IO_EVENT_HANGUP : 0);
148 : : }
149 : :
150 : : /* IO events */
151 : 1 : static pa_io_event* mainloop_io_new(
152 : : pa_mainloop_api *a,
153 : : int fd,
154 : : pa_io_event_flags_t events,
155 : : pa_io_event_cb_t callback,
156 : : void *userdata) {
157 : :
158 : : pa_mainloop *m;
159 : : pa_io_event *e;
160 : :
161 [ - + ]: 1 : pa_assert(a);
162 [ - + ]: 1 : pa_assert(a->userdata);
163 [ - + ]: 1 : pa_assert(fd >= 0);
164 [ - + ]: 1 : pa_assert(callback);
165 : :
166 : 1 : m = a->userdata;
167 [ - + ]: 1 : pa_assert(a == &m->api);
168 : :
169 : 1 : e = pa_xnew0(pa_io_event, 1);
170 : 1 : e->mainloop = m;
171 : :
172 : 1 : e->fd = fd;
173 : 1 : e->events = events;
174 : :
175 : 1 : e->callback = callback;
176 : 1 : e->userdata = userdata;
177 : :
178 : : #ifdef OS_IS_WIN32
179 : : {
180 : : fd_set xset;
181 : : struct timeval tv;
182 : :
183 : : tv.tv_sec = 0;
184 : : tv.tv_usec = 0;
185 : :
186 : : FD_ZERO (&xset);
187 : : FD_SET (fd, &xset);
188 : :
189 : : if ((select(fd, NULL, NULL, &xset, &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) {
190 : : pa_log_warn("Cannot monitor non-socket file descriptors.");
191 : : e->dead = TRUE;
192 : : }
193 : : }
194 : : #endif
195 : :
196 [ - + ][ - + ]: 1 : PA_LLIST_PREPEND(pa_io_event, m->io_events, e);
197 : 1 : m->rebuild_pollfds = TRUE;
198 : 1 : m->n_io_events ++;
199 : :
200 : 1 : pa_mainloop_wakeup(m);
201 : :
202 : 1 : return e;
203 : : }
204 : :
205 : 0 : static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) {
206 [ # # ]: 0 : pa_assert(e);
207 [ # # ]: 0 : pa_assert(!e->dead);
208 : :
209 [ # # ]: 0 : if (e->events == events)
210 : 0 : return;
211 : :
212 : 0 : e->events = events;
213 : :
214 [ # # ]: 0 : if (e->pollfd)
215 : 0 : e->pollfd->events = map_flags_to_libc(events);
216 : : else
217 : 0 : e->mainloop->rebuild_pollfds = TRUE;
218 : :
219 : 0 : pa_mainloop_wakeup(e->mainloop);
220 : : }
221 : :
222 : 1 : static void mainloop_io_free(pa_io_event *e) {
223 [ - + ]: 1 : pa_assert(e);
224 [ - + ]: 1 : pa_assert(!e->dead);
225 : :
226 : 1 : e->dead = TRUE;
227 : 1 : e->mainloop->io_events_please_scan ++;
228 : :
229 : 1 : e->mainloop->n_io_events --;
230 : 1 : e->mainloop->rebuild_pollfds = TRUE;
231 : :
232 : 1 : pa_mainloop_wakeup(e->mainloop);
233 : 1 : }
234 : :
235 : 0 : static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) {
236 [ # # ]: 0 : pa_assert(e);
237 : :
238 : 0 : e->destroy_callback = callback;
239 : 0 : }
240 : :
241 : : /* Defer events */
242 : 1 : static pa_defer_event* mainloop_defer_new(
243 : : pa_mainloop_api *a,
244 : : pa_defer_event_cb_t callback,
245 : : void *userdata) {
246 : :
247 : : pa_mainloop *m;
248 : : pa_defer_event *e;
249 : :
250 [ - + ]: 1 : pa_assert(a);
251 [ - + ]: 1 : pa_assert(a->userdata);
252 [ - + ]: 1 : pa_assert(callback);
253 : :
254 : 1 : m = a->userdata;
255 [ - + ]: 1 : pa_assert(a == &m->api);
256 : :
257 : 1 : e = pa_xnew0(pa_defer_event, 1);
258 : 1 : e->mainloop = m;
259 : :
260 : 1 : e->enabled = TRUE;
261 : 1 : m->n_enabled_defer_events++;
262 : :
263 : 1 : e->callback = callback;
264 : 1 : e->userdata = userdata;
265 : :
266 [ - + ][ - + ]: 1 : PA_LLIST_PREPEND(pa_defer_event, m->defer_events, e);
267 : :
268 : 1 : pa_mainloop_wakeup(e->mainloop);
269 : :
270 : 1 : return e;
271 : : }
272 : :
273 : 1 : static void mainloop_defer_enable(pa_defer_event *e, int b) {
274 [ - + ]: 1 : pa_assert(e);
275 [ - + ]: 1 : pa_assert(!e->dead);
276 : :
277 [ + - ][ + - ]: 1 : if (e->enabled && !b) {
278 [ - + ]: 1 : pa_assert(e->mainloop->n_enabled_defer_events > 0);
279 : 1 : e->mainloop->n_enabled_defer_events--;
280 [ # # ][ # # ]: 0 : } else if (!e->enabled && b) {
281 : 0 : e->mainloop->n_enabled_defer_events++;
282 : 0 : pa_mainloop_wakeup(e->mainloop);
283 : : }
284 : :
285 : 1 : e->enabled = b;
286 : 1 : }
287 : :
288 : 1 : static void mainloop_defer_free(pa_defer_event *e) {
289 [ - + ]: 1 : pa_assert(e);
290 [ - + ]: 1 : pa_assert(!e->dead);
291 : :
292 : 1 : e->dead = TRUE;
293 : 1 : e->mainloop->defer_events_please_scan ++;
294 : :
295 [ - + ]: 1 : if (e->enabled) {
296 [ # # ]: 0 : pa_assert(e->mainloop->n_enabled_defer_events > 0);
297 : 0 : e->mainloop->n_enabled_defer_events--;
298 : 0 : e->enabled = FALSE;
299 : : }
300 : 1 : }
301 : :
302 : 0 : static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) {
303 [ # # ]: 0 : pa_assert(e);
304 [ # # ]: 0 : pa_assert(!e->dead);
305 : :
306 : 0 : e->destroy_callback = callback;
307 : 0 : }
308 : :
309 : : /* Time events */
310 : 4 : static pa_usec_t make_rt(const struct timeval *tv, pa_bool_t *use_rtclock) {
311 : : struct timeval ttv;
312 : :
313 [ + + ]: 4 : if (!tv) {
314 : 2 : *use_rtclock = FALSE;
315 : 2 : return PA_USEC_INVALID;
316 : : }
317 : :
318 : 2 : ttv = *tv;
319 : 2 : *use_rtclock = !!(ttv.tv_usec & PA_TIMEVAL_RTCLOCK);
320 : :
321 [ + - ]: 2 : if (*use_rtclock)
322 : 2 : ttv.tv_usec &= ~PA_TIMEVAL_RTCLOCK;
323 : : else
324 : 0 : pa_rtclock_from_wallclock(&ttv);
325 : :
326 : 4 : return pa_timeval_load(&ttv);
327 : : }
328 : :
329 : 2 : static pa_time_event* mainloop_time_new(
330 : : pa_mainloop_api *a,
331 : : const struct timeval *tv,
332 : : pa_time_event_cb_t callback,
333 : : void *userdata) {
334 : :
335 : : pa_mainloop *m;
336 : : pa_time_event *e;
337 : : pa_usec_t t;
338 : 2 : pa_bool_t use_rtclock = FALSE;
339 : :
340 [ - + ]: 2 : pa_assert(a);
341 [ - + ]: 2 : pa_assert(a->userdata);
342 [ - + ]: 2 : pa_assert(callback);
343 : :
344 : 2 : t = make_rt(tv, &use_rtclock);
345 : :
346 : 2 : m = a->userdata;
347 [ - + ]: 2 : pa_assert(a == &m->api);
348 : :
349 : 2 : e = pa_xnew0(pa_time_event, 1);
350 : 2 : e->mainloop = m;
351 : :
352 [ + - ]: 2 : if ((e->enabled = (t != PA_USEC_INVALID))) {
353 : 2 : e->time = t;
354 : 2 : e->use_rtclock = use_rtclock;
355 : :
356 : 2 : m->n_enabled_time_events++;
357 : :
358 [ - + ]: 2 : if (m->cached_next_time_event) {
359 [ # # ]: 0 : pa_assert(m->cached_next_time_event->enabled);
360 : :
361 [ # # ]: 0 : if (t < m->cached_next_time_event->time)
362 : 0 : m->cached_next_time_event = e;
363 : : }
364 : : }
365 : :
366 : 2 : e->callback = callback;
367 : 2 : e->userdata = userdata;
368 : :
369 [ - + ][ - + ]: 2 : PA_LLIST_PREPEND(pa_time_event, m->time_events, e);
370 : :
371 [ + - ]: 2 : if (e->enabled)
372 : 2 : pa_mainloop_wakeup(m);
373 : :
374 : 2 : return e;
375 : : }
376 : :
377 : 2 : static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) {
378 : : pa_bool_t valid;
379 : : pa_usec_t t;
380 : 2 : pa_bool_t use_rtclock = FALSE;
381 : :
382 [ - + ]: 2 : pa_assert(e);
383 [ - + ]: 2 : pa_assert(!e->dead);
384 : :
385 : 2 : t = make_rt(tv, &use_rtclock);
386 : :
387 : 2 : valid = (t != PA_USEC_INVALID);
388 [ + - ][ + - ]: 2 : if (e->enabled && !valid) {
389 [ - + ]: 2 : pa_assert(e->mainloop->n_enabled_time_events > 0);
390 : 2 : e->mainloop->n_enabled_time_events--;
391 [ # # ][ # # ]: 0 : } else if (!e->enabled && valid)
392 : 0 : e->mainloop->n_enabled_time_events++;
393 : :
394 [ - + ]: 2 : if ((e->enabled = valid)) {
395 : 0 : e->time = t;
396 : 0 : e->use_rtclock = use_rtclock;
397 : 0 : pa_mainloop_wakeup(e->mainloop);
398 : : }
399 : :
400 [ + - ][ - + ]: 2 : if (e->mainloop->cached_next_time_event && e->enabled) {
401 [ # # ]: 0 : pa_assert(e->mainloop->cached_next_time_event->enabled);
402 : :
403 [ # # ]: 0 : if (t < e->mainloop->cached_next_time_event->time)
404 : 0 : e->mainloop->cached_next_time_event = e;
405 [ + - ]: 2 : } else if (e->mainloop->cached_next_time_event == e)
406 : 2 : e->mainloop->cached_next_time_event = NULL;
407 : 2 : }
408 : :
409 : 1 : static void mainloop_time_free(pa_time_event *e) {
410 [ - + ]: 1 : pa_assert(e);
411 [ - + ]: 1 : pa_assert(!e->dead);
412 : :
413 : 1 : e->dead = TRUE;
414 : 1 : e->mainloop->time_events_please_scan ++;
415 : :
416 [ - + ]: 1 : if (e->enabled) {
417 [ # # ]: 0 : pa_assert(e->mainloop->n_enabled_time_events > 0);
418 : 0 : e->mainloop->n_enabled_time_events--;
419 : 0 : e->enabled = FALSE;
420 : : }
421 : :
422 [ - + ]: 1 : if (e->mainloop->cached_next_time_event == e)
423 : 0 : e->mainloop->cached_next_time_event = NULL;
424 : :
425 : : /* no wakeup needed here. Think about it! */
426 : 1 : }
427 : :
428 : 0 : static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) {
429 [ # # ]: 0 : pa_assert(e);
430 [ # # ]: 0 : pa_assert(!e->dead);
431 : :
432 : 0 : e->destroy_callback = callback;
433 : 0 : }
434 : :
435 : : /* quit() */
436 : :
437 : 1 : static void mainloop_quit(pa_mainloop_api *a, int retval) {
438 : : pa_mainloop *m;
439 : :
440 [ - + ]: 1 : pa_assert(a);
441 [ - + ]: 1 : pa_assert(a->userdata);
442 : 1 : m = a->userdata;
443 [ - + ]: 1 : pa_assert(a == &m->api);
444 : :
445 : 1 : pa_mainloop_quit(m, retval);
446 : 1 : }
447 : :
448 : : static const pa_mainloop_api vtable = {
449 : : .userdata = NULL,
450 : :
451 : : .io_new = mainloop_io_new,
452 : : .io_enable = mainloop_io_enable,
453 : : .io_free = mainloop_io_free,
454 : : .io_set_destroy = mainloop_io_set_destroy,
455 : :
456 : : .time_new = mainloop_time_new,
457 : : .time_restart = mainloop_time_restart,
458 : : .time_free = mainloop_time_free,
459 : : .time_set_destroy = mainloop_time_set_destroy,
460 : :
461 : : .defer_new = mainloop_defer_new,
462 : : .defer_enable = mainloop_defer_enable,
463 : : .defer_free = mainloop_defer_free,
464 : : .defer_set_destroy = mainloop_defer_set_destroy,
465 : :
466 : : .quit = mainloop_quit,
467 : : };
468 : :
469 : 2 : pa_mainloop *pa_mainloop_new(void) {
470 : : pa_mainloop *m;
471 : :
472 : 2 : pa_init_i18n();
473 : :
474 : 2 : m = pa_xnew0(pa_mainloop, 1);
475 : :
476 [ - + ]: 2 : if (pa_pipe_cloexec(m->wakeup_pipe) < 0) {
477 : 0 : pa_log_error("ERROR: cannot create wakeup pipe");
478 : 0 : pa_xfree(m);
479 : 0 : return NULL;
480 : : }
481 : :
482 : 2 : pa_make_fd_nonblock(m->wakeup_pipe[0]);
483 : 2 : pa_make_fd_nonblock(m->wakeup_pipe[1]);
484 : :
485 : 2 : m->rebuild_pollfds = TRUE;
486 : :
487 : 2 : m->api = vtable;
488 : 2 : m->api.userdata = m;
489 : :
490 : 2 : m->state = STATE_PASSIVE;
491 : :
492 : 2 : m->poll_func_ret = -1;
493 : :
494 : 2 : return m;
495 : : }
496 : :
497 : 2 : static void cleanup_io_events(pa_mainloop *m, pa_bool_t force) {
498 : : pa_io_event *e, *n;
499 : :
500 [ + + ]: 3 : PA_LLIST_FOREACH_SAFE(e, n, m->io_events) {
501 : :
502 [ # # ][ - + ]: 1 : if (!force && m->io_events_please_scan <= 0)
503 : : break;
504 : :
505 [ - + ][ # # ]: 1 : if (force || e->dead) {
506 [ - + ][ - + ]: 1 : PA_LLIST_REMOVE(pa_io_event, m->io_events, e);
[ - + ][ - + ]
507 : :
508 [ + - ]: 1 : if (e->dead) {
509 [ - + ]: 1 : pa_assert(m->io_events_please_scan > 0);
510 : 1 : m->io_events_please_scan--;
511 : : }
512 : :
513 [ - + ]: 1 : if (e->destroy_callback)
514 : 0 : e->destroy_callback(&m->api, e, e->userdata);
515 : :
516 : 1 : pa_xfree(e);
517 : :
518 : 1 : m->rebuild_pollfds = TRUE;
519 : : }
520 : : }
521 : :
522 [ - + ]: 2 : pa_assert(m->io_events_please_scan == 0);
523 : 2 : }
524 : :
525 : 2 : static void cleanup_time_events(pa_mainloop *m, pa_bool_t force) {
526 : : pa_time_event *e, *n;
527 : :
528 [ + + ]: 4 : PA_LLIST_FOREACH_SAFE(e, n, m->time_events) {
529 : :
530 [ # # ][ - + ]: 2 : if (!force && m->time_events_please_scan <= 0)
531 : : break;
532 : :
533 [ - + ][ # # ]: 2 : if (force || e->dead) {
534 [ - + ][ - + ]: 2 : PA_LLIST_REMOVE(pa_time_event, m->time_events, e);
[ - + ][ - + ]
535 : :
536 [ + + ]: 2 : if (e->dead) {
537 [ - + ]: 1 : pa_assert(m->time_events_please_scan > 0);
538 : 1 : m->time_events_please_scan--;
539 : : }
540 : :
541 [ + + ][ - + ]: 2 : if (!e->dead && e->enabled) {
542 [ # # ]: 0 : pa_assert(m->n_enabled_time_events > 0);
543 : 0 : m->n_enabled_time_events--;
544 : 0 : e->enabled = FALSE;
545 : : }
546 : :
547 [ - + ]: 2 : if (e->destroy_callback)
548 : 0 : e->destroy_callback(&m->api, e, e->userdata);
549 : :
550 : 2 : pa_xfree(e);
551 : : }
552 : : }
553 : :
554 [ - + ]: 2 : pa_assert(m->time_events_please_scan == 0);
555 : 2 : }
556 : :
557 : 2 : static void cleanup_defer_events(pa_mainloop *m, pa_bool_t force) {
558 : : pa_defer_event *e, *n;
559 : :
560 [ + + ]: 3 : PA_LLIST_FOREACH_SAFE(e, n, m->defer_events) {
561 : :
562 [ # # ][ - + ]: 1 : if (!force && m->defer_events_please_scan <= 0)
563 : : break;
564 : :
565 [ - + ][ # # ]: 1 : if (force || e->dead) {
566 [ - + ][ - + ]: 1 : PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e);
[ - + ][ - + ]
567 : :
568 [ + - ]: 1 : if (e->dead) {
569 [ - + ]: 1 : pa_assert(m->defer_events_please_scan > 0);
570 : 1 : m->defer_events_please_scan--;
571 : : }
572 : :
573 [ - + ][ # # ]: 1 : if (!e->dead && e->enabled) {
574 [ # # ]: 0 : pa_assert(m->n_enabled_defer_events > 0);
575 : 0 : m->n_enabled_defer_events--;
576 : 0 : e->enabled = FALSE;
577 : : }
578 : :
579 [ - + ]: 1 : if (e->destroy_callback)
580 : 0 : e->destroy_callback(&m->api, e, e->userdata);
581 : :
582 : 1 : pa_xfree(e);
583 : : }
584 : : }
585 : :
586 [ - + ]: 2 : pa_assert(m->defer_events_please_scan == 0);
587 : 2 : }
588 : :
589 : :
590 : 2 : void pa_mainloop_free(pa_mainloop *m) {
591 [ - + ]: 2 : pa_assert(m);
592 : :
593 : 2 : cleanup_io_events(m, TRUE);
594 : 2 : cleanup_defer_events(m, TRUE);
595 : 2 : cleanup_time_events(m, TRUE);
596 : :
597 : 2 : pa_xfree(m->pollfds);
598 : :
599 : 2 : pa_close_pipe(m->wakeup_pipe);
600 : :
601 : 2 : pa_xfree(m);
602 : 2 : }
603 : :
604 : : static void scan_dead(pa_mainloop *m) {
605 [ - + ]: 4 : pa_assert(m);
606 : :
607 [ - + ]: 4 : if (m->io_events_please_scan)
608 : 0 : cleanup_io_events(m, FALSE);
609 : :
610 [ - + ]: 4 : if (m->time_events_please_scan)
611 : 0 : cleanup_time_events(m, FALSE);
612 : :
613 [ - + ]: 4 : if (m->defer_events_please_scan)
614 : 0 : cleanup_defer_events(m, FALSE);
615 : : }
616 : :
617 : 2 : static void rebuild_pollfds(pa_mainloop *m) {
618 : : pa_io_event*e;
619 : : struct pollfd *p;
620 : : unsigned l;
621 : :
622 : 2 : l = m->n_io_events + 1;
623 [ + - ]: 2 : if (m->max_pollfds < l) {
624 : 2 : l *= 2;
625 : 2 : m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l);
626 : 2 : m->max_pollfds = l;
627 : : }
628 : :
629 : 2 : m->n_pollfds = 0;
630 : 2 : p = m->pollfds;
631 : :
632 [ + - ]: 2 : if (m->wakeup_pipe[0] >= 0) {
633 : 2 : m->pollfds[0].fd = m->wakeup_pipe[0];
634 : 2 : m->pollfds[0].events = POLLIN;
635 : 2 : m->pollfds[0].revents = 0;
636 : 2 : p++;
637 : 2 : m->n_pollfds++;
638 : : }
639 : :
640 [ + + ]: 3 : PA_LLIST_FOREACH(e, m->io_events) {
641 [ - + ]: 1 : if (e->dead) {
642 : 0 : e->pollfd = NULL;
643 : 0 : continue;
644 : : }
645 : :
646 : 1 : e->pollfd = p;
647 : 1 : p->fd = e->fd;
648 : 2 : p->events = map_flags_to_libc(e->events);
649 : 1 : p->revents = 0;
650 : :
651 : 1 : p++;
652 : 1 : m->n_pollfds++;
653 : : }
654 : :
655 : 2 : m->rebuild_pollfds = FALSE;
656 : 2 : }
657 : :
658 : 0 : static unsigned dispatch_pollfds(pa_mainloop *m) {
659 : : pa_io_event *e;
660 : 0 : unsigned r = 0, k;
661 : :
662 [ # # ]: 0 : pa_assert(m->poll_func_ret > 0);
663 : :
664 : 0 : k = m->poll_func_ret;
665 : :
666 [ # # ]: 0 : PA_LLIST_FOREACH(e, m->io_events) {
667 : :
668 [ # # ][ # # ]: 0 : if (k <= 0 || m->quit)
669 : : break;
670 : :
671 [ # # ][ # # ]: 0 : if (e->dead || !e->pollfd || !e->pollfd->revents)
[ # # ]
672 : 0 : continue;
673 : :
674 [ # # ]: 0 : pa_assert(e->pollfd->fd == e->fd);
675 [ # # ]: 0 : pa_assert(e->callback);
676 : :
677 : 0 : e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata);
678 : 0 : e->pollfd->revents = 0;
679 : 0 : r++;
680 : 0 : k--;
681 : : }
682 : :
683 : 0 : return r;
684 : : }
685 : :
686 : 1 : static unsigned dispatch_defer(pa_mainloop *m) {
687 : : pa_defer_event *e;
688 : 1 : unsigned r = 0;
689 : :
690 [ + - ]: 1 : if (m->n_enabled_defer_events <= 0)
691 : : return 0;
692 : :
693 [ + + ]: 2 : PA_LLIST_FOREACH(e, m->defer_events) {
694 : :
695 [ + - ]: 1 : if (m->quit)
696 : : break;
697 : :
698 [ + - ][ - + ]: 1 : if (e->dead || !e->enabled)
699 : 0 : continue;
700 : :
701 [ - + ]: 1 : pa_assert(e->callback);
702 : 1 : e->callback(&m->api, e, e->userdata);
703 : 1 : r++;
704 : : }
705 : :
706 : : return r;
707 : : }
708 : :
709 : 2 : static pa_time_event* find_next_time_event(pa_mainloop *m) {
710 : 2 : pa_time_event *t, *n = NULL;
711 [ - + ]: 2 : pa_assert(m);
712 : :
713 [ - + ]: 2 : if (m->cached_next_time_event)
714 : 0 : return m->cached_next_time_event;
715 : :
716 [ + + ]: 4 : PA_LLIST_FOREACH(t, m->time_events) {
717 : :
718 [ + - ][ - + ]: 2 : if (t->dead || !t->enabled)
719 : 0 : continue;
720 : :
721 [ - + ][ # # ]: 2 : if (!n || t->time < n->time) {
722 : 2 : n = t;
723 : :
724 : : /* Shortcut for time == 0 */
725 [ + - ]: 2 : if (n->time == 0)
726 : : break;
727 : : }
728 : : }
729 : :
730 : 2 : m->cached_next_time_event = n;
731 : 2 : return n;
732 : : }
733 : :
734 : : static pa_usec_t calc_next_timeout(pa_mainloop *m) {
735 : : pa_time_event *t;
736 : : pa_usec_t clock_now;
737 : :
738 [ + + ]: 3 : if (m->n_enabled_time_events <= 0)
739 : : return PA_USEC_INVALID;
740 : :
741 [ - + ]: 2 : pa_assert_se(t = find_next_time_event(m));
742 : :
743 [ + - ]: 2 : if (t->time <= 0)
744 : : return 0;
745 : :
746 : 2 : clock_now = pa_rtclock_now();
747 : :
748 [ + - ]: 2 : if (t->time <= clock_now)
749 : : return 0;
750 : :
751 : 2 : return t->time - clock_now;
752 : : }
753 : :
754 : 2 : static unsigned dispatch_timeout(pa_mainloop *m) {
755 : : pa_time_event *e;
756 : : pa_usec_t now;
757 : 2 : unsigned r = 0;
758 [ - + ]: 2 : pa_assert(m);
759 : :
760 [ + - ]: 2 : if (m->n_enabled_time_events <= 0)
761 : : return 0;
762 : :
763 : 2 : now = pa_rtclock_now();
764 : :
765 [ + + ]: 4 : PA_LLIST_FOREACH(e, m->time_events) {
766 : :
767 [ + - ]: 2 : if (m->quit)
768 : : break;
769 : :
770 [ + - ][ - + ]: 2 : if (e->dead || !e->enabled)
771 : 0 : continue;
772 : :
773 [ + - ]: 2 : if (e->time <= now) {
774 : : struct timeval tv;
775 [ - + ]: 2 : pa_assert(e->callback);
776 : :
777 : : /* Disable time event */
778 : 2 : mainloop_time_restart(e, NULL);
779 : :
780 : 2 : e->callback(&m->api, e, pa_timeval_rtstore(&tv, e->time, e->use_rtclock), e->userdata);
781 : :
782 : 2 : r++;
783 : : }
784 : : }
785 : :
786 : : return r;
787 : : }
788 : :
789 : 7 : void pa_mainloop_wakeup(pa_mainloop *m) {
790 : 7 : char c = 'W';
791 [ - + ]: 7 : pa_assert(m);
792 : :
793 [ + - ][ + + ]: 7 : if (m->wakeup_pipe[1] >= 0 && m->state == STATE_POLLING) {
794 : 1 : pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type);
795 : 1 : m->wakeup_requested++;
796 : : }
797 : 7 : }
798 : :
799 : : static void clear_wakeup(pa_mainloop *m) {
800 : : char c[10];
801 : :
802 [ - + ]: 4 : pa_assert(m);
803 : :
804 [ + - ]: 4 : if (m->wakeup_pipe[0] < 0)
805 : : return;
806 : :
807 [ - + ]: 4 : if (m->wakeup_requested) {
808 [ # # ]: 0 : while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c))
809 : : ;
810 : 0 : m->wakeup_requested = 0;
811 : : }
812 : : }
813 : :
814 : 4 : int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
815 [ - + ]: 4 : pa_assert(m);
816 [ - + ]: 4 : pa_assert(m->state == STATE_PASSIVE);
817 : :
818 : : clear_wakeup(m);
819 : : scan_dead(m);
820 : :
821 [ + - ]: 4 : if (m->quit)
822 : : goto quit;
823 : :
824 [ + + ]: 4 : if (m->n_enabled_defer_events <= 0) {
825 : :
826 [ + + ]: 3 : if (m->rebuild_pollfds)
827 : 2 : rebuild_pollfds(m);
828 : :
829 : 3 : m->prepared_timeout = calc_next_timeout(m);
830 [ - + ]: 3 : if (timeout >= 0) {
831 : 0 : uint64_t u = (uint64_t) timeout * PA_USEC_PER_MSEC;
832 : :
833 [ # # ][ # # ]: 0 : if (u < m->prepared_timeout || m->prepared_timeout == PA_USEC_INVALID)
834 : 0 : m->prepared_timeout = timeout;
835 : : }
836 : : }
837 : :
838 : 4 : m->state = STATE_PREPARED;
839 : 4 : return 0;
840 : :
841 : : quit:
842 : 0 : m->state = STATE_QUIT;
843 : 4 : return -2;
844 : : }
845 : :
846 : : static int usec_to_timeout(pa_usec_t u) {
847 : : int timeout;
848 : :
849 [ + + ]: 2 : if (u == PA_USEC_INVALID)
850 : : return -1;
851 : :
852 : 1 : timeout = (u + PA_USEC_PER_MSEC - 1) / PA_USEC_PER_MSEC;
853 [ - + ]: 1 : pa_assert(timeout >= 0);
854 : :
855 : : return timeout;
856 : : }
857 : :
858 : 4 : int pa_mainloop_poll(pa_mainloop *m) {
859 [ - + ]: 4 : pa_assert(m);
860 [ - + ]: 4 : pa_assert(m->state == STATE_PREPARED);
861 : :
862 [ + - ]: 4 : if (m->quit)
863 : : goto quit;
864 : :
865 : 4 : m->state = STATE_POLLING;
866 : :
867 [ + + ]: 4 : if (m->n_enabled_defer_events )
868 : 1 : m->poll_func_ret = 0;
869 : : else {
870 [ - + ]: 3 : pa_assert(!m->rebuild_pollfds);
871 : :
872 [ + + ]: 3 : if (m->poll_func)
873 : 2 : m->poll_func_ret = m->poll_func(
874 : 2 : m->pollfds, m->n_pollfds,
875 : : usec_to_timeout(m->prepared_timeout),
876 : : m->poll_func_userdata);
877 : : else {
878 : : #ifdef HAVE_PPOLL
879 : : struct timespec ts;
880 : :
881 [ + - ]: 1 : m->poll_func_ret = ppoll(
882 : 1 : m->pollfds, m->n_pollfds,
883 : 2 : m->prepared_timeout == PA_USEC_INVALID ? NULL : pa_timespec_store(&ts, m->prepared_timeout),
884 : : NULL);
885 : : #else
886 : : m->poll_func_ret = pa_poll(
887 : : m->pollfds, m->n_pollfds,
888 : : usec_to_timeout(m->prepared_timeout));
889 : : #endif
890 : : }
891 : :
892 [ - + ]: 3 : if (m->poll_func_ret < 0) {
893 [ # # ]: 0 : if (errno == EINTR)
894 : 0 : m->poll_func_ret = 0;
895 : : else
896 : 0 : pa_log("poll(): %s", pa_cstrerror(errno));
897 : : }
898 : : }
899 : :
900 [ + - ]: 4 : m->state = m->poll_func_ret < 0 ? STATE_PASSIVE : STATE_POLLED;
901 : 4 : return m->poll_func_ret;
902 : :
903 : : quit:
904 : 0 : m->state = STATE_QUIT;
905 : 4 : return -2;
906 : : }
907 : :
908 : 4 : int pa_mainloop_dispatch(pa_mainloop *m) {
909 : 4 : unsigned dispatched = 0;
910 : :
911 [ - + ]: 4 : pa_assert(m);
912 [ - + ]: 4 : pa_assert(m->state == STATE_POLLED);
913 : :
914 [ + + ]: 4 : if (m->quit)
915 : : goto quit;
916 : :
917 [ + + ]: 3 : if (m->n_enabled_defer_events)
918 : 1 : dispatched += dispatch_defer(m);
919 : : else {
920 [ + - ]: 2 : if (m->n_enabled_time_events)
921 : 2 : dispatched += dispatch_timeout(m);
922 : :
923 [ + + ]: 2 : if (m->quit)
924 : : goto quit;
925 : :
926 [ - + ]: 1 : if (m->poll_func_ret > 0)
927 : 0 : dispatched += dispatch_pollfds(m);
928 : : }
929 : :
930 [ + - ]: 2 : if (m->quit)
931 : : goto quit;
932 : :
933 : 2 : m->state = STATE_PASSIVE;
934 : :
935 : 2 : return (int) dispatched;
936 : :
937 : : quit:
938 : 2 : m->state = STATE_QUIT;
939 : 4 : return -2;
940 : : }
941 : :
942 : 0 : int pa_mainloop_get_retval(pa_mainloop *m) {
943 [ # # ]: 0 : pa_assert(m);
944 : :
945 : 0 : return m->retval;
946 : : }
947 : :
948 : 4 : int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
949 : : int r;
950 [ - + ]: 4 : pa_assert(m);
951 : :
952 [ - + ][ + - ]: 4 : if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0)
953 : : goto quit;
954 : :
955 [ + - ]: 4 : if ((r = pa_mainloop_poll(m)) < 0)
956 : : goto quit;
957 : :
958 [ + + ]: 4 : if ((r = pa_mainloop_dispatch(m)) < 0)
959 : : goto quit;
960 : :
961 : : return r;
962 : :
963 : : quit:
964 : :
965 [ - + ]: 2 : if ((r == -2) && retval)
966 : 4 : *retval = pa_mainloop_get_retval(m);
967 : : return r;
968 : : }
969 : :
970 : 2 : int pa_mainloop_run(pa_mainloop *m, int *retval) {
971 : : int r;
972 : :
973 [ + + ]: 4 : while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0)
974 : : ;
975 : :
976 [ - + ]: 2 : if (r == -2)
977 : : return 1;
978 [ # # ]: 0 : else if (r < 0)
979 : : return -1;
980 : : else
981 : 2 : return 0;
982 : : }
983 : :
984 : 2 : void pa_mainloop_quit(pa_mainloop *m, int retval) {
985 [ - + ]: 2 : pa_assert(m);
986 : :
987 : 2 : m->quit = TRUE;
988 : 2 : m->retval = retval;
989 : 2 : pa_mainloop_wakeup(m);
990 : 2 : }
991 : :
992 : 2 : pa_mainloop_api* pa_mainloop_get_api(pa_mainloop *m) {
993 [ - + ]: 2 : pa_assert(m);
994 : :
995 : 2 : return &m->api;
996 : : }
997 : :
998 : 1 : void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
999 [ - + ]: 1 : pa_assert(m);
1000 : :
1001 : 1 : m->poll_func = poll_func;
1002 : 1 : m->poll_func_userdata = userdata;
1003 : 1 : }
1004 : :
1005 : 0 : pa_bool_t pa_mainloop_is_our_api(pa_mainloop_api *m) {
1006 [ # # ]: 0 : pa_assert(m);
1007 : :
1008 : 0 : return m->io_new == mainloop_io_new;
1009 : : }
|