2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
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 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
30 #include <pulse/xmalloc.h>
31 #include <pulse/timeval.h>
33 #include <pulsecore/poll.h>
34 #include <pulsecore/core-error.h>
35 #include <pulsecore/core-rtclock.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/llist.h>
38 #include <pulsecore/flist.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/ratelimit.h>
41 #include <pulse/rtclock.h>
45 /* #define DEBUG_TIMING */
48 struct pollfd *pollfd, *pollfd2;
49 unsigned n_pollfd_alloc, n_pollfd_used;
51 struct timeval next_elapse;
56 bool rebuild_needed:1;
62 pa_usec_t slept, awake;
65 PA_LLIST_HEAD(pa_rtpoll_item, items);
68 struct pa_rtpoll_item {
72 pa_rtpoll_priority_t priority;
74 struct pollfd *pollfd;
77 int (*work_cb)(pa_rtpoll_item *i);
78 int (*before_cb)(pa_rtpoll_item *i);
79 void (*after_cb)(pa_rtpoll_item *i);
81 void *before_userdata;
84 PA_LLIST_FIELDS(pa_rtpoll_item);
87 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
89 pa_rtpoll *pa_rtpoll_new(void) {
92 p = pa_xnew0(pa_rtpoll, 1);
94 p->n_pollfd_alloc = 32;
95 p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
96 p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
99 p->timestamp = pa_rtclock_now();
105 static void rtpoll_rebuild(pa_rtpoll *p) {
107 struct pollfd *e, *t;
113 p->rebuild_needed = false;
115 if (p->n_pollfd_used > p->n_pollfd_alloc) {
116 /* Hmm, we have to allocate some more space */
117 p->n_pollfd_alloc = p->n_pollfd_used * 2;
118 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
124 for (i = p->items; i; i = i->next) {
126 if (i->n_pollfd > 0) {
127 size_t l = i->n_pollfd * sizeof(struct pollfd);
130 memcpy(e, i->pollfd, l);
141 pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used);
143 p->pollfd = p->pollfd2;
147 p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
150 static void rtpoll_item_destroy(pa_rtpoll_item *i) {
157 PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i);
159 p->n_pollfd_used -= i->n_pollfd;
161 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
164 p->rebuild_needed = true;
167 void pa_rtpoll_free(pa_rtpoll *p) {
171 rtpoll_item_destroy(p->items);
174 pa_xfree(p->pollfd2);
179 static void reset_revents(pa_rtpoll_item *i) {
185 if (!(f = pa_rtpoll_item_get_pollfd(i, &n)))
192 static void reset_all_revents(pa_rtpoll *p) {
197 for (i = p->items; i; i = i->next) {
206 int pa_rtpoll_run(pa_rtpoll *p) {
209 struct timeval timeout;
212 pa_assert(!p->running);
215 pa_log("rtpoll_run");
219 p->timer_elapsed = false;
221 /* First, let's do some work */
222 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
233 pa_log("rtpoll finish");
238 if ((k = i->work_cb(i)) != 0) {
242 pa_log("rtpoll finish");
248 /* Now let's prepare for entering the sleep */
249 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
258 if (p->quit || (k = i->before_cb(i)) != 0) {
260 /* Hmm, this one doesn't let us enter the poll, so rewind everything */
262 for (i = i->prev; i; i = i->prev) {
276 pa_log("rtpoll finish");
282 if (p->rebuild_needed)
287 /* Calculate timeout */
288 if (!p->quit && p->timer_enabled) {
290 pa_rtclock_get(&now);
292 if (pa_timeval_cmp(&p->next_elapse, &now) > 0)
293 pa_timeval_add(&timeout, pa_timeval_diff(&p->next_elapse, &now));
298 pa_usec_t now = pa_rtclock_now();
299 p->awake = now - p->timestamp;
301 if (!p->quit && p->timer_enabled)
302 pa_log("poll timeout: %d ms ",(int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)));
304 pa_log("poll timeout is ZERO");
306 pa_log("poll timeout is FOREVER");
310 /* OK, now let's sleep */
314 ts.tv_sec = timeout.tv_sec;
315 ts.tv_nsec = timeout.tv_usec * 1000;
316 r = ppoll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? &ts : NULL, NULL);
319 r = pa_poll(p->pollfd, p->n_pollfd_used, (p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1);
322 p->timer_elapsed = r == 0;
326 pa_usec_t now = pa_rtclock_now();
327 p->slept = now - p->timestamp;
330 pa_log("Process time %llu ms; sleep time %llu ms",
331 (unsigned long long) (p->awake / PA_USEC_PER_MSEC),
332 (unsigned long long) (p->slept / PA_USEC_PER_MSEC));
337 if (errno == EAGAIN || errno == EINTR)
340 pa_log_error("poll(): %s", pa_cstrerror(errno));
342 reset_all_revents(p);
345 /* Let's tell everyone that we left the sleep */
346 for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) {
361 if (p->scan_for_dead) {
364 p->scan_for_dead = false;
366 for (i = p->items; i; i = n) {
370 rtpoll_item_destroy(i);
374 return r < 0 ? r : !p->quit;
377 void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
380 pa_timeval_store(&p->next_elapse, usec);
381 p->timer_enabled = true;
384 void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
387 /* Scheduling a timeout for more than an hour is very very suspicious */
388 pa_assert(usec <= PA_USEC_PER_SEC*60ULL*60ULL);
390 pa_rtclock_get(&p->next_elapse);
391 pa_timeval_add(&p->next_elapse, usec);
392 p->timer_enabled = true;
395 void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
398 memset(&p->next_elapse, 0, sizeof(p->next_elapse));
399 p->timer_enabled = false;
402 pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {
403 pa_rtpoll_item *i, *j, *l = NULL;
407 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
408 i = pa_xnew(pa_rtpoll_item, 1);
416 i->work_userdata = NULL;
417 i->before_userdata = NULL;
418 i->work_userdata = NULL;
423 for (j = p->items; j; j = j->next) {
424 if (prio <= j->priority)
430 PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i);
433 p->rebuild_needed = 1;
434 p->n_pollfd_used += n_fds;
440 void pa_rtpoll_item_free(pa_rtpoll_item *i) {
443 if (i->rtpoll->running) {
445 i->rtpoll->scan_for_dead = true;
449 rtpoll_item_destroy(i);
452 struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) {
456 if (i->rtpoll->rebuild_needed)
457 rtpoll_rebuild(i->rtpoll);
460 *n_fds = i->n_pollfd;
465 void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i), void *userdata) {
467 pa_assert(i->priority < PA_RTPOLL_NEVER);
469 i->before_cb = before_cb;
470 i->before_userdata = userdata;
473 void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i), void *userdata) {
475 pa_assert(i->priority < PA_RTPOLL_NEVER);
477 i->after_cb = after_cb;
478 i->after_userdata = userdata;
481 void pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i), void *userdata) {
483 pa_assert(i->priority < PA_RTPOLL_NEVER);
485 i->work_cb = work_cb;
486 i->work_userdata = userdata;
489 void* pa_rtpoll_item_get_work_userdata(pa_rtpoll_item *i) {
492 return i->work_userdata;
495 static int fdsem_before(pa_rtpoll_item *i) {
497 if (pa_fdsem_before_poll(i->before_userdata) < 0)
498 return 1; /* 1 means immediate restart of the loop */
503 static void fdsem_after(pa_rtpoll_item *i) {
506 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
507 pa_fdsem_after_poll(i->after_userdata);
510 pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) {
512 struct pollfd *pollfd;
517 i = pa_rtpoll_item_new(p, prio, 1);
519 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
521 pollfd->fd = pa_fdsem_get(f);
522 pollfd->events = POLLIN;
524 pa_rtpoll_item_set_before_callback(i, fdsem_before, f);
525 pa_rtpoll_item_set_after_callback(i, fdsem_after, f);
530 static int asyncmsgq_read_before(pa_rtpoll_item *i) {
533 if (pa_asyncmsgq_read_before_poll(i->before_userdata) < 0)
534 return 1; /* 1 means immediate restart of the loop */
539 static void asyncmsgq_read_after(pa_rtpoll_item *i) {
542 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
543 pa_asyncmsgq_read_after_poll(i->after_userdata);
546 static int asyncmsgq_read_work(pa_rtpoll_item *i) {
547 pa_msgobject *object;
555 if (pa_asyncmsgq_get(i->work_userdata, &object, &code, &data, &offset, &chunk, 0) == 0) {
558 if (!object && code == PA_MESSAGE_SHUTDOWN) {
559 pa_asyncmsgq_done(i->work_userdata, 0);
560 /* Requests the loop to exit. Will cause the next iteration of
561 * pa_rtpoll_run() to return 0 */
562 i->rtpoll->quit = true;
566 ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
567 pa_asyncmsgq_done(i->work_userdata, ret);
574 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_read(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
576 struct pollfd *pollfd;
581 i = pa_rtpoll_item_new(p, prio, 1);
583 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
584 pollfd->fd = pa_asyncmsgq_read_fd(q);
585 pollfd->events = POLLIN;
587 pa_rtpoll_item_set_before_callback(i, asyncmsgq_read_before, q);
588 pa_rtpoll_item_set_after_callback(i, asyncmsgq_read_after, q);
589 pa_rtpoll_item_set_work_callback(i, asyncmsgq_read_work, q);
594 static int asyncmsgq_write_before(pa_rtpoll_item *i) {
597 pa_asyncmsgq_write_before_poll(i->before_userdata);
601 static void asyncmsgq_write_after(pa_rtpoll_item *i) {
604 pa_assert((i->pollfd[0].revents & ~POLLIN) == 0);
605 pa_asyncmsgq_write_after_poll(i->after_userdata);
608 pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq_write(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) {
610 struct pollfd *pollfd;
615 i = pa_rtpoll_item_new(p, prio, 1);
617 pollfd = pa_rtpoll_item_get_pollfd(i, NULL);
618 pollfd->fd = pa_asyncmsgq_write_fd(q);
619 pollfd->events = POLLIN;
621 pa_rtpoll_item_set_before_callback(i, asyncmsgq_write_before, q);
622 pa_rtpoll_item_set_after_callback(i, asyncmsgq_write_after, q);
627 bool pa_rtpoll_timer_elapsed(pa_rtpoll *p) {
630 return p->timer_elapsed;