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