From 9b5be13e623ef49be57beebe9abfac22bca61401 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 23 Jul 2013 00:41:52 +0200 Subject: [PATCH] Split libuev.c into smaller files to help linker Split libuev.c into one file per watcher type, mostly to give a better overview and ease of maintenance, but also to help the linker. Unfortunately this steals a few bytes when linking a full blown app, but for apps that, e.g., only need I/O watchers and no timers the resulting binary will be smaller. This applies to static binaries that are more common in embedded systems. $ size libuev.a libuev.so.1 text data bss dec hex filename 999 0 0 999 3e7 main.o (ex libuev.a) 90 0 0 90 5a io.o (ex libuev.a) 490 0 0 490 1ea timer.o (ex libuev.a) 4380 696 8 5084 13dc libuev.so.1 Also, move uev.h back to top from include/libuev/uev.h since a separate namespace is not needed after the removal of the OpenBSD queue.h copy. Signed-off-by: Joachim Nilsson --- .gitignore | 8 +- Makefile | 10 +-- io.c | 62 +++++++++++++++ libuev.c => main.c | 124 ++++-------------------------- test.c | 2 +- timer.c | 137 ++++++++++++++++++++++++++++++++++ include/libuev/uev.h => uev.h | 26 ++++--- 7 files changed, 241 insertions(+), 128 deletions(-) create mode 100644 io.c rename libuev.c => main.c (60%) create mode 100644 timer.c rename include/libuev/uev.h => uev.h (73%) diff --git a/.gitignore b/.gitignore index de472d6..62969e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ test test.o -.libuev.d -libuev.o +.main.d +main.o +.io.d +io.o +.timer.d +timer.o libuev.a libuev.so.1 diff --git a/Makefile b/Makefile index 21c78f9..2faa09f 100644 --- a/Makefile +++ b/Makefile @@ -36,11 +36,11 @@ LIBNAME = libuev prefix ?= /usr/local libdir ?= $(prefix)/lib datadir ?= $(prefix)/share/doc/$(LIBNAME) -incdir ?= $(prefix)/include/$(LIBNAME) +incdir ?= $(prefix)/include DISTFILES = README LICENSE test.c -INCLUDES = uev.h queue.h +HEADER = uev.h -OBJS := libuev.o +OBJS := main.o io.o timer.o SRCS := $(OBJS:.o=.c) DEPS := $(addprefix .,$(SRCS:.c=.d)) VER = 1 @@ -77,9 +77,7 @@ install: strip @install $(STATICLIB) $(DESTDIR)$(prefix)/lib/$(STATICLIB) @ln -sf $(SOLIB) $(DESTDIR)$(prefix)/lib/$(SYMLIB) @install -d $(DESTDIR)$(incdir) - @for file in $(INCLUDES); do \ - install -m 0644 include/libuev/$$file $(DESTDIR)$(incdir)/$$file; \ - done + @install -m 0644 $(HEADER) $(DESTDIR)$(incdir)/$(HEADER) @install -d $(DESTDIR)$(datadir) @for file in $(DISTFILES); do \ install -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \ diff --git a/io.c b/io.c new file mode 100644 index 0000000..e6abb2f --- /dev/null +++ b/io.c @@ -0,0 +1,62 @@ +/* libuev - Micro event loop library + * + * Copyright (c) 2012 Flemming Madsen + * Copyright (c) 2013 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "uev.h" + + +/** + * 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 + * + * @return The new I/O watcher, or %NULL if invalid pointers or out or memory. + */ +uev_io_t *uev_io_create(uev_t *ctx, uev_cb_t *handler, void *data, int fd, uev_dir_t dir) +{ + return uev_watcher_create(ctx, UEV_FILE_TYPE, fd, dir, handler, data); +} + +/** + * Delete an I/O watcher + * @param ctx A valid libuev context + * @param w I/O watcher + * + * @return POSIX OK(0) or non-zero with @param errno set. + */ +int uev_io_delete(uev_t *ctx, uev_io_t *w) +{ + return uev_watcher_delete(ctx, w); +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/libuev.c b/main.c similarity index 60% rename from libuev.c rename to main.c index d154a89..4ef6b31 100644 --- a/libuev.c +++ b/main.c @@ -1,4 +1,4 @@ -/* libuev - Asynchronous event loop library +/* libuev - Micro event loop library * * Copyright (c) 2012 Flemming Madsen * Copyright (c) 2013 Joachim Nilsson @@ -26,22 +26,12 @@ #include #include /* calloc(), free() */ #include -#include #include /* close(), read() */ -#include "libuev/uev.h" +#include "uev.h" -static struct timespec msec2tspec(int msec) -{ - struct timespec ts; - - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - - return ts; -} - -static uev_io_t *new_watcher(uev_t *ctx, uev_type_t type, int fd, uev_dir_t dir, uev_cb_t *handler, void *data) +/* Private to libuev, do not use directly! */ +uev_io_t *uev_watcher_create(uev_t *ctx, uev_type_t type, int fd, uev_dir_t dir, uev_cb_t *handler, void *data) { uev_io_t *w; struct epoll_event ev; @@ -73,7 +63,8 @@ static uev_io_t *new_watcher(uev_t *ctx, uev_type_t type, int fd, uev_dir_t dir, return w; } -static int delete_watcher(uev_t *ctx, uev_io_t *w) +/* Private to libuev, do not use directly! */ +int uev_watcher_delete(uev_t *ctx, uev_io_t *w) { if (!ctx || !w) { errno = EINVAL; @@ -90,97 +81,10 @@ static int delete_watcher(uev_t *ctx, uev_io_t *w) return 0; } -uev_io_t *uev_io_create(uev_t *ctx, uev_cb_t *handler, void *data, int fd, uev_dir_t dir) -{ - return new_watcher(ctx, UEV_FILE_TYPE, fd, dir, handler, data); -} - -int uev_io_delete(uev_t *ctx, uev_io_t *w) -{ - return delete_watcher(ctx, w); -} - /** - * Add a timer event - * @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 an event loop context * - * 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 - * timer ends its life there, while a periodic task's @param timeout is - * reset to the @param period and restarted. - * - * @return The new timer, or %NULL if invalid pointers or out or memory. - */ -uev_io_t *uev_timer_create(uev_t *ctx, uev_cb_t *handler, void *data, int timeout, int period) -{ - int fd; - uev_io_t *w; - - fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (fd < 0) - return NULL; - - w = new_watcher(ctx, UEV_TIMER_TYPE, fd, UEV_DIR_INBOUND, handler, data); - if (!w) - goto exit; - - if (uev_timer_set(ctx, w, timeout, period)) { - delete_watcher(ctx, w); - exit: - close(fd); - return NULL; - } - - return w; -} - -/** - * Reset or reschedule a timer - */ -int uev_timer_set(uev_t *ctx, uev_io_t *w, int timeout, int period) -{ - struct itimerspec time; - - if (!ctx || !w) { - errno = EINVAL; - return -1; - } - - w->timeout = timeout; - w->period = period; - - if (!ctx->running) - return 0; - - time.it_value = msec2tspec(timeout); - time.it_interval = msec2tspec(period); - - return timerfd_settime(w->fd, 0, &time, NULL); -} - -/** - * Remove a timer event - */ -int uev_timer_delete(uev_t *ctx, uev_io_t *w) -{ - if (!ctx || !w) { - errno = EINVAL; - return -1; - } - - uev_timer_set(ctx, w, 0, 0); - return delete_watcher(ctx, w); -} - -/** - * Create an application context + * @return Returns a new uev_t context, or %NULL on error. */ uev_t *uev_ctx_create(void) { @@ -210,7 +114,8 @@ uev_t *uev_ctx_create(void) } /** - * Destroy an application context + * Destroy an event loop context + * @param ctx A valid libuev context */ void uev_ctx_delete(uev_t *ctx) { @@ -229,7 +134,10 @@ void uev_ctx_delete(uev_t *ctx) } /** - * Run the application + * Start the event loop + * @param ctx A valid libuev context + * + * @return POSIX OK(0) upon successful termination of the event loop, or non-zero on error. */ int uev_run(uev_t *ctx) { @@ -286,14 +194,14 @@ int uev_run(uev_t *ctx) } /** - * Terminate the application + * Terminate the event loop + * @param ctx A valid libuev context */ void uev_exit(uev_t *ctx) { ctx->running = 0; } - /** * Local Variables: * version-control: t diff --git a/test.c b/test.c index 18395b6..68ab72f 100644 --- a/test.c +++ b/test.c @@ -27,7 +27,7 @@ #include #include /* intptr_t */ -#include "libuev/uev.h" +#include "uev.h" static int in, out; static int period = 0; diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..716f4a1 --- /dev/null +++ b/timer.c @@ -0,0 +1,137 @@ +/* libuev - Micro event loop library + * + * Copyright (c) 2012 Flemming Madsen + * Copyright (c) 2013 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include /* close(), read() */ + +#include "uev.h" + + +static struct timespec msec2tspec(int msec) +{ + struct timespec ts; + + ts.tv_sec = msec / 1000; + ts.tv_nsec = (msec % 1000) * 1000000; + + return ts; +} + +/** + * 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 + * + * 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 + * timer ends its life there, while a periodic task's @param timeout is + * reset to the @param period and restarted. + * + * @return The new timer, or %NULL if invalid pointers or out or memory. + */ +uev_io_t *uev_timer_create(uev_t *ctx, uev_cb_t *handler, void *data, int timeout, int period) +{ + int fd; + uev_io_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 I/O watcher + * + * @return POSIX OK(0) or non-zero with @param errno set. + */ +int uev_timer_set(uev_t *ctx, uev_io_t *w, int timeout, int period) +{ + struct itimerspec time; + + if (!ctx || !w) { + errno = EINVAL; + return -1; + } + + w->timeout = timeout; + w->period = period; + + if (!ctx->running) + return 0; + + time.it_value = msec2tspec(timeout); + time.it_interval = msec2tspec(period); + + return timerfd_settime(w->fd, 0, &time, NULL); +} + +/** + * Delete a timer watcher + * @param ctx A valid libuev context + * @param w I/O watcher + * + * @return POSIX OK(0) or non-zero with @param errno set. + */ +int uev_timer_delete(uev_t *ctx, uev_io_t *w) +{ + if (!ctx || !w) { + errno = EINVAL; + return -1; + } + + uev_timer_set(ctx, w, 0, 0); + + return uev_watcher_delete(ctx, w); +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/include/libuev/uev.h b/uev.h similarity index 73% rename from include/libuev/uev.h rename to uev.h index 0649e60..801de82 100644 --- a/include/libuev/uev.h +++ b/uev.h @@ -1,4 +1,4 @@ -/* libuev - Asynchronous event loop library +/* libuev - Micro event loop library * * Copyright (c) 2012 Flemming Madsen * Copyright (c) 2013 Joachim Nilsson @@ -73,21 +73,25 @@ typedef struct { } uev_t; /* Generic callback for watchers */ -typedef void (uev_cb_t) (uev_t *ctx, uev_io_t *w, void *data); +typedef void (uev_cb_t) (uev_t *ctx, uev_io_t *w, void *data); + +/* Private methods, do not use directly! */ +uev_io_t *uev_watcher_create(uev_t *ctx, uev_type_t type, int fd, uev_dir_t dir, uev_cb_t *handler, void *data); +int uev_watcher_delete(uev_t *ctx, uev_io_t *w); /* Public interface */ -uev_io_t *uev_io_create (uev_t *ctx, uev_cb_t *cb, void *data, int fd, uev_dir_t dir); -int uev_io_delete (uev_t *ctx, uev_io_t *w); +uev_io_t *uev_io_create (uev_t *ctx, uev_cb_t *cb, void *data, int fd, uev_dir_t dir); +int uev_io_delete (uev_t *ctx, uev_io_t *w); -int uev_timer_set (uev_t *ctx, uev_io_t *w, int timeout, int period); -uev_io_t *uev_timer_create(uev_t *ctx, uev_cb_t *cb, void *data, int timeout, int period); -int uev_timer_delete(uev_t *ctx, uev_io_t *w); +int uev_timer_set (uev_t *ctx, uev_io_t *w, int timeout, int period); +uev_io_t *uev_timer_create (uev_t *ctx, uev_cb_t *cb, void *data, int timeout, int period); +int uev_timer_delete (uev_t *ctx, uev_io_t *w); -uev_t *uev_ctx_create (void); -void uev_ctx_delete (uev_t *uev); +uev_t *uev_ctx_create (void); +void uev_ctx_delete (uev_t *uev); -int uev_run (uev_t *ctx); -void uev_exit (uev_t *ctx); +int uev_run (uev_t *ctx); +void uev_exit (uev_t *ctx); #endif /* LIBUEV_UEV_H_ */