From d3a0358797b8de742bcafb96bad4857bd140077c Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 18 Sep 2012 16:24:06 +0200 Subject: [PATCH] eloop: add ev_timer_drain() helper This helper reads the current expiration-count from a timer. This can be used when waking up from an idle-period or similar to reset the timer. Signed-off-by: David Herrmann --- src/eloop.c | 88 ++++++++++++++++++++++++++++++++++++++--------------- src/eloop.h | 1 + 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/src/eloop.c b/src/eloop.c index daf24b6..c097292 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -1443,44 +1443,63 @@ void ev_eloop_rm_fd(struct ev_fd *fd) * real precision depends on the operating-system and hardware. */ +static int timer_drain(struct ev_timer *timer, uint64_t *out) +{ + int len; + uint64_t expirations; + + if (out) + *out = 0; + + len = read(timer->fd, &expirations, sizeof(expirations)); + if (len < 0) { + if (errno == EAGAIN) { + return 0; + } else { + llog_warning(timer, "cannot read timerfd (%d): %m", + errno); + return errno; + } + } else if (len == 0) { + llog_warning(timer, "EOF on timer source"); + return -EFAULT; + } else if (len != sizeof(expirations)) { + llog_warn(timer, "invalid size %d read on timerfd", len); + return -EFAULT; + } else { + if (out) + *out = expirations; + return 0; + } +} + static void timer_cb(struct ev_fd *fd, int mask, void *data) { struct ev_timer *timer = data; uint64_t expirations; - int len; + int ret; if (mask & (EV_HUP | EV_ERR)) { llog_warn(fd, "HUP/ERR on timer source"); - if (timer->cb) - timer->cb(timer, 0, timer->data); - return; + goto err_cb; } if (mask & EV_READABLE) { - len = read(timer->fd, &expirations, sizeof(expirations)); - if (len < 0) { - if (errno != EAGAIN) { - llog_warning(fd, "cannot read timerfd (%d): %m", - errno); - ev_timer_disable(timer); - if (timer->cb) - timer->cb(timer, 0, timer->data); - } - } else if (len == 0) { - llog_warning(fd, "EOF on timer source"); - ev_timer_disable(timer); - if (timer->cb) - timer->cb(timer, 0, timer->data); - } else if (len != sizeof(expirations)) { - llog_warn(fd, "invalid size %d read on timerfd", len); - ev_timer_disable(timer); - if (timer->cb) - timer->cb(timer, 0, timer->data); - } else if (expirations > 0) { + ret = timer_drain(timer, &expirations); + if (ret) + goto err_cb; + if (expirations > 0) { if (timer->cb) timer->cb(timer, expirations, timer->data); } } + + return; + +err_cb: + ev_timer_disable(timer); + if (timer->cb) + timer->cb(timer, 0, timer->data); } /** @@ -1687,6 +1706,27 @@ int ev_timer_update(struct ev_timer *timer, const struct itimerspec *spec) return 0; } +/** + * ev_timer_drain: + * @timer: valid timer object + * @expirations: destination to save result or NULL + * + * This reads the current expiration-count from the timer object @timer and + * saves it in @expirations (if it is non-NULL). This can be used to clear the + * timer after an idle-period or similar. + * Note that the timer_cb() callback function automatically calls this before + * calling the user-supplied callback. + * + * Returns: 0 on success, negative error code on failure. + */ +int ev_timer_drain(struct ev_timer *timer, uint64_t *expirations) +{ + if (!timer) + return -EINVAL; + + return timer_drain(timer, expirations); +} + /** * ev_eloop_new_timer: * @loop: event loop diff --git a/src/eloop.h b/src/eloop.h index 91aa3a5..c7d21f2 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -190,6 +190,7 @@ bool ev_timer_is_enabled(struct ev_timer *timer); bool ev_timer_is_bound(struct ev_timer *timer); void ev_timer_set_cb_data(struct ev_timer *timer, ev_timer_cb cb, void *data); int ev_timer_update(struct ev_timer *timer, const struct itimerspec *spec); +int ev_timer_drain(struct ev_timer *timer, uint64_t *expirations); int ev_eloop_new_timer(struct ev_eloop *loop, struct ev_timer **out, const struct itimerspec *spec, ev_timer_cb cb,