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 <dh.herrmann@googlemail.com>
This commit is contained in:
parent
0cf2f8efbd
commit
d3a0358797
88
src/eloop.c
88
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.
|
* 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)
|
static void timer_cb(struct ev_fd *fd, int mask, void *data)
|
||||||
{
|
{
|
||||||
struct ev_timer *timer = data;
|
struct ev_timer *timer = data;
|
||||||
uint64_t expirations;
|
uint64_t expirations;
|
||||||
int len;
|
int ret;
|
||||||
|
|
||||||
if (mask & (EV_HUP | EV_ERR)) {
|
if (mask & (EV_HUP | EV_ERR)) {
|
||||||
llog_warn(fd, "HUP/ERR on timer source");
|
llog_warn(fd, "HUP/ERR on timer source");
|
||||||
if (timer->cb)
|
goto err_cb;
|
||||||
timer->cb(timer, 0, timer->data);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & EV_READABLE) {
|
if (mask & EV_READABLE) {
|
||||||
len = read(timer->fd, &expirations, sizeof(expirations));
|
ret = timer_drain(timer, &expirations);
|
||||||
if (len < 0) {
|
if (ret)
|
||||||
if (errno != EAGAIN) {
|
goto err_cb;
|
||||||
llog_warning(fd, "cannot read timerfd (%d): %m",
|
if (expirations > 0) {
|
||||||
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) {
|
|
||||||
if (timer->cb)
|
if (timer->cb)
|
||||||
timer->cb(timer, expirations, timer->data);
|
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;
|
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:
|
* ev_eloop_new_timer:
|
||||||
* @loop: event loop
|
* @loop: event loop
|
||||||
|
@ -190,6 +190,7 @@ bool ev_timer_is_enabled(struct ev_timer *timer);
|
|||||||
bool ev_timer_is_bound(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);
|
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_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,
|
int ev_eloop_new_timer(struct ev_eloop *loop, struct ev_timer **out,
|
||||||
const struct itimerspec *spec, ev_timer_cb cb,
|
const struct itimerspec *spec, ev_timer_cb cb,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user