diff --git a/Makefile b/Makefile index b262b9e..ff3078d 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ CC = $(CROSS)gcc AR = $(CROSS)ar STRIP = $(CROSS)strip CFLAGS += -fPIC -Os -CPPFLAGS += -W -Wall -Iinclude +CPPFLAGS += -W -Wall -Werror -Iinclude ARFLAGS = crus JUNK = *~ *.bak *.map .*.d DEADJOE *.gdb *.elf core core.* diff --git a/io.c b/io.c index 5f49100..8f2531b 100644 --- a/io.c +++ b/io.c @@ -29,28 +29,53 @@ /** * Create an I/O watcher * @param ctx A valid libuev context - * @param handler I/O callback - * @param data Optional callback argument - * @param fd File descriptor to watch - * @param dir Direction of I/O to watch for: %UEV_DIR_INBOUND, or %UEV_DIR_OUTBOUND + * @param w Pointer to an uev_t watcher + * @param cb I/O callback + * @param arg Optional callback argument + * @param fd File descriptor to watch, or -1 to register an empty watcher + * @param events Requested events to watch for, a mask of %UEV_READ and %UEV_WRITE * - * @return The new I/O watcher, or %NULL if invalid pointers or out or memory. + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -uev_t *uev_io_create(uev_ctx_t *ctx, uev_cb_t *handler, void *data, int fd, uev_dir_t dir) +int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events) { - return uev_watcher_create(ctx, UEV_FILE_TYPE, fd, dir, handler, data); + if (uev_watcher_init(ctx, w, UEV_IO_TYPE, cb, arg, fd, events)) + return -1; + + if (fd < 0) + return 0; + + return uev_watcher_start(w); } /** - * Delete an I/O watcher - * @param ctx A valid libuev context - * @param w I/O watcher + * Reset an I/O watcher + * @param w Pointer to an uev_t watcher + * @param fd New file descriptor to monitor + * @param events Requested events to watch for, a mask of %UEV_READ and %UEV_WRITE * - * @return POSIX OK(0) or non-zero with @param errno set. + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -int uev_io_delete(uev_ctx_t *ctx, uev_t *w) +int uev_io_set(uev_t *w, int fd, int events) { - return uev_watcher_delete(ctx, w); + if (uev_io_stop(w)) + return -1; + + /* Remove from internal list */ + LIST_REMOVE(w, link); + + return uev_io_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, fd, events); +} + +/** + * Stop an I/O watcher + * @param w Pointer to an uev_t watcher + * + * @return POSIX OK(0) or non-zero with @param errno set on error. + */ +int uev_io_stop(uev_t *w) +{ + return uev_watcher_stop(w); } /** diff --git a/main.c b/main.c index 96a19cc..eeae857 100644 --- a/main.c +++ b/main.c @@ -24,7 +24,7 @@ */ #include -#include /* calloc(), free() */ +#include /* memset() */ #include #include /* struct signalfd_siginfo */ #include /* close(), read() */ @@ -32,103 +32,135 @@ #include "uev.h" /* Private to libuev, do not use directly! */ -uev_t *uev_watcher_create(uev_ctx_t *ctx, uev_type_t type, int fd, uev_dir_t dir, uev_cb_t *cb, void *arg) -{ - uev_t *w; - struct epoll_event ev; - - if (!ctx || !cb) { - errno = EINVAL; - return NULL; - } - - w = (uev_t *)calloc(1, sizeof(*w)); - if (!w) - return NULL; - - w->fd = fd; - w->type = type; - w->cb = (void *)cb; - w->arg = arg; - - ev.events = dir == UEV_DIR_OUTBOUND ? EPOLLOUT : EPOLLIN; - ev.data.ptr = w; - if (epoll_ctl(ctx->efd, EPOLL_CTL_ADD, fd, &ev) < 0) { - free(w); - return NULL; - } - - LIST_INSERT_HEAD(&ctx->watchers, w, link); - - return w; -} - -/* Private to libuev, do not use directly! */ -int uev_watcher_delete(uev_ctx_t *ctx, uev_t *w) +int uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events) { if (!ctx || !w) { errno = EINVAL; return -1; } - /* Remove from kernel */ - epoll_ctl(ctx->efd, EPOLL_CTL_DEL, w->fd, NULL); + memset(w, 0, sizeof(*w)); + w->ctx = ctx; + w->fd = fd; + w->type = type; + w->cb = (void *)cb; + w->arg = arg; + w->events = events; - /* Remove from internal list */ - LIST_REMOVE(w, link); - free(w); + LIST_INSERT_HEAD(&w->ctx->watchers, w, link); + + return 0; +} + +/* Private to libuev, do not use directly! */ +int uev_watcher_start(uev_t *w) +{ + struct epoll_event ev; + + if (!w || w->fd < 0) { + errno = EINVAL; + return -1; + } + + if (w->active) + return 0; + + ev.events = w->events; + ev.data.ptr = w; + if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) + return -1; + + w->active = 1; + + return 0; +} + +/* Private to libuev, do not use directly! */ +int uev_watcher_stop(uev_t *w) +{ + if (!w) { + errno = EINVAL; + return -1; + } + + if (!w->active) + return 0; + + /* Remove from kernel */ + epoll_ctl(w->ctx->fd, EPOLL_CTL_DEL, w->fd, NULL); + w->active = 0; return 0; } /** * Create an event loop context + * @param ctx Pointer to an uev_ctx_t context to be initialized * - * @return Returns a new uev_ctx_t context, or %NULL on error. + * @return POSIX OK(0) on success, or non-zero on error. */ -uev_ctx_t *uev_ctx_create(void) +int uev_init(uev_ctx_t *ctx) { int fd; - uev_ctx_t *ctx; fd = epoll_create(1); if (fd < 0) - return NULL; + return -1; - ctx = (uev_ctx_t *)calloc(1, sizeof(*ctx)); - if (!ctx) { - close(fd); - return NULL; - } - - ctx->efd = fd; + memset(ctx, 0, sizeof(*ctx)); + ctx->fd = fd; LIST_INIT(&ctx->watchers); - return ctx; + return 0; } /** - * Destroy an event loop context - * @param ctx A valid libuev context + * Terminate the event loop + * @param ctx A valid libuev context + * + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -void uev_ctx_delete(uev_ctx_t *ctx) +int uev_exit(uev_ctx_t *ctx) { + if (!ctx) { + errno = EINVAL; + return -1; + } + while (!LIST_EMPTY(&ctx->watchers)) { uev_t *w = LIST_FIRST(&ctx->watchers); - if (UEV_TIMER_TYPE == w->type) - uev_timer_delete(ctx, w); - else - uev_io_delete(ctx, w); + /* Remove from internal list */ + LIST_REMOVE(w, link); + + if (!w->active) + continue; + + switch (w->type) { + case UEV_TIMER_TYPE: + uev_timer_stop(w); + break; + + case UEV_SIGNAL_TYPE: + uev_signal_stop(w); + break; + + case UEV_IO_TYPE: + uev_io_stop(w); + break; + } } - close(ctx->efd); - free(ctx); + ctx->running = 0; + close(ctx->fd); + ctx->fd = -1; + + return 0; } /** * Start the event loop - * @param ctx A valid libuev context + * @param ctx A valid libuev context * * @return POSIX OK(0) upon successful termination of the event loop, or non-zero on error. */ @@ -137,7 +169,7 @@ int uev_run(uev_ctx_t *ctx) int result = 0; uev_t *w; - if (!ctx) { + if (!ctx || ctx->fd < 0) { errno = EINVAL; return -1; } @@ -148,14 +180,17 @@ int uev_run(uev_ctx_t *ctx) /* Start all dormant timers */ LIST_FOREACH(w, &ctx->watchers, link) { if (UEV_TIMER_TYPE == w->type) - uev_timer_set(ctx, w, w->timeout, w->period); + uev_timer_set(w, w->timeout, w->period); } while (ctx->running) { int i, nfds; struct epoll_event events[UEV_MAX_EVENTS]; - while ((nfds = epoll_wait(ctx->efd, events, UEV_MAX_EVENTS, -1)) < 0) { + while ((nfds = epoll_wait(ctx->fd, events, UEV_MAX_EVENTS, -1)) < 0) { + if (!ctx->running) + break; + if (EINTR == errno) continue; /* Signalled, try again */ exit: @@ -164,7 +199,7 @@ int uev_run(uev_ctx_t *ctx) break; } - for (i = 0; i < nfds; i++) { + for (i = 0; ctx->running && i < nfds; i++) { w = (uev_t *)events[i].data.ptr; if (UEV_TIMER_TYPE == w->type) { @@ -172,6 +207,9 @@ int uev_run(uev_ctx_t *ctx) if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) goto exit; + + if (!w->period) + w->timeout = 0; } if (UEV_SIGNAL_TYPE == w->type) { @@ -188,8 +226,8 @@ int uev_run(uev_ctx_t *ctx) w->cb((struct uev *)ctx, w, w->arg); if (UEV_TIMER_TYPE == w->type) { - if (!w->period) - uev_timer_delete(ctx, w); + if (!w->timeout) + uev_timer_stop(w); } } } @@ -197,15 +235,6 @@ int uev_run(uev_ctx_t *ctx) return result; } -/** - * Terminate the event loop - * @param ctx A valid libuev context - */ -void uev_exit(uev_ctx_t *ctx) -{ - ctx->running = 0; -} - /** * Local Variables: * version-control: t diff --git a/signal.c b/signal.c index 41218ee..85ac95b 100644 --- a/signal.c +++ b/signal.c @@ -33,90 +33,90 @@ /** * Create a signal watcher - * @param ctx A valid libuev context - * @param handler Timer callback - * @param data Optional callback argument - * @param signo Signal to watch for + * @param ctx A valid libuev context + * @param w Pointer to an uev_t watcher + * @param cb Timer callback + * @param arg Optional callback argument + * @param signo Signal to watch for * - * @return The new watcher, or %NULL with @param errno set on error. + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -uev_t *uev_signal_create(uev_ctx_t *ctx, uev_cb_t *handler, void *data, int signo) +int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo) { int fd; sigset_t mask; - uev_t *w; sigemptyset(&mask); fd = signalfd(-1, &mask, SFD_NONBLOCK); if (fd < 0) - return NULL; + return -1; - w = uev_watcher_create(ctx, UEV_SIGNAL_TYPE, fd, UEV_DIR_INBOUND, handler, data); - if (!w) + if (uev_watcher_init(ctx, w, UEV_SIGNAL_TYPE, cb, arg, fd, UEV_READ)) goto exit; - if (uev_signal_set(ctx, w, signo)) { - uev_watcher_delete(ctx, w); + if (uev_signal_set(w, signo)) { + uev_watcher_stop(w); exit: close(fd); - return NULL; + return -1; } - return w; + return 0; } /** * Reset a signal watcher - * @param ctx A valid libuev context - * @param w Watcher to reset - * @param signo New signal to watch for + * @param w Watcher to reset + * @param signo New signal to watch for * - * @return POSIX OK(0) or non-zero with @param errno set. + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -int uev_signal_set(uev_ctx_t *ctx, uev_t *w, int signo) +int uev_signal_set(uev_t *w, int signo) { sigset_t mask; - if (!ctx || !w) { + /* Every watcher must be registered to a context */ + if (!w || !w->ctx) { errno = EINVAL; return -1; } + /* Handle stopped signal watchers */ + if (w->fd < 0) { + /* Remove from internal list */ + LIST_REMOVE(w, link); + + if (uev_signal_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, signo)) + return -1; + } + sigemptyset(&mask); sigaddset(&mask, signo); /* Block signals so that they aren't handled according to their default dispositions */ - if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) return -1; if (signalfd(w->fd, &mask, SFD_NONBLOCK) < 0) return -1; - return 0; + return uev_watcher_start(w); } /** - * Delete a signal watcher - * @param ctx A valid libuev context - * @param w Watcher to delete + * Stop a signal watcher + * @param w Watcher to stop * - * @return POSIX OK(0) or non-zero with @param errno set. + * @return POSIX OK(0) or non-zero with @param errno set on error. */ -int uev_signal_delete(uev_ctx_t *ctx, uev_t *w) +int uev_signal_stop(uev_t *w) { - int fd; - - if (!ctx || !w) { - errno = EINVAL; + if (uev_watcher_stop(w)) return -1; - } - uev_timer_set(ctx, w, 0, 0); - fd = w->fd; - uev_watcher_delete(ctx, w); - close(fd); + close(w->fd); + w->fd = -1; return 0; } diff --git a/test.c b/test.c index e3cd415..0553533 100644 --- a/test.c +++ b/test.c @@ -30,105 +30,113 @@ #include "uev.h" +#define UNUSED(arg) arg __attribute__ ((unused)) + +typedef struct { + int counter; +} my_t; + static int in, out; static int period = 0; -static uev_t *timer = NULL; +static uev_t *watchdog; -static void lifetime_cb(uev_ctx_t *ctx, uev_t *w __attribute__ ((unused)), void *data) +static void lifetime_cb(uev_ctx_t *ctx, uev_t UNUSED(*w), void *arg, int UNUSED(events)) { - fprintf(stderr, "\nLifetime exceeded %p\n", data); + fprintf(stderr, "\nLifetime exceeded %p\n", arg); uev_exit(ctx); } /* The pipe watchdog, if it triggers we haven't received data in time. */ -static void timeout_cb(uev_ctx_t *ctx, uev_t *w, void *data) +static void timeout_cb(uev_ctx_t *ctx, uev_t *w, void *arg, int UNUSED(events)) { - timer = NULL; - fprintf(stderr, "\nTimeout exceeded %p\n", data); + watchdog = NULL; + fprintf(stderr, "\nTimeout exceeded %p\n", arg); - uev_timer_delete(ctx, w); + uev_timer_stop(w); uev_exit(ctx); } -static void periodic_task(uev_ctx_t *ctx __attribute__ ((unused)), uev_t *w __attribute__ ((unused)), void *data __attribute__ ((unused))) +static void periodic_task(uev_ctx_t UNUSED(*ctx), uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events)) { fprintf(stderr, "|"); } -static void signal_cb(uev_ctx_t *ctx __attribute__ ((unused)), uev_t *w, void *data __attribute__ ((unused))) +static void signal_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *UNUSED(arg), int UNUSED(events)) { fprintf(stderr, w->signo == SIGINT ? "^Cv" : "^\v"); } -static void pipe_read_cb(uev_ctx_t *ctx, uev_t *w __attribute__ ((unused)), void *data __attribute__ ((unused))) +static void pipe_read_cb(uev_ctx_t *UNUSED(ctx), uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events)) { int cnt; char msg[50]; /* Kick watchdog */ - if (timer) - uev_timer_set(ctx, timer, 1000, 0); + if (watchdog) + uev_timer_set(watchdog, 1000, 0); cnt = read(in, msg, sizeof(msg)); // fprintf(stderr, "READ %.*s %d\n", cnt, msg, cnt); fprintf(stderr, "%.*s.%d ", cnt, msg, cnt); } -static void pipe_write_cb(uev_ctx_t *ctx, uev_t *w __attribute__ ((unused)), void *data) +static void pipe_write_cb(uev_ctx_t UNUSED(*ctx), uev_t *w, void *arg, int UNUSED(events)) { - int cnt = (int)(intptr_t)data; + my_t *my = arg; char *msg = "TESTING"; - if (write(out, msg, cnt) < 0) { + if (write(out, msg, my->counter) < 0) { perror("\nFailed writing to pipe"); return; } -// fprintf(stderr, "WRITE %.*s %d\n", cnt, msg, cnt); - fprintf(stderr, "%d ", cnt); - period = cnt + 5; +// fprintf(stderr, "WRITE %.*s %d\n", my->counter, msg, my->counter); + fprintf(stderr, "%d ", my->counter); + period = my->counter + 5; + my->counter++; - uev_timer_create(ctx, pipe_write_cb, (void *)(intptr_t)(cnt + 1), period * 100, 0); + uev_timer_set(w, period * 100, 0); } int main(void) { int fd[2]; - uev_ctx_t *ctx = uev_ctx_create(); - - /* Total program execution time */ - uev_timer_create(ctx, lifetime_cb, (void *)(intptr_t)2, 4000, 0); + my_t my = { .counter = 1 }; + uev_t timeout, wdt, periodic, writer, reader, sigint_watcher, sigquit_watcher; + uev_ctx_t ctx; /* Work load, one timer callback writes to a pipe periodically, * and one I/O watcher that is called every time the pipe has * some data. */ - if (pipe(fd) < 0) { - /* Cleanup */ - uev_ctx_delete(ctx); + if (pipe(fd) < 0) return 1; - } + /* */ + uev_init(&ctx); + + /* Signal watchers, Ctrl-C => SIGINT, Ctrl-\ => SIGQUIT */ + uev_signal_init(&ctx, &sigint_watcher, signal_cb, NULL, SIGINT); + uev_signal_init(&ctx, &sigquit_watcher, signal_cb, NULL, SIGQUIT); + + /* Total program execution time */ + uev_timer_init(&ctx, &timeout, lifetime_cb, (void *)(intptr_t)2, 4000, 0); + + /* Main pipe worker and consumer */ in = fd[0]; out = fd[1]; - uev_timer_create(ctx, pipe_write_cb, (void *)(intptr_t)1, 400, 0); - uev_io_create(ctx, pipe_read_cb, NULL, in, UEV_DIR_INBOUND); + uev_io_init(&ctx, &reader, pipe_read_cb, NULL, in, UEV_READ); + uev_timer_init(&ctx, &writer, pipe_write_cb, &my, 400, 0); /* Watchdog for the above timer callback, if it doesn't wake up * and write to the pipe within a given deadline it will bark. */ - timer = uev_timer_create(ctx, timeout_cb, (void *)(intptr_t)1, 950, 0); + uev_timer_init(&ctx, &wdt, timeout_cb, (void *)(intptr_t)1, 950, 0); + watchdog = &wdt; /* Periodic background task */ - uev_timer_create(ctx, periodic_task, NULL, 200, 200); - - /* Signal watchers, Ctrl-C => SIGINT, Ctrl-\ => SIGQUIT */ - uev_signal_create(ctx, signal_cb, NULL, SIGINT); - uev_signal_create(ctx, signal_cb, NULL, SIGQUIT); + uev_timer_init(&ctx, &periodic, periodic_task, NULL, 200, 200); /* Start event loop */ - uev_run(ctx); - - /* Tear down event context */ - uev_ctx_delete(ctx); + uev_run(&ctx); fprintf(stderr, "Period is %d must be 10: %s\n", period, 10 == period ? "OK" : "ERROR!"); if (10 != period) diff --git a/timer.c b/timer.c index f3cf3ba..480ed54 100644 --- a/timer.c +++ b/timer.c @@ -30,107 +30,123 @@ #include "uev.h" -static struct timespec msec2tspec(int msec) +static void msec2tspec(int msec, struct timespec *ts) { - struct timespec ts; - - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - - return ts; + if (msec) { + ts->tv_sec = msec / 1000; + ts->tv_nsec = (msec % 1000) * 1000000; + } else { + ts->tv_sec = 0; + ts->tv_nsec = 0; + } } /** - * Create a timer watcher - * @param ctx A valid libuev context - * @param handler Timer callback - * @param data Optional callback argument - * @param timeout Timeout in milliseconds before @param handler is called - * @param period For periodic timers this is the period time that @param timeout is reset to + * Create and start a timer watcher + * @param ctx A valid libuev context + * @param w Pointer to an uev_t watcher + * @param cb Callback function + * @param arg Optional callback argument + * @param timeout Timeout in milliseconds before @param cb is called + * @param period For periodic timers this is the period time that @param timeout is reset to * * For one-shot timers you set @param period to zero and only use @param * timeout. For periodic timers you likely set @param timeout to either * zero, to call it as soon as the event loop starts, or to the same - * value as @param period. When the timer expires, the @param handler - * is called, with the optional @param data argument. A non-periodic + * value as @param period. When the timer expires, the @param cb + * is called, with the optional @param arg argument. A non-periodic * timer ends its life there, while a periodic task's @param timeout is * reset to the @param period and restarted. * - * @return The new watcher, or %NULL with @param errno set on error. - */ -uev_t *uev_timer_create(uev_ctx_t *ctx, uev_cb_t *handler, void *data, int timeout, int period) -{ - int fd; - uev_t *w; - - fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (fd < 0) - return NULL; - - w = uev_watcher_create(ctx, UEV_TIMER_TYPE, fd, UEV_DIR_INBOUND, handler, data); - if (!w) - goto exit; - - if (uev_timer_set(ctx, w, timeout, period)) { - uev_watcher_delete(ctx, w); - exit: - close(fd); - return NULL; - } - - return w; -} - -/** - * Reset or reschedule a timer - * @param ctx A valid libuev context - * @param w Watcher to reset - * @param timeout Timeout in milliseconds before @param handler is called - * @param period For periodic timers this is the period time that @param timeout is reset to + * A timer is automatically started if the event loop is already + * running, otherwise it is kept on hold until triggered by calling + * uev_run(). * * @return POSIX OK(0) or non-zero with @param errno set on error. */ -int uev_timer_set(uev_ctx_t *ctx, uev_t *w, int timeout, int period) +int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period) { - struct itimerspec time; + int fd; - if (!ctx || !w) { + fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (fd < 0) + return -1; + + if (uev_watcher_init(ctx, w, UEV_TIMER_TYPE, cb, arg, fd, UEV_READ)) + goto exit; + + if (uev_timer_set(w, timeout, period)) { + uev_watcher_stop(w); + exit: + close(fd); + return -1; + } + + return 0; +} + +/** + * Reset a timer + * @param w Watcher to reset + * @param timeout Timeout in milliseconds before @param cb is called + * @param period For periodic timers this is the period time that @param timeout is reset to + * + * @return POSIX OK(0) or non-zero with @param errno set on error. + */ +int uev_timer_set(uev_t *w, int timeout, int period) +{ + /* Every watcher must be registered to a context */ + if (!w || !w->ctx) { errno = EINVAL; return -1; } + /* Handle stopped timers */ + if (w->fd < 0) { + /* Timer already stopped */ + if (!timeout && !period) + return 0; + + /* Remove from internal list */ + LIST_REMOVE(w, link); + + if (uev_timer_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, timeout, period)) + return -1; + } + w->timeout = timeout; w->period = period; - if (!ctx->running) - return 0; + if (w->ctx->running) { + struct itimerspec time; - time.it_value = msec2tspec(timeout); - time.it_interval = msec2tspec(period); + msec2tspec(timeout, &time.it_value); + msec2tspec(period, &time.it_interval); + timerfd_settime(w->fd, 0, &time, NULL); - return timerfd_settime(w->fd, 0, &time, NULL); + return uev_watcher_start(w); + } + + return 0; } /** - * Delete a timer watcher - * @param ctx A valid libuev context - * @param w Watcher to delete + * Stop and unregister a timer watcher + * @param w Watcher to stop * * @return POSIX OK(0) or non-zero with @param errno set on error. */ -int uev_timer_delete(uev_ctx_t *ctx, uev_t *w) +int uev_timer_stop(uev_t *w) { - int fd; - - if (!ctx || !w) { - errno = EINVAL; + if (uev_watcher_stop(w)) return -1; - } - uev_timer_set(ctx, w, 0, 0); - fd = w->fd; - uev_watcher_delete(ctx, w); - close(fd); + /* Stop kernel timer */ + uev_timer_set(w, 0, 0); + + /* Close timerfd, will have to be reopened again on reset */ + close(w->fd); + w->fd = -1; return 0; } diff --git a/uev.h b/uev.h index 5efa351..5733d59 100644 --- a/uev.h +++ b/uev.h @@ -26,78 +26,83 @@ #ifndef LIBUEV_UEV_H_ #define LIBUEV_UEV_H_ +#include +#include #include /* Max. number of simulateneous events */ #define UEV_MAX_EVENTS 10 -/* Forward declare due to dependencys, don't try this at home. */ -struct uev; +/* I/O events, for signals and timers revents will always be UEV_READ */ +#define UEV_NONE 0 +#define UEV_READ EPOLLIN +#define UEV_WRITE EPOLLOUT -/* I/O direction */ +/* I/O, timer, or signal watcher */ typedef enum { - UEV_DIR_INBOUND = 0, - UEV_DIR_OUTBOUND = 1 -} uev_dir_t; - -/* I/O, timer, or signal */ -typedef enum { - UEV_FILE_TYPE = 1, + UEV_IO_TYPE = 1, UEV_TIMER_TYPE, UEV_SIGNAL_TYPE, } uev_type_t; -/* I/O event watcher */ -typedef struct uev { - LIST_ENTRY(uev) link; /* For queue.h linked list */ - - /* Common to all watchers */ - uev_type_t type; - int fd; - - /* Watcher callback with optional argument */ - void (*cb)(struct uev *, struct uev *, void *); - void *arg; - - /* Timer watchers, time in milliseconds */ - int timeout; - int period; - - /* Signal watchers */ - int signo; -} uev_t; +/* Forward declare due to dependencys, don't try this at home kids. */ +struct uev; /* Main libuev context type */ typedef struct { - int running; - int efd; /* For epoll() */ - LIST_HEAD(, uev) watchers; + int running; + int fd; /* For epoll() */ + LIST_HEAD(,uev) watchers; } uev_ctx_t; +/* I/O event watcher */ +typedef struct uev { + LIST_ENTRY(uev) link; /* For queue.h linked list */ + + /* Common to all watchers */ + uev_ctx_t *ctx; + uev_type_t type; + int active; + int fd; + int events; + + /* Watcher callback with optional argument */ + void (*cb)(struct uev *, struct uev *, void *); + void *arg; + + /* Timer watchers, time in milliseconds */ + int timeout; + int period; + + /* Signal watchers */ + int signo; +} uev_t; + /* Generic callback for watchers */ -typedef void (uev_cb_t) (uev_ctx_t *ctx, uev_t *w, void *data); +typedef void (uev_cb_t)(uev_ctx_t *ctx, uev_t *w, void *arg, int events); /* Private methods, do not use directly! */ -uev_t *uev_watcher_create(uev_ctx_t *ctx, uev_type_t type, int fd, uev_dir_t dir, uev_cb_t *cb, void *data); -int uev_watcher_delete(uev_ctx_t *ctx, uev_t *w); +int uev_watcher_init (uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events); +int uev_watcher_start (uev_t *w); +int uev_watcher_stop (uev_t *w); /* Public interface */ -uev_t *uev_io_create (uev_ctx_t *ctx, uev_cb_t *cb, void *data, int fd, uev_dir_t dir); -int uev_io_delete (uev_ctx_t *ctx, uev_t *w); +int uev_init (uev_ctx_t *ctx); +int uev_exit (uev_ctx_t *ctx); -int uev_timer_set (uev_ctx_t *ctx, uev_t *w, int timeout, int period); -uev_t *uev_timer_create (uev_ctx_t *ctx, uev_cb_t *cb, void *data, int timeout, int period); -int uev_timer_delete (uev_ctx_t *ctx, uev_t *w); +int uev_run (uev_ctx_t *ctx); -uev_t *uev_signal_create (uev_ctx_t *ctx, uev_cb_t *handler, void *data, int signo); -int uev_signal_set (uev_ctx_t *ctx, uev_t *w, int signo); -int uev_signal_delete (uev_ctx_t *ctx, uev_t *w); +int uev_io_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events); +int uev_io_set (uev_t *w, int fd, int events); +int uev_io_stop (uev_t *w); -uev_ctx_t *uev_ctx_create (void); -void uev_ctx_delete (uev_ctx_t *uev); +int uev_timer_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period); +int uev_timer_set (uev_t *w, int timeout, int period); +int uev_timer_stop (uev_t *w); -int uev_run (uev_ctx_t *ctx); -void uev_exit (uev_ctx_t *ctx); +int uev_signal_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo); +int uev_signal_set (uev_t *w, int signo); +int uev_signal_stop (uev_t *w); #endif /* LIBUEV_UEV_H_ */