diff options
| author | William Ahern <[email protected]> | 2016-02-24 09:00:10 -0800 |
|---|---|---|
| committer | William Ahern <[email protected]> | 2016-02-24 09:00:10 -0800 |
| commit | 28738799e03588a9446a8f49fd6fe786ea6132ef (patch) | |
| tree | 3e3ab43afd9aad547677d9b713ccb38656c21e42 | |
| parent | 3e5568cd440fa43cd6973c1f7e4a2fa160420845 (diff) | |
reimplement foreach operation without callbacks
| -rw-r--r-- | bench-wheel.c | 6 | ||||
| -rw-r--r-- | bench.c | 38 | ||||
| -rw-r--r-- | bench.h | 1 | ||||
| -rw-r--r-- | timeout.c | 78 | ||||
| -rw-r--r-- | timeout.h | 32 |
5 files changed, 131 insertions, 24 deletions
diff --git a/bench-wheel.c b/bench-wheel.c index 3089140..cef80f8 100644 --- a/bench-wheel.c +++ b/bench-wheel.c @@ -57,6 +57,11 @@ static int empty(void *T) { } /* empty() */ +static struct timeout *next(void *T, struct timeouts_cursor *cur) { + return timeouts_next(T, cur); +} /* next() */ + + static void destroy(void *T) { timeouts_close(T); } /* destroy() */ @@ -70,6 +75,7 @@ const struct benchops benchops = { .update = &update, .check = &check, .empty = &empty, + .next = &next, .destroy = &destroy }; @@ -183,6 +183,39 @@ static int bench_empty(lua_State *L) { } /* bench_empty() */ +static int bench__next(lua_State *L) { + struct bench *B = lua_touserdata(L, lua_upvalueindex(1)); + struct timeouts_cursor *cursor = lua_touserdata(L, lua_upvalueindex(2)); + struct timeout *to; + + if (!B->ops.next || !(to = B->ops.next(B->state, cursor))) + return 0; + + lua_pushinteger(L, luaL_optinteger(L, 2, 0) + 1); + + lua_newtable(L); + lua_pushinteger(L, to->expires); + lua_setfield(L, -2, "expires"); + + return 2; +} /* bench__next() */ + +static int bench__pairs(lua_State *L) { + struct timeouts_cursor *cursor; + + lua_settop(L, 1); + + cursor = lua_newuserdata(L, sizeof *cursor); + TIMEOUTS_CURSOR_INIT(cursor, TIMEOUTS_ALL); + + lua_pushcclosure(L, &bench__next, 2); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + + return 3; +} /* bench__pairs() */ + + static int bench__gc(lua_State *L) { struct bench *B = lua_touserdata(L, 1); @@ -206,8 +239,9 @@ static const luaL_Reg bench_methods[] = { }; static const luaL_Reg bench_metatable[] = { - { "__gc", &bench__gc }, - { NULL, NULL } + { "__pairs", &bench__pairs }, + { "__gc", &bench__gc }, + { NULL, NULL } }; static const luaL_Reg bench_globals[] = { @@ -6,5 +6,6 @@ struct benchops { void (*update)(void *, timeout_t); void (*check)(void *); int (*empty)(void *); + struct timeout *(*next)(void *, struct timeouts_cursor *); void (*destroy)(void *); }; /* struct benchops() */ @@ -79,6 +79,13 @@ } while (0) #endif +#if !defined TAILQ_FOREACH_SAFE +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) && ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) +#endif + /* * B I T M A N I P U L A T I O N R O U T I N E S @@ -587,24 +594,6 @@ static struct timeout *timeouts_min(struct timeouts *T) { } \ } while (0) -TIMEOUT_PUBLIC int timeouts_foreach(struct timeouts *T, int (*fp)(struct timeout *, void *), void *cb_arg) -{ - struct timeout *to = NULL; - int rv; - unsigned i, j; - - for (i = 0; i < countof(T->wheel); i++) { - for (j = 0; j < countof(T->wheel[i]); j++) { - TAILQ_FOREACH(to, &T->wheel[i][j], tqe) { - rv = fp(to,cb_arg); - if (rv) - return rv; - } - } - } - return 0; -} /* timeouts_foreach */ - TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) { timeout_t timeout; struct timeout *to; @@ -630,6 +619,59 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) { } /* timeouts_check() */ +#define ENTER \ + do { \ + static const int pc0 = __LINE__; \ + switch (pc0 + cur->pc) { \ + case __LINE__: (void)0 + +#define SAVE_AND_DO(do_statement) \ + do { \ + cur->pc = __LINE__ - pc0; \ + do_statement; \ + case __LINE__: (void)0; \ + } while (0) + +#define YIELD(rv) \ + SAVE_AND_DO(return (rv)) + +#define LEAVE \ + SAVE_AND_DO(break); \ + } \ + } while (0) + +TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts_cursor *cur) { + struct timeout *to; + + ENTER; + + if (cur->flags & TIMEOUTS_EXPIRED) { + TAILQ_FOREACH_SAFE(to, &T->expired, tqe, cur->to) { + YIELD(to); + } + } + + if (cur->flags & TIMEOUTS_PENDING) { + for (cur->i = 0; cur->i < countof(T->wheel); cur->i++) { + for (cur->j = 0; cur->j < countof(T->wheel[cur->i]); cur->j++) { + TAILQ_FOREACH_SAFE(to, &T->wheel[cur->i][cur->j], tqe, cur->to) { + YIELD(to); + } + } + } + } + + LEAVE; + + return NULL; +} /* timeouts_next */ + +#undef LEAVE +#undef YIELD +#undef SAVE_AND_DO +#undef ENTER + + /* * T I M E O U T R O U T I N E S * @@ -189,10 +189,34 @@ TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *); TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *, FILE *); /* return true if invariants hold. describes failures to optional file handle. */ -TIMEOUT_PUBLIC int timeouts_foreach(struct timeouts *, int (*fn)(struct timeout *, void *), void *); -/* Run fn(timeout,arg) on every pending or expired timeout in the wheel. If - * any iteration returns nonzero, return the nonzero value immediately and - * stop looping. */ +#define TIMEOUTS_PENDING 0x10 +#define TIMEOUTS_EXPIRED 0x20 +#define TIMEOUTS_ALL (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED) + +#define TIMEOUTS_CURSOR_INITIALIZER(flags) { (flags) } + +#define TIMEOUTS_CURSOR_INIT(cur, _flags) do { \ + (cur)->flags = (_flags); \ + (cur)->pc = 0; \ +} while (0) + +struct timeouts_cursor { + int flags; + unsigned pc, i, j; + struct timeout *to; +}; /* struct timeouts_cursor */ + +TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *, struct timeouts_cursor *); +/* return next timeout in pending wheel or expired queue. caller can delete + * the returned timeout, but should not otherwise manipulate the timing + * wheel. in particular, caller SHOULD NOT delete any other timeout as that + * could invalidate cursor state and trigger a use-after-free. + */ + +#define TIMEOUTS_FOREACH(var, T, flags) \ + struct timeouts_cursor _foreach_cursor = TIMEOUTS_CURSOR_INITIALIZER((flags)); \ + while (((var) = timeouts_next((T), &_foreach_cursor))) + /* * B O N U S W H E E L I N T E R F A C E S |
