]> code.delx.au - pulseaudio/blob - src/pulsecore/rtpoll.c
treat timer_enabled like a real, grown-up boolean variable
[pulseaudio] / src / pulsecore / rtpoll.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <sys/utsname.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #include <pulse/xmalloc.h>
37
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/rtclock.h>
40 #include <pulsecore/macro.h>
41 #include <pulsecore/llist.h>
42 #include <pulsecore/rtsig.h>
43 #include <pulsecore/flist.h>
44 #include <pulsecore/core-util.h>
45
46 #include "rtpoll.h"
47
48 struct pa_rtpoll {
49 struct pollfd *pollfd, *pollfd2;
50 unsigned n_pollfd_alloc, n_pollfd_used;
51
52 pa_bool_t timer_enabled;
53 struct timespec next_elapse;
54 pa_usec_t period;
55
56 pa_bool_t scan_for_dead;
57 pa_bool_t running, installed, rebuild_needed, quit;
58
59 #ifdef HAVE_PPOLL
60 int rtsig;
61 sigset_t sigset_unblocked;
62 timer_t timer;
63 #ifdef __linux__
64 pa_bool_t dont_use_ppoll;
65 #endif
66 #endif
67
68 PA_LLIST_HEAD(pa_rtpoll_item, items);
69 };
70
71 struct pa_rtpoll_item {
72 pa_rtpoll *rtpoll;
73 pa_bool_t dead;
74
75 pa_rtpoll_priority_t priority;
76
77 struct pollfd *pollfd;
78 unsigned n_pollfd;
79
80 int (*work_cb)(pa_rtpoll_item *i);
81 int (*before_cb)(pa_rtpoll_item *i);
82 void (*after_cb)(pa_rtpoll_item *i);
83 void *userdata;
84
85 PA_LLIST_FIELDS(pa_rtpoll_item);
86 };
87
88 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
89
90 static void signal_handler_noop(int s) { }
91
92 pa_rtpoll *pa_rtpoll_new(void) {
93 pa_rtpoll *p;
94
95 p = pa_xnew(pa_rtpoll, 1);
96
97 #ifdef HAVE_PPOLL
98
99 #ifdef __linux__
100 /* ppoll is broken on Linux < 2.6.16 */
101 p->dont_use_ppoll = FALSE;
102
103 {
104 struct utsname u;
105 unsigned major, minor, micro;
106
107 pa_assert_se(uname(&u) == 0);
108
109 if (sscanf(u.release, "%u.%u.%u", &major, &minor, &micro) != 3 ||
110 (major < 2) ||
111 (major == 2 && minor < 6) ||
112 (major == 2 && minor == 6 && micro < 16))
113
114 p->dont_use_ppoll = TRUE;
115 }
116
117 #endif
118
119 p->rtsig = -1;
120 sigemptyset(&p->sigset_unblocked);
121 p->timer = (timer_t) -1;
122
123 #endif
124
125 p->n_pollfd_alloc = 32;
126 p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
127 p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
128 p->n_pollfd_used = 0;
129
130 p->period = 0;
131 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
132 p->timer_enabled = FALSE;
133
134 p->running = FALSE;
135 p->installed = FALSE;
136 p->scan_for_dead = FALSE;
137 p->rebuild_needed = FALSE;
138 p->quit = FALSE;
139
140 PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items);
141
142 return p;
143 }
144
145 void pa_rtpoll_install(pa_rtpoll *p) {
146 pa_assert(p);
147 pa_assert(!p->installed);
148
149 p->installed = 1;
150
151 #ifdef HAVE_PPOLL
152 if (p->dont_use_ppoll)
153 return;
154
155 if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) {
156 pa_log_warn("Failed to reserve POSIX realtime signal.");
157 return;
158 }
159
160 pa_log_debug("Acquired POSIX realtime signal %s", pa_sig2str(p->rtsig));
161
162 {
163 sigset_t ss;
164 struct sigaction sa;
165
166 pa_assert_se(sigemptyset(&ss) == 0);
167 pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
168 pa_assert_se(pthread_sigmask(SIG_BLOCK, &ss, &p->sigset_unblocked) == 0);
169 pa_assert_se(sigdelset(&p->sigset_unblocked, p->rtsig) == 0);
170
171 memset(&sa, 0, sizeof(sa));
172 sa.sa_handler = signal_handler_noop;
173 pa_assert_se(sigemptyset(&sa.sa_mask) == 0);
174
175 pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0);
176
177 /* We never reset the signal handler. Why should we? */
178 }
179
180 #endif
181 }
182
183 static void rtpoll_rebuild(pa_rtpoll *p) {
184
185 struct pollfd *e, *t;
186 pa_rtpoll_item *i;
187 int ra = 0;
188
189 pa_assert(p);
190
191 p->rebuild_needed = FALSE;
192
193 if (p->n_pollfd_used > p->n_pollfd_alloc) {
194 /* Hmm, we have to allocate some more space */
195 p->n_pollfd_alloc = p->n_pollfd_used * 2;
196 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
197 ra = 1;
198 }
199
200 e = p->pollfd2;
201
202 for (i = p->items; i; i = i->next) {
203
204 if (i->n_pollfd > 0) {
205 size_t l = i->n_pollfd * sizeof(struct pollfd);
206
207 if (i->pollfd)
208 memcpy(e, i->pollfd, l);
209 else
210 memset(e, 0, l);
211
212 i->pollfd = e;
213 } else
214 i->pollfd = NULL;
215
216 e += i->n_pollfd;
217 }
218
219 pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
220 t = p->pollfd;
221 p->pollfd = p->pollfd2;
222 p->pollfd2 = t;
223
224 if (ra)
225 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
226
227 }
228
229 static void rtpoll_item_destroy(pa_rtpoll_item *i) {
230 pa_rtpoll *p;
231
232 pa_assert(i);
233
234 p = i->rtpoll;
235
236 PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
237
238 p->n_pollfd_used -= i->n_pollfd;
239
240 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
241 pa_xfree(i);
242
243 p->rebuild_needed = TRUE;
244 }
245
246 void pa_rtpoll_free(pa_rtpoll *p) {
247 pa_assert(p);
248
249 while (p->items)
250 rtpoll_item_destroy(p->items);
251
252 pa_xfree(p->pollfd);
253 pa_xfree(p->pollfd2);
254
255 #ifdef HAVE_PPOLL
256 if (p->timer != (timer_t) -1)
257 timer_delete(p->timer);
258 #endif
259
260 pa_xfree(p);
261 }
262
263 static void reset_revents(pa_rtpoll_item *i) {
264 struct pollfd *f;
265 unsigned n;
266
267 pa_assert(i);
268
269 if (!(f = pa_rtpoll_item_get_pollfd(i, &n)))
270 return;
271
272 for (; n > 0; n--)
273 f[n-1].revents = 0;
274 }
275
276 static void reset_all_revents(pa_rtpoll *p) {
277 pa_rtpoll_item *i;
278
279 pa_assert(p);
280
281 for (i = p->items; i; i = i->next) {
282
283 if (i->dead)
284 continue;
285
286 reset_revents(i);
287 }
288 }
289
290 int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
291 pa_rtpoll_item *i;
292 int r = 0;
293 struct timespec timeout;
294
295 pa_assert(p);
296 pa_assert(!p->running);
297 pa_assert(p->installed);
298
299 p->running = TRUE;
300
301 /* First, let's do some work */
302 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
303 int k;
304
305 if (i->dead)
306 continue;
307
308 if (!i->work_cb)
309 continue;
310
311 if (p->quit)
312 goto finish;
313
314 if ((k = i->work_cb(i)) != 0) {
315 if (k < 0)
316 r = k;
317
318 goto finish;
319 }
320 }
321
322 /* Now let's prepare for entering the sleep */
323 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
324 int k = 0;
325
326 if (i->dead)
327 continue;
328
329 if (!i->before_cb)
330 continue;
331
332 if (p->quit || (k = i->before_cb(i)) != 0) {
333
334 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
335
336 for (i = i->prev; i; i = i->prev) {
337
338 if (i->dead)
339 continue;
340
341 if (!i->after_cb)
342 continue;
343
344 i->after_cb(i);
345 }
346
347 if (k < 0)
348 r = k;
349
350 goto finish;
351 }
352 }
353
354 if (p->rebuild_needed)
355 rtpoll_rebuild(p);
356
357 /* Calculate timeout */
358 if (!wait || p->quit) {
359 timeout.tv_sec = 0;
360 timeout.tv_nsec = 0;
361 } else if (p->timer_enabled) {
362 struct timespec now;
363 pa_rtclock_get(&now);
364
365 if (pa_timespec_cmp(&p->next_elapse, &now) <= 0)
366 memset(&timeout, 0, sizeof(timeout));
367 else
368 pa_timespec_store(&timeout, pa_timespec_diff(&p->next_elapse, &now));
369 }
370
371 /* OK, now let's sleep */
372 #ifdef HAVE_PPOLL
373
374 #ifdef __linux__
375 if (!p->dont_use_ppoll)
376 #endif
377 r = ppoll(p->pollfd, p->n_pollfd_used, p->timer_enabled ? &timeout : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked);
378 #ifdef __linux__
379 else
380 #endif
381
382 #endif
383 r = poll(p->pollfd, p->n_pollfd_used, p->timer_enabled ? (timeout.tv_sec*1000) + (timeout.tv_nsec / 1000000) : -1);
384
385 if (r < 0) {
386 if (errno == EAGAIN || errno == EINTR)
387 r = 0;
388 else
389 pa_log_error("poll(): %s", pa_cstrerror(errno));
390
391 reset_all_revents(p);
392 }
393
394 if (p->timer_enabled) {
395 if (p->period > 0) {
396 struct timespec now;
397 pa_rtclock_get(&now);
398
399 pa_timespec_add(&p->next_elapse, p->period);
400
401 /* Guarantee that the next timeout will happen in the future */
402 if (pa_timespec_cmp(&p->next_elapse, &now) < 0)
403 pa_timespec_add(&p->next_elapse, (pa_timespec_diff(&now, &p->next_elapse) / p->period + 1) * p->period);
404
405 } else
406 p->timer_enabled = FALSE;
407 }
408
409 /* Let's tell everyone that we left the sleep */
410 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
411
412 if (i->dead)
413 continue;
414
415 if (!i->after_cb)
416 continue;
417
418 i->after_cb(i);
419 }
420
421 finish:
422
423 p->running = FALSE;
424
425 if (p->scan_for_dead) {
426 pa_rtpoll_item *n;
427
428 p->scan_for_dead = FALSE;
429
430 for (i = p->items; i; i = n) {
431 n = i->next;
432
433 if (i->dead)
434 rtpoll_item_destroy(i);
435 }
436 }
437
438 return r < 0 ? r : !p->quit;
439 }
440
441 static void update_timer(pa_rtpoll *p) {
442 pa_assert(p);
443
444 #ifdef HAVE_PPOLL
445
446 #ifdef __linux__
447 if (!p->dont_use_ppoll) {
448 #endif
449
450 if (p->timer == (timer_t) -1) {
451 struct sigevent se;
452
453 memset(&se, 0, sizeof(se));
454 se.sigev_notify = SIGEV_SIGNAL;
455 se.sigev_signo = p->rtsig;
456
457 if (timer_create(CLOCK_MONOTONIC, &se, &p->timer) < 0)
458 if (timer_create(CLOCK_REALTIME, &se, &p->timer) < 0) {
459 pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno));
460 p->timer = (timer_t) -1;
461 }
462 }
463
464 if (p->timer != (timer_t) -1) {
465 struct itimerspec its;
466 memset(&its, 0, sizeof(its));
467
468 if (p->timer_enabled) {
469 its.it_value = p->next_elapse;
470
471 /* Make sure that 0,0 is not understood as
472 * "disarming" */
473 if (its.it_value.tv_sec == 0)
474 its.it_value.tv_nsec = 1;
475
476 if (p->period > 0)
477 pa_timespec_store(&its.it_interval, p->period);
478 }
479
480 pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
481 }
482
483 #ifdef __linux__
484 }
485 #endif
486
487 #endif
488 }
489
490 void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timespec *ts) {
491 pa_assert(p);
492 pa_assert(ts);
493
494 p->next_elapse = *ts;
495 p->period = 0;
496 p->timer_enabled = TRUE;
497
498 update_timer(p);
499 }
500
501 void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec) {
502 pa_assert(p);
503
504 p->period = usec;
505 pa_rtclock_get(&p->next_elapse);
506 pa_timespec_add(&p->next_elapse, usec);
507 p->timer_enabled = TRUE;
508
509 update_timer(p);
510 }
511
512 void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
513 pa_assert(p);
514
515 p->period = 0;
516 pa_rtclock_get(&p->next_elapse);
517 pa_timespec_add(&p->next_elapse, usec);
518 p->timer_enabled = TRUE;
519
520 update_timer(p);
521 }
522
523 void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
524 pa_assert(p);
525
526 p->period = 0;
527 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
528 p->timer_enabled = FALSE;
529
530 update_timer(p);
531 }
532
533 pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {
534 pa_rtpoll_item *i, *j, *l = NULL;
535
536 pa_assert(p);
537
538 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
539 i = pa_xnew(pa_rtpoll_item, 1);
540
541 i->rtpoll = p;
542 i->dead = FALSE;
543 i->n_pollfd = n_fds;
544 i->pollfd = NULL;
545 i->priority = prio;
546
547 i->userdata = NULL;
548 i->before_cb = NULL;
549 i->after_cb = NULL;
550 i->work_cb = NULL;
551
552 for (j = p->items; j; j = j->next) {
553 if (prio <= j->priority)
554 break;
555
556 l = j;
557 }
558
559 PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i);
560
561 if (n_fds > 0) {
562 p->rebuild_needed = 1;
563 p->n_pollfd_used += n_fds;
564 }
565
566 return i;
567 }
568
569 void pa_rtpoll_item_free(pa_rtpoll_item *i) {
570 pa_assert(i);
571
572 if (i->rtpoll->running) {
573 i->dead = TRUE;
574 i->rtpoll->scan_for_dead = TRUE;
575 return;
576 }
577
578 rtpoll_item_destroy(i);
579 }
580
581 struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
582 pa_assert(i);
583
584 if (i->n_pollfd > 0)
585 if (i->rtpoll->rebuild_needed)
586 rtpoll_rebuild(i->rtpoll);
587
588 if (n_fds)
589 *n_fds = i->n_pollfd;
590
591 return i->pollfd;
592 }
593
594 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)) {
595 pa_assert(i);
596 pa_assert(i->priority < PA_RTPOLL_NEVER);
597
598 i->before_cb = before_cb;
599 }
600
601 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i)) {
602 pa_assert(i);
603 pa_assert(i->priority < PA_RTPOLL_NEVER);
604
605 i->after_cb = after_cb;
606 }
607
608 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i)) {
609 pa_assert(i);
610 pa_assert(i->priority < PA_RTPOLL_NEVER);
611
612 i->work_cb = work_cb;
613 }
614
615 void pa_rtpoll_item_set_userdata(pa_rtpoll_item *i, void *userdata) {
616 pa_assert(i);
617
618 i->userdata = userdata;
619 }
620
621 void* pa_rtpoll_item_get_userdata(pa_rtpoll_item *i) {
622 pa_assert(i);
623
624 return i->userdata;
625 }
626
627 static int fdsem_before(pa_rtpoll_item *i) {
628
629 if (pa_fdsem_before_poll(i->userdata) < 0)
630 return 1; /* 1 means immediate restart of the loop */
631
632 return 0;
633 }
634
635 static void fdsem_after(pa_rtpoll_item *i) {
636 pa_assert(i);
637
638 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
639 pa_fdsem_after_poll(i->userdata);
640 }
641
642 pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) {
643 pa_rtpoll_item *i;
644 struct pollfd *pollfd;
645
646 pa_assert(p);
647 pa_assert(f);
648
649 i = pa_rtpoll_item_new(p, prio, 1);
650
651 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
652
653 pollfd->fd = pa_fdsem_get(f);
654 pollfd->events = POLLIN;
655
656 i->before_cb = fdsem_before;
657 i->after_cb = fdsem_after;
658 i->userdata = f;
659
660 return i;
661 }
662
663 static int asyncmsgq_before(pa_rtpoll_item *i) {
664 pa_assert(i);
665
666 if (pa_asyncmsgq_before_poll(i->userdata) < 0)
667 return 1; /* 1 means immediate restart of the loop */
668
669 return 0;
670 }
671
672 static void asyncmsgq_after(pa_rtpoll_item *i) {
673 pa_assert(i);
674
675 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
676 pa_asyncmsgq_after_poll(i->userdata);
677 }
678
679 static int asyncmsgq_work(pa_rtpoll_item *i) {
680 pa_msgobject *object;
681 int code;
682 void *data;
683 pa_memchunk chunk;
684 int64_t offset;
685
686 pa_assert(i);
687
688 if (pa_asyncmsgq_get(i->userdata, &object, &code, &data, &offset, &chunk, 0) == 0) {
689 int ret;
690
691 if (!object && code == PA_MESSAGE_SHUTDOWN) {
692 pa_asyncmsgq_done(i->userdata, 0);
693 pa_rtpoll_quit(i->rtpoll);
694 return 1;
695 }
696
697 ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
698 pa_asyncmsgq_done(i->userdata, ret);
699 return 1;
700 }
701
702 return 0;
703 }
704
705 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
706 pa_rtpoll_item *i;
707 struct pollfd *pollfd;
708
709 pa_assert(p);
710 pa_assert(q);
711
712 i = pa_rtpoll_item_new(p, prio, 1);
713
714 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
715 pollfd->fd = pa_asyncmsgq_get_fd(q);
716 pollfd->events = POLLIN;
717
718 i->before_cb = asyncmsgq_before;
719 i->after_cb = asyncmsgq_after;
720 i->work_cb = asyncmsgq_work;
721 i->userdata = q;
722
723 return i;
724 }
725
726 void pa_rtpoll_quit(pa_rtpoll *p) {
727 pa_assert(p);
728
729 p->quit = TRUE;
730 }