From e1b1daf5e3a7ecaa2352813d394ab50a845214b4 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 21 Jul 2013 08:31:29 +0200 Subject: [PATCH] Simplify linked list of I/O watchers and its garbage collect mechanism. Simplifed uev_io_t by removing uev_io_rem_t completely. A refactor that would not have been possible without the BSD queue.h API. This makes the code readable and thus maintainable and less error prone. Signed-off-by: Joachim Nilsson --- libuev.c | 35 +++++++++++++++++------------------ libuev.h | 13 +++---------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/libuev.c b/libuev.c index 29466cb..2a47e85 100644 --- a/libuev.c +++ b/libuev.c @@ -46,7 +46,6 @@ uev_io_t *uev_io_create(uev_t *ctx, int fd, uev_dir_t dir, uev_io_cb_t handler, if (!w) return NULL; - w->rem.ent = w; w->fd = fd; w->dir = dir; w->handler = (void *)handler; @@ -60,22 +59,23 @@ uev_io_t *uev_io_create(uev_t *ctx, int fd, uev_dir_t dir, uev_io_cb_t handler, int uev_io_delete(uev_t *ctx, uev_io_t *w) { - uev_io_rem_t *ent; + uev_io_t *tmp; if (!ctx || !w) { errno = EINVAL; return -1; } - TAILQ_FOREACH(ent, &ctx->io_delist, link) { - if (ent->ent == w) { + /* Check if already removed */ + TAILQ_FOREACH(tmp, &ctx->io_delist, gc) { + if (tmp == w) { errno = EALREADY; - return -1; /* Already removed */ + return -1; } } w->handler = NULL; - TAILQ_INSERT_TAIL(&ctx->io_delist, &w->rem, link); + TAILQ_INSERT_TAIL(&ctx->io_delist, w, gc); return 0; } @@ -150,10 +150,11 @@ int uev_timer_delete(uev_t *ctx, uev_timer_t *w) return -1; } + /* Check if already removed */ TAILQ_FOREACH(tmp, &ctx->timer_delist, link) { if (tmp == w) { errno = EALREADY; - return -1; /* Already removed */ + return -1; } } @@ -191,7 +192,7 @@ static int do_run_pending(uev_t *ctx, int immediate) diff = TIME_DIFF_MSEC(now, ctx->base_time); } - /* Reap timer zombies */ + /* Garbage collect */ TAILQ_FOREACH_SAFE(timer, &ctx->timer_delist, link, tmp) { TAILQ_REMOVE(&ctx->timer_delist, timer, link); free(timer); @@ -248,13 +249,12 @@ static int do_run_pending(uev_t *ctx, int immediate) } } + /* Garbage collect */ if (!TAILQ_EMPTY(&ctx->io_delist)) { - uev_io_rem_t *tmp; - - TAILQ_FOREACH(tmp, &ctx->io_delist, link) { - TAILQ_REMOVE(&ctx->io_delist, tmp, link); - TAILQ_REMOVE(&ctx->io_list, tmp->ent, link); - free(tmp->ent); + TAILQ_FOREACH(w, &ctx->io_delist, gc) { + TAILQ_REMOVE(&ctx->io_delist, w, gc); + TAILQ_REMOVE(&ctx->io_list, w, link); + free(w); } } } else if (diff > 0) { @@ -286,10 +286,9 @@ void uev_run(uev_t *ctx) /** * Drive the timeouts ourself (from now on until an increment of -1) * This is intended for use in testing frameworks - * Caveat emptor: Currently, interactions with the scheduler (agent) API is undefined. - * Not for use in uevs that use the agent scheduler - * @param ctx UEVlication context object - * @param msec Ms to advance. Use -1 to return to realtime + * + * @param ctx libuev context object + * @param msec Milliseconds to advance the timer. Use -1 to return to realtime */ void uev_run_tick(uev_t *ctx, int msec) { diff --git a/libuev.h b/libuev.h index 4f4fdc9..c62fdb2 100644 --- a/libuev.h +++ b/libuev.h @@ -33,10 +33,8 @@ ( (now - then) / clock_tick * 1000 + \ ((now - then) % clock_tick) * 1000 / clock_tick ) -/* Forward declarations due to dependencys, don't try this at home. */ +/* Forward declare due to dependencys, don't try this at home. */ struct uev; -struct uev_io; -struct uev_timer; /* I/O direction */ typedef enum { @@ -45,14 +43,9 @@ typedef enum { } uev_dir_t; /* I/O event watcher */ -typedef struct uev_io_rem { - TAILQ_ENTRY(uev_io_rem) link; - struct uev_io *ent; -} uev_io_rem_t; - typedef struct uev_io { TAILQ_ENTRY(uev_io) link; - uev_io_rem_t rem; ///< For postponed removal + TAILQ_ENTRY(uev_io) gc; int fd; ///< File descriptor uev_dir_t dir; ///< Direction: in or out @@ -77,7 +70,7 @@ typedef struct { TAILQ_HEAD(, uev_io) io_list; ///< File handlers TAILQ_HEAD(, uev_timer) timer_list; ///< Timer handlers - TAILQ_HEAD(, uev_io_rem) io_delist; ///< List of file handles to be garbage collected + TAILQ_HEAD(, uev_io) io_delist; ///< List of file handles to be garbage collected TAILQ_HEAD(, uev_timer) timer_delist; ///< List of timer handles to be garbage collected clock_t base_time; ///< Time at last timer tick