From 0ff2afd8a65517c6f0458dc936108bd64ad9afa1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Aug 2007 22:26:30 +0000 Subject: [PATCH] support absolute, relative and periodic timers in pa_rtpoll git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1703 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/rtpoll.c | 108 +++++++++++++++++++++++++++++++++++++++++------- src/pulsecore/rtpoll.h | 10 ++++- src/tests/rtpoll-test.c | 2 +- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c index 4f39c68..0f09c7d 100644 --- a/src/pulsecore/rtpoll.c +++ b/src/pulsecore/rtpoll.c @@ -49,7 +49,9 @@ struct pa_rtpoll { struct pollfd *pollfd, *pollfd2; unsigned n_pollfd_alloc, n_pollfd_used; - pa_usec_t interval; + int timer_enabled; + struct timespec next_elapse; + pa_usec_t period; int scan_for_dead; int running, installed, rebuild_needed; @@ -57,7 +59,6 @@ struct pa_rtpoll { #ifdef HAVE_PPOLL int rtsig; sigset_t sigset_unblocked; - struct timespec interval_timespec; timer_t timer; #ifdef __linux__ int dont_use_ppoll; @@ -115,7 +116,6 @@ pa_rtpoll *pa_rtpoll_new(void) { p->rtsig = -1; sigemptyset(&p->sigset_unblocked); - memset(&p->interval_timespec, 0, sizeof(p->interval_timespec)); p->timer = (timer_t) -1; #endif @@ -125,7 +125,9 @@ pa_rtpoll *pa_rtpoll_new(void) { p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc); p->n_pollfd_used = 0; - p->interval = 0; + p->period = 0; + memset(&p->next_elapse, 0, sizeof(p->next_elapse)); + p->timer_enabled = 0; p->running = 0; p->installed = 0; @@ -260,6 +262,7 @@ int pa_rtpoll_run(pa_rtpoll *p) { int r = 0; int no_events = 0; int saved_errno; + struct timespec timeout; pa_assert(p); pa_assert(!p->running); @@ -296,6 +299,17 @@ int pa_rtpoll_run(pa_rtpoll *p) { if (p->rebuild_needed) rtpoll_rebuild(p); + + /* Calculate timeout */ + if (p->timer_enabled) { + struct timespec now; + pa_rtclock_get(&now); + + if (pa_timespec_cmp(&p->next_elapse, &now) <= 0) + memset(&timeout, 0, sizeof(timeout)); + else + pa_timespec_store(&timeout, pa_timespec_diff(&p->next_elapse, &now)); + } /* OK, now let's sleep */ #ifdef HAVE_PPOLL @@ -303,18 +317,33 @@ int pa_rtpoll_run(pa_rtpoll *p) { #ifdef __linux__ if (!p->dont_use_ppoll) #endif - r = ppoll(p->pollfd, p->n_pollfd_used, p->interval > 0 ? &p->interval_timespec : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked); + r = ppoll(p->pollfd, p->n_pollfd_used, p->timer_enabled > 0 ? &timeout : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked); #ifdef __linux__ else #endif #else - r = poll(p->pollfd, p->n_pollfd_used, p->interval > 0 ? p->interval / 1000 : -1); + r = poll(p->pollfd, p->n_pollfd_used, p->timer_enabled > 0 ? (timeout.tv_sec*1000) + (timeout.tv_nsec / 1000000) : -1); #endif saved_errno = errno; + + if (p->timer_enabled) { + if (p->period > 0) { + struct timespec now; + pa_rtclock_get(&now); + + pa_timespec_add(&p->next_elapse, p->period); + + /* Guarantee that the next timeout will happen in the future */ + if (pa_timespec_cmp(&p->next_elapse, &now) < 0) + pa_timespec_add(&p->next_elapse, (pa_timespec_diff(&now, &p->next_elapse) / p->period + 1) * p->period); + + } else + p->timer_enabled = 0; + } - if (r < 0 && (errno == EAGAIN || errno == EINTR)) { + if (r == 0 || (r < 0 && (errno == EAGAIN || errno == EINTR))) { r = 0; no_events = 1; } @@ -359,13 +388,10 @@ finish: return r; } -void pa_rtpoll_set_itimer(pa_rtpoll *p, pa_usec_t usec) { +static void update_timer(pa_rtpoll *p) { pa_assert(p); - p->interval = usec; - #ifdef HAVE_PPOLL - pa_timespec_store(&p->interval_timespec, usec); #ifdef __linux__ if (!p->dont_use_ppoll) { @@ -387,12 +413,21 @@ void pa_rtpoll_set_itimer(pa_rtpoll *p, pa_usec_t usec) { if (p->timer != (timer_t) -1) { struct itimerspec its; - memset(&its, 0, sizeof(its)); - pa_timespec_store(&its.it_value, usec); - pa_timespec_store(&its.it_interval, usec); - assert(timer_settime(p->timer, 0, &its, NULL) == 0); + if (p->timer_enabled) { + its.it_value = p->next_elapse; + + /* Make sure that 0,0 is not understood as + * "disarming" */ + if (its.it_value.tv_sec == 0) + its.it_value.tv_nsec = 1; + + if (p->period > 0) + pa_timespec_store(&its.it_interval, p->period); + } + + pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0); } #ifdef __linux__ @@ -402,6 +437,49 @@ void pa_rtpoll_set_itimer(pa_rtpoll *p, pa_usec_t usec) { #endif } +void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timespec *ts) { + pa_assert(p); + pa_assert(ts); + + p->next_elapse = *ts; + p->period = 0; + p->timer_enabled = 1; + + update_timer(p); +} + +void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec) { + pa_assert(p); + + p->period = usec; + pa_rtclock_get(&p->next_elapse); + pa_timespec_add(&p->next_elapse, usec); + p->timer_enabled = 1; + + update_timer(p); +} + +void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) { + pa_assert(p); + + p->period = 0; + pa_rtclock_get(&p->next_elapse); + pa_timespec_add(&p->next_elapse, usec); + p->timer_enabled = 1; + + update_timer(p); +} + +void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) { + pa_assert(p); + + p->period = 0; + memset(&p->next_elapse, 0, sizeof(p->next_elapse)); + p->timer_enabled = 0; + + update_timer(p); +} + pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, unsigned n_fds) { pa_rtpoll_item *i; diff --git a/src/pulsecore/rtpoll.h b/src/pulsecore/rtpoll.h index bed3ae3..7fe5cb3 100644 --- a/src/pulsecore/rtpoll.h +++ b/src/pulsecore/rtpoll.h @@ -59,11 +59,18 @@ void pa_rtpoll_free(pa_rtpoll *p); void pa_rtpoll_install(pa_rtpoll *p); int pa_rtpoll_run(pa_rtpoll *f); -void pa_rtpoll_set_itimer(pa_rtpoll *p, pa_usec_t usec); + +void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timespec *ts); +void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec); +void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec); +void pa_rtpoll_set_timer_disabled(pa_rtpoll *p); pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, unsigned n_fds); void pa_rtpoll_item_free(pa_rtpoll_item *i); +/* Please note that this pointer might change on every call and when + * pa_rtpoll_run() is called. Hence: call this immediately before + * using the pointer and don't save the result anywhere */ struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds); void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)); @@ -74,5 +81,4 @@ void* pa_rtpoll_item_get_userdata(pa_rtpoll_item *i); pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_fdsem *s); pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq(pa_rtpoll *p, pa_asyncmsgq *q); - #endif diff --git a/src/tests/rtpoll-test.c b/src/tests/rtpoll-test.c index 29f2e92..2a90684 100644 --- a/src/tests/rtpoll-test.c +++ b/src/tests/rtpoll-test.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { pollfd->events = POLLIN; pa_rtpoll_install(p); - pa_rtpoll_set_itimer(p, 10000000); /* 10 s */ + pa_rtpoll_set_timer_periodic(p, 10000000); /* 10 s */ pa_rtpoll_run(p); -- 2.7.4