Commit ed7d5b92 authored by william's avatar william

refactor API, moving struct timeout to header, renaming some routines, and adding others

parent 917958e3
...@@ -33,11 +33,10 @@ ...@@ -33,11 +33,10 @@
#include <sys/queue.h> #include <sys/queue.h>
#include "timer.h" #include "timer.h"
#include "debug.h"
#define abstime_t timeout_t /* for documentation purposes */ #if TIMER_DEBUG - 0 || TIMER_MAIN - 0
#define reltime_t timeout_t /* "" */ #include "debug.h"
#endif
/* /*
...@@ -45,6 +44,9 @@ ...@@ -45,6 +44,9 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define abstime_t timeout_t /* for documentation purposes */
#define reltime_t timeout_t /* "" */
#if !defined countof #if !defined countof
#define countof(a) (sizeof (a) / sizeof *(a)) #define countof(a) (sizeof (a) / sizeof *(a))
#endif #endif
...@@ -181,39 +183,12 @@ static inline wheel_t rotr(const wheel_t v, int c) { ...@@ -181,39 +183,12 @@ static inline wheel_t rotr(const wheel_t v, int c) {
/* /*
* T I M E O U T R O U T I N E S * T I M E R R O U T I N E S
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
TAILQ_HEAD(timeout_list, timeout); TAILQ_HEAD(timeout_list, timeout);
#define TIMEOUT_INITIALIZER { 0, 0, { 0, 0 } }
struct timeout {
int flags;
timeout_t expires;
struct timeout_list *pending;
TAILQ_ENTRY(timeout) tqe;
}; /* struct timeout */
struct timeout *timeout_init(struct timeout *to, int flags) {
memset(to, 0, sizeof *to);
to->flags = flags;
return to;
} /* timeout_init() */
/*
* T I M E R R O U T I N E S
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct timeouts { struct timeouts {
struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired; struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired;
...@@ -258,6 +233,7 @@ void timeouts_del(struct timeouts *T, struct timeout *to) { ...@@ -258,6 +233,7 @@ void timeouts_del(struct timeouts *T, struct timeout *to) {
TAILQ_REMOVE(to->pending, to, tqe); TAILQ_REMOVE(to->pending, to, tqe);
to->pending = NULL; to->pending = NULL;
to->timeouts = NULL;
} }
} /* timeouts_del() */ } /* timeouts_del() */
...@@ -277,7 +253,7 @@ static inline int timeout_slot(int wheel, timeout_t expires) { ...@@ -277,7 +253,7 @@ static inline int timeout_slot(int wheel, timeout_t expires) {
} /* timeout_slot() */ } /* timeout_slot() */
void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t expires) { static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t expires) {
timeout_t rem; timeout_t rem;
int wheel, slot; int wheel, slot;
...@@ -285,6 +261,8 @@ void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t expires) { ...@@ -285,6 +261,8 @@ void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t expires) {
to->expires = expires; to->expires = expires;
to->timeouts = T;
if (expires > T->curtime) { if (expires > T->curtime) {
rem = timeout_rem(T, to); rem = timeout_rem(T, to);
...@@ -299,10 +277,48 @@ void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t expires) { ...@@ -299,10 +277,48 @@ void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t expires) {
to->pending = &T->expired; to->pending = &T->expired;
TAILQ_INSERT_TAIL(to->pending, to, tqe); TAILQ_INSERT_TAIL(to->pending, to, tqe);
} }
} /* timeouts_sched() */
static void timeouts_readd(struct timeouts *T, struct timeout *to) {
to->expires += to->interval;
if (to->expires <= T->curtime) {
if (to->expires < T->curtime) {
timeout_t n = T->curtime - to->expires;
timeout_t q = n / to->interval;
timeout_t r = n % to->interval;
if (r)
to->expires += (to->interval * q) + (to->interval - r);
else
to->expires += (to->interval * q);
} else {
to->expires += to->interval;
}
}
timeouts_sched(T, to, to->expires);
} /* timeouts_readd() */
void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t timeout) {
if (to->flags & TIMEOUT_INT)
to->interval = MAX(1, timeout);
if (to->flags & TIMEOUT_ABS)
timeouts_sched(T, to, timeout);
else
timeouts_sched(T, to, T->curtime + timeout);
} /* timeouts_add() */ } /* timeouts_add() */
void timeouts_step(struct timeouts *T, abstime_t curtime) { void timeouts_addf(struct timeouts *T, struct timeout *to, double timeout) {
timeouts_add(T, to, timeout * T->hertz);
} /* timeouts_addf() */
void timeouts_update(struct timeouts *T, abstime_t curtime) {
timeout_t elapsed = curtime - T->curtime; timeout_t elapsed = curtime - T->curtime;
struct timeout_list todo; struct timeout_list todo;
int wheel; int wheel;
...@@ -360,10 +376,15 @@ void timeouts_step(struct timeouts *T, abstime_t curtime) { ...@@ -360,10 +376,15 @@ void timeouts_step(struct timeouts *T, abstime_t curtime) {
TAILQ_REMOVE(&todo, to, tqe); TAILQ_REMOVE(&todo, to, tqe);
to->pending = 0; to->pending = 0;
timeouts_add(T, to, to->expires); timeouts_sched(T, to, to->expires);
} }
return; return;
} /* timeouts_update() */
void timeouts_step(struct timeouts *T, reltime_t elapsed) {
timeouts_update(T, T->curtime + elapsed);
} /* timeouts_step() */ } /* timeouts_step() */
...@@ -385,7 +406,8 @@ bool timeouts_expired(struct timeouts *T) { ...@@ -385,7 +406,8 @@ bool timeouts_expired(struct timeouts *T) {
/* /*
* Calculate a minimum timeout value for timeouts pending on our wheels. * Calculate the interval before needing to process any timeouts pending on
* any wheel.
* *
* (This is separated from the public API routine so we can evaluate our * (This is separated from the public API routine so we can evaluate our
* wheel invariant assertions irrespective of the expired queue.) * wheel invariant assertions irrespective of the expired queue.)
...@@ -399,7 +421,7 @@ bool timeouts_expired(struct timeouts *T) { ...@@ -399,7 +421,7 @@ bool timeouts_expired(struct timeouts *T) {
* *
* We should never return a timeout larger than the lowest actual timeout. * We should never return a timeout larger than the lowest actual timeout.
*/ */
static timeout_t tms__timeout(struct timeouts *T) { static timeout_t timeouts_int(struct timeouts *T) {
timeout_t timeout = ~TIMEOUT_C(0), _timeout; timeout_t timeout = ~TIMEOUT_C(0), _timeout;
timeout_t relmask; timeout_t relmask;
int wheel, slot; int wheel, slot;
...@@ -424,22 +446,21 @@ static timeout_t tms__timeout(struct timeouts *T) { ...@@ -424,22 +446,21 @@ static timeout_t tms__timeout(struct timeouts *T) {
} }
return timeout; return timeout;
} /* tms__timeout() */ } /* timeouts_int() */
/* /*
* Calculate a timeout that our caller can wait before updating and * Calculate the interval our caller can wait before needing to process
* processing the wheel. * events.
*/ */
timeout_t timeouts_timeout(struct timeouts *T) { timeout_t timeouts_timeout(struct timeouts *T) {
if (!TAILQ_EMPTY(&T->expired)) if (!TAILQ_EMPTY(&T->expired))
return 0; return 0;
return tms__timeout(T); return timeouts_int(T);
} /* timeouts_timeout() */ } /* timeouts_timeout() */
struct timeout *timeouts_get(struct timeouts *T) { struct timeout *timeouts_get(struct timeouts *T) {
if (!TAILQ_EMPTY(&T->expired)) { if (!TAILQ_EMPTY(&T->expired)) {
struct timeout *to = TAILQ_FIRST(&T->expired); struct timeout *to = TAILQ_FIRST(&T->expired);
...@@ -447,6 +468,12 @@ struct timeout *timeouts_get(struct timeouts *T) { ...@@ -447,6 +468,12 @@ struct timeout *timeouts_get(struct timeouts *T) {
TAILQ_REMOVE(&T->expired, to, tqe); TAILQ_REMOVE(&T->expired, to, tqe);
to->pending = 0; to->pending = 0;
if ((to->flags & TIMEOUT_INT) && to->interval > 0) {
timeouts_readd(T, to);
} else {
to->timeouts = 0;
}
return to; return to;
} else { } else {
return 0; return 0;
...@@ -458,7 +485,7 @@ struct timeout *timeouts_get(struct timeouts *T) { ...@@ -458,7 +485,7 @@ struct timeout *timeouts_get(struct timeouts *T) {
* Use dumb looping to locate the earliest timeout pending on the wheel so * Use dumb looping to locate the earliest timeout pending on the wheel so
* our invariant assertions can check the result of our optimized code. * our invariant assertions can check the result of our optimized code.
*/ */
static struct timeout *tms__min(struct timeouts *T) { static struct timeout *timeouts_min(struct timeouts *T) {
struct timeout *to, *min = NULL; struct timeout *to, *min = NULL;
unsigned i, j; unsigned i, j;
...@@ -472,7 +499,7 @@ static struct timeout *tms__min(struct timeouts *T) { ...@@ -472,7 +499,7 @@ static struct timeout *tms__min(struct timeouts *T) {
} }
return min; return min;
} /* tms__min() */ } /* timeouts_min() */
/* /*
...@@ -495,10 +522,10 @@ bool timeouts_check(struct timeouts *T, FILE *fp) { ...@@ -495,10 +522,10 @@ bool timeouts_check(struct timeouts *T, FILE *fp) {
timeout_t timeout; timeout_t timeout;
struct timeout *to; struct timeout *to;
if ((to = tms__min(T))) { if ((to = timeouts_min(T))) {
check(to->expires > T->curtime, "missed timeout (expires:%" TIMEOUT_PRIu " <= curtime:%" TIMEOUT_PRIu ")\n", to->expires, T->curtime); check(to->expires > T->curtime, "missed timeout (expires:%" TIMEOUT_PRIu " <= curtime:%" TIMEOUT_PRIu ")\n", to->expires, T->curtime);
timeout = tms__timeout(T); timeout = timeouts_int(T);
check(timeout <= to->expires - T->curtime, "wrong soft timeout (soft:%" TIMEOUT_PRIu " > hard:%" TIMEOUT_PRIu ") (expires:%" TIMEOUT_PRIu "; curtime:%" TIMEOUT_PRIu ")\n", timeout, (to->expires - T->curtime), to->expires, T->curtime); check(timeout <= to->expires - T->curtime, "wrong soft timeout (soft:%" TIMEOUT_PRIu " > hard:%" TIMEOUT_PRIu ") (expires:%" TIMEOUT_PRIu "; curtime:%" TIMEOUT_PRIu ")\n", timeout, (to->expires - T->curtime), to->expires, T->curtime);
timeout = timeouts_timeout(T); timeout = timeouts_timeout(T);
...@@ -516,6 +543,35 @@ bool timeouts_check(struct timeouts *T, FILE *fp) { ...@@ -516,6 +543,35 @@ bool timeouts_check(struct timeouts *T, FILE *fp) {
} /* timeouts_check() */ } /* timeouts_check() */
/*
* T I M E O U T R O U T I N E S
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct timeout *timeout_init(struct timeout *to, int flags) {
memset(to, 0, sizeof *to);
to->flags = flags;
return to;
} /* timeout_init() */
bool timeout_pending(struct timeout *to) {
return to->pending && to->pending != &to->timeouts->expired;
} /* timeout_pending() */
bool timeout_expired(struct timeout *to) {
return to->pending && to->pending == &to->timeouts->expired;
} /* timeout_expired() */
void timeout_del(struct timeout *to) {
timeouts_del(to->timeouts, to);
} /* timeout_del() */
#if TIMER_MAIN - 0 #if TIMER_MAIN - 0
#include <stdio.h> #include <stdio.h>
...@@ -524,7 +580,7 @@ bool timeouts_check(struct timeouts *T, FILE *fp) { ...@@ -524,7 +580,7 @@ bool timeouts_check(struct timeouts *T, FILE *fp) {
static timeout_t slow_timeout(struct timeouts *T) { static timeout_t slow_timeout(struct timeouts *T) {
struct timeout *to = tms__min(T); struct timeout *to = timeouts_min(T);
return (to)? to->expires - T->curtime : 0; return (to)? to->expires - T->curtime : 0;
} /* slow_timeout() */ } /* slow_timeout() */
...@@ -569,15 +625,15 @@ int main(int argc, char **argv) { ...@@ -569,15 +625,15 @@ int main(int argc, char **argv) {
argv += optind; argv += optind;
timeouts_init(&T, TIMEOUT_mHZ); timeouts_init(&T, TIMEOUT_mHZ);
timeouts_step(&T, time); timeouts_update(&T, time);
timeouts_add(&T, timeout_init(&to[0], 0), time + 62); count++; timeouts_add(&T, timeout_init(&to[0], 0), 62); count++;
timeouts_add(&T, timeout_init(&to[1], 0), time + 63); count++; timeouts_add(&T, timeout_init(&to[1], 0), 63); count++;
timeouts_add(&T, timeout_init(&to[2], 0), time + 64); count++; timeouts_add(&T, timeout_init(&to[2], 0), 64); count++;
timeouts_add(&T, timeout_init(&to[3], 0), time + 65); count++; timeouts_add(&T, timeout_init(&to[3], 0), 65); count++;
timeouts_add(&T, timeout_init(&to[5], 0), time + 192); count++; timeouts_add(&T, timeout_init(&to[5], 0), 192); count++;
timeouts_add(&T, timeout_init(&to[6], 0), time + 6); count++; timeouts_add(&T, timeout_init(&to[6], 0), 6); count++;
timeouts_add(&T, timeout_init(&to[7], 0), time + 7); count++; timeouts_add(&T, timeout_init(&to[7], 0), 7); count++;
timeouts_add(&T, timeout_init(&to[8], 0), time + 8); count++; timeouts_add(&T, timeout_init(&to[8], 0), 8); count++;
while (count > 0 && time <= stop - 1) { while (count > 0 && time <= stop - 1) {
time += step; time += step;
...@@ -585,7 +641,7 @@ int main(int argc, char **argv) { ...@@ -585,7 +641,7 @@ int main(int argc, char **argv) {
SAY("timeout -> %" TIMEOUT_PRIu " (actual:%" TIMEOUT_PRIu " curtime:%" TIMEOUT_PRIu ")", timeouts_timeout(&T), slow_timeout(&T), T.curtime); SAY("timeout -> %" TIMEOUT_PRIu " (actual:%" TIMEOUT_PRIu " curtime:%" TIMEOUT_PRIu ")", timeouts_timeout(&T), slow_timeout(&T), T.curtime);
timeouts_check(&T, stderr); timeouts_check(&T, stderr);
timeouts_step(&T, time); timeouts_update(&T, time);
timeouts_check(&T, stderr); timeouts_check(&T, stderr);
while ((expired = timeouts_get(&T))) { while ((expired = timeouts_get(&T))) {
......
...@@ -27,11 +27,15 @@ ...@@ -27,11 +27,15 @@
#define TIMER_H #define TIMER_H
#include <stdbool.h> /* bool */ #include <stdbool.h> /* bool */
#include <stdio.h> /* FILE */
#include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */ #include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
#include <sys/queue.h> /* TAILQ(3) */
/* /*
* T I M I N G W H E E L I N T E R F A C E S * I N T E G E R T Y P E I N T E R F A C E S
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
...@@ -46,36 +50,107 @@ ...@@ -46,36 +50,107 @@
typedef uint64_t timeout_t; typedef uint64_t timeout_t;
struct timeouts;
struct timeout;
struct timeouts *timeouts_open(timeout_t); /*
* C A L L B A C K I N T E R F A C E
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void timeouts_close(struct timeouts *); struct timeout_cb {
void (*fn)();
void *arg;
}; /* struct timeout_cb */
void timeouts_add(struct timeouts *, struct timeout *, timeout_t);
void timeouts_del(struct timeouts *, struct timeout *); /*
* T I M E O U T I N T E R F A C E S
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool timeouts_pending(struct timeouts *); #define TIMEOUT_INT 0x01 /* interval (repeating) timeout */
#define TIMEOUT_ABS 0x02 /* treat timeout values as absolute */
timeout_t timeouts_timeout(struct timeouts *); #define TIMEOUT_INITIALIZER(flags) { (flags), 0, 0, 0, { 0, 0 } }
#define timeout_setcb(to, fn, arg) do { \
(to)->callback.fn = (fn); \
(to)->callback.arg = (arg); \
} while (0)
/* struct timeout {
* T I M E O U T C O N T E X T I N T E R F A C E S int flags;
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ timeout_t interval;
/* timeout interval if periodic */
timeout_t expires;
/* absolute expiration time */
struct timeouts *timeouts;
/* timeouts collection if member of */
struct timeout_list *pending;
/* timeout list if pending on wheel or expiry queue */
struct timeout_cb callback;
/* optional callback information */
TAILQ_ENTRY(timeout) tqe;
}; /* struct timeout */
#define TIMEOUT_PERIODIC 0x01
#define TIMEOUT_ABSTIME 0x02
struct timeout *timeout_init(struct timeout *, int); struct timeout *timeout_init(struct timeout *, int);
/* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
bool timeout_pending(struct timeout *); bool timeout_pending(struct timeout *);
/* true if on timing wheel or expired queue, false otherwise */ /* true if on timing wheel, false otherwise */
bool timeout_expired(struct timeout *); bool timeout_expired(struct timeout *);
/* true if on expired queue, false otherwise */ /* true if on expired queue, false otherwise */
void timeout_del(struct timeout *);
/* remove timeout from any timing wheel (okay if not member of any) */
/*
* T I M I N G W H E E L I N T E R F A C E S
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct timeouts;
struct timeouts *timeouts_open(timeout_t);
/* open a new timing wheel, setting optional HZ */
void timeouts_close(struct timeouts *);
/* destroy timing wheel */
void timeouts_update(struct timeouts *, timeout_t);
/* update timing wheel with current absolute time */
void timeouts_step(struct timeouts *, timeout_t);
/* step timing wheel by relative time */
timeout_t timeouts_timeout(struct timeouts *);
/* return interval to next required update */
void timeouts_add(struct timeouts *, struct timeout *, timeout_t);
/* add timeout to timing wheel */
void timeouts_addf(struct timeouts *, struct timeout *, double);
/* add timeout to timing wheel, translating floating point timeout */
void timeouts_del(struct timeouts *, struct timeout *);
/* remove timeout from any timing wheel or expired queue (okay if on neither) */
bool timeouts_pending(struct timeouts *);
/* return true if any timeouts pending on timing wheel */
bool timeouts_expired(struct timeouts *);
/* return true if any timeouts on expired queue */
bool timeouts_check(struct timeouts *, FILE *);
/* return true if invariants hold. describes failures to optional file handle. */
#endif /* TIMER_H */ #endif /* TIMER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment