]> code.delx.au - pulseaudio/blob - src/pulsecore/rtpoll.c
extend rtpoll API to allow registration of arbitray functions to be executed in the...
[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
45 #include "rtpoll.h"
46
47 struct pa_rtpoll {
48 struct pollfd *pollfd, *pollfd2;
49 unsigned n_pollfd_alloc, n_pollfd_used;
50
51 int timer_enabled;
52 struct timespec next_elapse;
53 pa_usec_t period;
54
55 int scan_for_dead;
56 int running, installed, rebuild_needed;
57
58 #ifdef HAVE_PPOLL
59 int rtsig;
60 sigset_t sigset_unblocked;
61 timer_t timer;
62 #ifdef __linux__
63 int dont_use_ppoll;
64 #endif
65 #endif
66
67 PA_LLIST_HEAD(pa_rtpoll_item, items);
68 };
69
70 struct pa_rtpoll_item {
71 pa_rtpoll *rtpoll;
72 int dead;
73
74 pa_rtpoll_priority_t priority;
75
76 struct pollfd *pollfd;
77 unsigned n_pollfd;
78
79 int (*before_cb)(pa_rtpoll_item *i);
80 void (*after_cb)(pa_rtpoll_item *i);
81 void *userdata;
82
83 PA_LLIST_FIELDS(pa_rtpoll_item);
84 };
85
86 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
87
88 static void signal_handler_noop(int s) { }
89
90 pa_rtpoll *pa_rtpoll_new(void) {
91 pa_rtpoll *p;
92
93 p = pa_xnew(pa_rtpoll, 1);
94
95 #ifdef HAVE_PPOLL
96
97 #ifdef __linux__
98 /* ppoll is broken on Linux < 2.6.16 */
99
100 p->dont_use_ppoll = 0;
101
102 {
103 struct utsname u;
104 unsigned major, minor, micro;
105
106 pa_assert_se(uname(&u) == 0);
107
108 if (sscanf(u.release, "%u.%u.%u", &major, &minor, &micro) != 3 ||
109 (major < 2) ||
110 (major == 2 && minor < 6) ||
111 (major == 2 && minor == 6 && micro < 16))
112
113 p->dont_use_ppoll = 1;
114 }
115
116 #endif
117
118 p->rtsig = -1;
119 sigemptyset(&p->sigset_unblocked);
120 p->timer = (timer_t) -1;
121
122 #endif
123
124 p->n_pollfd_alloc = 32;
125 p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
126 p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
127 p->n_pollfd_used = 0;
128
129 p->period = 0;
130 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
131 p->timer_enabled = 0;
132
133 p->running = 0;
134 p->installed = 0;
135 p->scan_for_dead = 0;
136 p->rebuild_needed = 0;
137
138 PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items);
139
140 return p;
141 }
142
143 void pa_rtpoll_install(pa_rtpoll *p) {
144 pa_assert(p);
145 pa_assert(!p->installed);
146
147 p->installed = 1;
148
149 #ifdef HAVE_PPOLL
150 if (p->dont_use_ppoll)
151 return;
152
153 if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) {
154 pa_log_warn("Failed to reserve POSIX realtime signal.");
155 return;
156 }
157
158 pa_log_debug("Acquired POSIX realtime signal SIGRTMIN+%i", p->rtsig - SIGRTMIN);
159
160 {
161 sigset_t ss;
162 struct sigaction sa;
163
164 pa_assert_se(sigemptyset(&ss) == 0);
165 pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
166 pa_assert_se(pthread_sigmask(SIG_BLOCK, &ss, &p->sigset_unblocked) == 0);
167 pa_assert_se(sigdelset(&p->sigset_unblocked, p->rtsig) == 0);
168
169 memset(&sa, 0, sizeof(sa));
170 sa.sa_handler = signal_handler_noop;
171 pa_assert_se(sigemptyset(&sa.sa_mask) == 0);
172
173 pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0);
174
175 /* We never reset the signal handler. Why should we? */
176 }
177
178 #endif
179 }
180
181 static void rtpoll_rebuild(pa_rtpoll *p) {
182
183 struct pollfd *e, *t;
184 pa_rtpoll_item *i;
185 int ra = 0;
186
187 pa_assert(p);
188
189 p->rebuild_needed = 0;
190
191 if (p->n_pollfd_used > p->n_pollfd_alloc) {
192 /* Hmm, we have to allocate some more space */
193 p->n_pollfd_alloc = p->n_pollfd_used * 2;
194 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
195 ra = 1;
196 }
197
198 e = p->pollfd2;
199
200 for (i = p->items; i; i = i->next) {
201
202 if (i->n_pollfd > 0) {
203 size_t l = i->n_pollfd * sizeof(struct pollfd);
204
205 if (i->pollfd)
206 memcpy(e, i->pollfd, l);
207 else
208 memset(e, 0, l);
209
210 i->pollfd = e;
211 } else
212 i->pollfd = NULL;
213
214 e += i->n_pollfd;
215 }
216
217 pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
218 t = p->pollfd;
219 p->pollfd = p->pollfd2;
220 p->pollfd2 = t;
221
222 if (ra)
223 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
224
225 }
226
227 static void rtpoll_item_destroy(pa_rtpoll_item *i) {
228 pa_rtpoll *p;
229
230 pa_assert(i);
231
232 p = i->rtpoll;
233
234 PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
235
236 p->n_pollfd_used -= i->n_pollfd;
237
238 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
239 pa_xfree(i);
240
241 p->rebuild_needed = 1;
242 }
243
244 void pa_rtpoll_free(pa_rtpoll *p) {
245 pa_assert(p);
246
247 while (p->items)
248 rtpoll_item_destroy(p->items);
249
250 pa_xfree(p->pollfd);
251 pa_xfree(p->pollfd2);
252
253 #ifdef HAVE_PPOLL
254 if (p->timer != (timer_t) -1)
255 timer_delete(p->timer);
256 #endif
257
258 pa_xfree(p);
259 }
260
261 static void reset_revents(pa_rtpoll_item *i) {
262 struct pollfd *f;
263 unsigned n;
264
265 pa_assert(i);
266
267 if (!(f = pa_rtpoll_item_get_pollfd(i, &n)))
268 return;
269
270 for (; n > 0; n--)
271 f[n-1].revents = 0;
272 }
273
274 static void reset_all_revents(pa_rtpoll *p) {
275 pa_rtpoll_item *i;
276
277 pa_assert(p);
278
279 for (i = p->items; i; i = i->next) {
280
281 if (i->dead)
282 continue;
283
284 reset_revents(i);
285 }
286 }
287
288 int pa_rtpoll_run(pa_rtpoll *p, int wait) {
289 pa_rtpoll_item *i;
290 int r = 0;
291 int saved_errno = 0;
292 struct timespec timeout;
293
294 pa_assert(p);
295 pa_assert(!p->running);
296 pa_assert(p->installed);
297
298 p->running = 1;
299
300 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
301 int k;
302
303 if (i->dead)
304 continue;
305
306 if (!i->before_cb)
307 continue;
308
309 if ((k = i->before_cb(i)) != 0) {
310
311 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
312
313 reset_all_revents(p);
314
315 for (i = i->prev; i; i = i->prev) {
316
317 if (i->dead)
318 continue;
319
320 if (!i->after_cb)
321 continue;
322
323 i->after_cb(i);
324 }
325
326 if (k < 0)
327 r = k;
328
329 goto finish;
330 }
331 }
332
333 if (p->rebuild_needed)
334 rtpoll_rebuild(p);
335
336 /* Calculate timeout */
337 if (!wait) {
338 timeout.tv_sec = 0;
339 timeout.tv_nsec = 0;
340 } else if (p->timer_enabled) {
341 struct timespec now;
342 pa_rtclock_get(&now);
343
344 if (pa_timespec_cmp(&p->next_elapse, &now) <= 0)
345 memset(&timeout, 0, sizeof(timeout));
346 else
347 pa_timespec_store(&timeout, pa_timespec_diff(&p->next_elapse, &now));
348 }
349
350 /* OK, now let's sleep */
351 #ifdef HAVE_PPOLL
352
353 #ifdef __linux__
354 if (!p->dont_use_ppoll)
355 #endif
356 r = ppoll(p->pollfd, p->n_pollfd_used, p->timer_enabled > 0 ? &timeout : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked);
357 #ifdef __linux__
358 else
359 #endif
360
361 #else
362 r = poll(p->pollfd, p->n_pollfd_used, p->timer_enabled > 0 ? (timeout.tv_sec*1000) + (timeout.tv_nsec / 1000000) : -1);
363 #endif
364
365 if (r < 0)
366 reset_all_revents(p);
367
368 if (r < 0 && (errno == EAGAIN || errno == EINTR))
369 r = 0;
370
371 saved_errno = r < 0 ? errno : 0;
372
373 if (p->timer_enabled) {
374 if (p->period > 0) {
375 struct timespec now;
376 pa_rtclock_get(&now);
377
378 pa_timespec_add(&p->next_elapse, p->period);
379
380 /* Guarantee that the next timeout will happen in the future */
381 if (pa_timespec_cmp(&p->next_elapse, &now) < 0)
382 pa_timespec_add(&p->next_elapse, (pa_timespec_diff(&now, &p->next_elapse) / p->period + 1) * p->period);
383
384 } else
385 p->timer_enabled = 0;
386 }
387
388 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
389
390 if (i->dead)
391 continue;
392
393 if (!i->after_cb)
394 continue;
395
396 i->after_cb(i);
397 }
398
399 finish:
400
401 p->running = 0;
402
403 if (p->scan_for_dead) {
404 pa_rtpoll_item *n;
405
406 p->scan_for_dead = 0;
407
408 for (i = p->items; i; i = n) {
409 n = i->next;
410
411 if (i->dead)
412 rtpoll_item_destroy(i);
413 }
414 }
415
416 if (saved_errno != 0)
417 errno = saved_errno;
418
419 return r;
420 }
421
422 static void update_timer(pa_rtpoll *p) {
423 pa_assert(p);
424
425 #ifdef HAVE_PPOLL
426
427 #ifdef __linux__
428 if (!p->dont_use_ppoll) {
429 #endif
430
431 if (p->timer == (timer_t) -1) {
432 struct sigevent se;
433
434 memset(&se, 0, sizeof(se));
435 se.sigev_notify = SIGEV_SIGNAL;
436 se.sigev_signo = p->rtsig;
437
438 if (timer_create(CLOCK_MONOTONIC, &se, &p->timer) < 0)
439 if (timer_create(CLOCK_REALTIME, &se, &p->timer) < 0) {
440 pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno));
441 p->timer = (timer_t) -1;
442 }
443 }
444
445 if (p->timer != (timer_t) -1) {
446 struct itimerspec its;
447 memset(&its, 0, sizeof(its));
448
449 if (p->timer_enabled) {
450 its.it_value = p->next_elapse;
451
452 /* Make sure that 0,0 is not understood as
453 * "disarming" */
454 if (its.it_value.tv_sec == 0)
455 its.it_value.tv_nsec = 1;
456
457 if (p->period > 0)
458 pa_timespec_store(&its.it_interval, p->period);
459 }
460
461 pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
462 }
463
464 #ifdef __linux__
465 }
466 #endif
467
468 #endif
469 }
470
471 void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timespec *ts) {
472 pa_assert(p);
473 pa_assert(ts);
474
475 p->next_elapse = *ts;
476 p->period = 0;
477 p->timer_enabled = 1;
478
479 update_timer(p);
480 }
481
482 void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec) {
483 pa_assert(p);
484
485 p->period = usec;
486 pa_rtclock_get(&p->next_elapse);
487 pa_timespec_add(&p->next_elapse, usec);
488 p->timer_enabled = 1;
489
490 update_timer(p);
491 }
492
493 void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
494 pa_assert(p);
495
496 p->period = 0;
497 pa_rtclock_get(&p->next_elapse);
498 pa_timespec_add(&p->next_elapse, usec);
499 p->timer_enabled = 1;
500
501 update_timer(p);
502 }
503
504 void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
505 pa_assert(p);
506
507 p->period = 0;
508 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
509 p->timer_enabled = 0;
510
511 update_timer(p);
512 }
513
514 pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {
515 pa_rtpoll_item *i, *j, *l = NULL;
516
517 pa_assert(p);
518
519 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
520 i = pa_xnew(pa_rtpoll_item, 1);
521
522 i->rtpoll = p;
523 i->dead = 0;
524 i->n_pollfd = n_fds;
525 i->pollfd = NULL;
526 i->priority = prio;
527
528 i->userdata = NULL;
529 i->before_cb = NULL;
530 i->after_cb = NULL;
531
532 for (j = p->items; j; j = j->next) {
533 if (prio <= j->priority)
534 break;
535
536 l = j;
537 }
538
539 PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i);
540
541 if (n_fds > 0) {
542 p->rebuild_needed = 1;
543 p->n_pollfd_used += n_fds;
544 }
545
546 return i;
547 }
548
549 void pa_rtpoll_item_free(pa_rtpoll_item *i) {
550 pa_assert(i);
551
552 if (i->rtpoll->running) {
553 i->dead = 1;
554 i->rtpoll->scan_for_dead = 1;
555 return;
556 }
557
558 rtpoll_item_destroy(i);
559 }
560
561 struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
562 pa_assert(i);
563
564 if (i->n_pollfd > 0)
565 if (i->rtpoll->rebuild_needed)
566 rtpoll_rebuild(i->rtpoll);
567
568 if (n_fds)
569 *n_fds = i->n_pollfd;
570
571 return i->pollfd;
572 }
573
574 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)) {
575 pa_assert(i);
576 pa_assert(i->priority < PA_RTPOLL_NEVER);
577
578 i->before_cb = before_cb;
579 }
580
581 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i)) {
582 pa_assert(i);
583 pa_assert(i->priority < PA_RTPOLL_NEVER);
584
585 i->after_cb = after_cb;
586 }
587
588 void pa_rtpoll_item_set_userdata(pa_rtpoll_item *i, void *userdata) {
589 pa_assert(i);
590
591 i->userdata = userdata;
592 }
593
594 void* pa_rtpoll_item_get_userdata(pa_rtpoll_item *i) {
595 pa_assert(i);
596
597 return i->userdata;
598 }
599
600 static int fdsem_before(pa_rtpoll_item *i) {
601
602 if (pa_fdsem_before_poll(i->userdata) < 0)
603 return 1; /* 1 means immediate restart of the loop */
604
605 return 0;
606 }
607
608 static void fdsem_after(pa_rtpoll_item *i) {
609 pa_assert(i);
610
611 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
612 pa_fdsem_after_poll(i->userdata);
613 }
614
615 pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) {
616 pa_rtpoll_item *i;
617 struct pollfd *pollfd;
618
619 pa_assert(p);
620 pa_assert(f);
621
622 i = pa_rtpoll_item_new(p, prio, 1);
623
624 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
625
626 pollfd->fd = pa_fdsem_get(f);
627 pollfd->events = POLLIN;
628
629 i->before_cb = fdsem_before;
630 i->after_cb = fdsem_after;
631 i->userdata = f;
632
633 return i;
634 }
635
636 static int asyncmsgq_before(pa_rtpoll_item *i) {
637 pa_assert(i);
638
639 if (pa_asyncmsgq_before_poll(i->userdata) < 0)
640 return 1; /* 1 means immediate restart of the loop */
641
642 return 0;
643 }
644
645 static void asyncmsgq_after(pa_rtpoll_item *i) {
646 pa_assert(i);
647
648 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
649 pa_asyncmsgq_after_poll(i->userdata);
650 }
651
652 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
653 pa_rtpoll_item *i;
654 struct pollfd *pollfd;
655
656 pa_assert(p);
657 pa_assert(q);
658
659 i = pa_rtpoll_item_new(p, prio, 1);
660
661 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
662 pollfd->fd = pa_asyncmsgq_get_fd(q);
663 pollfd->events = POLLIN;
664
665 i->before_cb = asyncmsgq_before;
666 i->after_cb = asyncmsgq_after;
667 i->userdata = q;
668
669 return i;
670 }