From b76ab9dd5e8b2d7c947d0130de0f34e794fc941b Mon Sep 17 00:00:00 2001 From: Chris Murphy Date: Wed, 22 Apr 2020 13:17:11 -0400 Subject: [PATCH] master: Issue 390: Clarify documentation of qb_loop_timer_expire_time_get and provide new function to return previously documented behavior --- include/qb/qbloop.h | 15 +++++++++++-- lib/loop_timerlist.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/qb/qbloop.h b/include/qb/qbloop.h index db0c480d4..c9b1993d1 100644 --- a/include/qb/qbloop.h +++ b/include/qb/qbloop.h @@ -187,16 +187,27 @@ int32_t qb_loop_timer_del(qb_loop_t *l, qb_loop_timer_handle th); int32_t qb_loop_timer_is_running(qb_loop_t *l, qb_loop_timer_handle th); /** - * Get the time remaining before it expires. + * Get the expiration time of the timer, as set when the timer was created * * @note if the timer has already expired it will return 0 * * @param l pointer to the loop instance * @param th timer handle. - * @return nano seconds left + * @return nano seconds at which the timer will expire */ uint64_t qb_loop_timer_expire_time_get(struct qb_loop *l, qb_loop_timer_handle th); +/** + * Get the time remaining before the timer expires + * + * @note if the timer has already expired it will return 0 + * + * @param l pointer to the loop instance + * @param th timer handle. + * @return nano seconds remaining until the timer expires + */ +uint64_t qb_loop_timer_expire_time_remaining(struct qb_loop *l, qb_loop_timer_handle th); + /** * Set a callback to receive events on file descriptors * getting low. diff --git a/lib/loop_timerlist.c b/lib/loop_timerlist.c index 4102ea3d4..e5e3ae831 100644 --- a/lib/loop_timerlist.c +++ b/lib/loop_timerlist.c @@ -286,6 +286,56 @@ qb_loop_timer_expire_time_get(struct qb_loop * lp, qb_loop_timer_handle th) return timerlist_expire_time(&s->timerlist, t->timerlist_handle); } +uint64_t +qb_loop_timer_expire_time_remaining(struct qb_loop * lp, qb_loop_timer_handle th) +{ + + uint64_t current_ns; + /* NOTE: while it does not appear that absolute timers are used anywhere, + * we may as well respect this pattern in case that changes. + * Unfortunately, that means we do need to repeat timer fetch code from qb_loop_timer_expire_time_get + * rather than just a simple call to qb_loop_timer_expire_time_get and qb_util_nano_current_get. + */ + + struct qb_timer_source *s; + struct qb_loop_timer *t; + int32_t res; + struct qb_loop *l = lp; + + if (l == NULL) { + l = qb_loop_default_get(); + } + s = (struct qb_timer_source *)l->timer_source; + + res = _timer_from_handle_(s, th, &t); + if (res != 0) { + return 0; + } + + struct timerlist_timer *timer = (struct timerlist_timer *)t->timerlist_handle; + + + if (timer->is_absolute_timer) { + current_ns = qb_util_nano_from_epoch_get(); + } + else { + current_ns = qb_util_nano_current_get(); + } + uint64_t timer_ns = timerlist_expire_time(&s->timerlist, t->timerlist_handle); + /* since time estimation is racy by nature, I'll try to check the state late, + * and try to understand that no matter what, the timer might have expired in the mean time + */ + if (t->state != QB_POLL_ENTRY_ACTIVE) { + return 0; + } + if (timer_ns < current_ns) { + return 0; // respect the "expired" contract + } + return timer_ns - current_ns; + + +} + int32_t qb_loop_timer_is_running(qb_loop_t *l, qb_loop_timer_handle th) {