7 Commits
Author SHA1 Message Date
Joachim Nilsson 6397edc2c4 Update ChangeLog and bump version for v1.2.0 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-09 13:18:39 +02:00
Joachim Nilsson cbd962c5b6 Fix bench.c so it actually reads from the pipe/socket, update callback API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-09 13:14:49 +02:00
Joachim Nilsson 1f9558059a API change -- Remove first ctx argument and add event mask to callback
There really does not exist a good reason for us sending a `uev_ctx_t *`
pointer as the first argument to event callbacks.  If the callback needs
to reference the context, it can find the ctx pointer in the `uev_t *w`.

This patch removes the first argument from all callbacks and also fixes
a slight bug in that the event loop never returned the actual event that
triggered the callback!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-09 13:10:20 +02:00
Joachim Nilsson 9e7f6865fc uev_timer_set(): Bugfix, call uev_watcher_start() even if not running yet!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-09 13:05:55 +02:00
Joachim Nilsson 3b31079a1c README: Refactor API section in an attempt to make it more accessible.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-29 09:31:14 +02:00
Joachim Nilsson 63697e9eda Add support for building static-only libuev.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-06 21:33:49 +01:00
Joachim Nilsson ce3930f0cf Update .gitignore, dep files now named *.d
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 15:55:44 +01:00
11 changed files with 118 additions and 61 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
bench
test
.*.d
*.d
*.o
*~
libuev.a
+20 -5
View File
@@ -4,8 +4,22 @@ Change Log
All notable changes to the project are documented in this file.
[v1.1.0]
--------
[v1.2.0] - 2015-06-09
---------------------
API change in event callbacks and fix timers that never start.
### Changes
- Remove first `uev_ctx_t *` argument in callbacks, incompatible API
change! Please update all your callbacks if you upgrade.
### Fixes
- Fix timers that accidentally broke in [v1.1.0].
- Fixes to `bench.c`, it now actually listens to the pipe/socket.
[v1.1.0] - 2015-03-04
---------------------
Massively improved error handling.
@@ -25,8 +39,8 @@ Massively improved error handling.
- Fix broken link to [v1.0.5] in this file.
[v1.0.5]
--------
[v1.0.5] - 2015-02-15
---------------------
### Changes
- Add `uev_*_start()` functions.
@@ -107,7 +121,8 @@ v0.0.1 - 2012-03-17
[Initial announcement] of [libuevent] by [Flemming Madsen] to the Lua
users mailing list.
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v1.1,0...HEAD
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v1.2.0...HEAD
[v1.2.0]: https://github.com/troglobit/libuev/compare/v1.1.0...v1.2.0
[v1.1.0]: https://github.com/troglobit/libuev/compare/v1.0.5...v1.1.0
[v1.0.5]: https://github.com/troglobit/libuev/compare/v1.0.4...v1.0.5
[v1.0.4]: https://github.com/troglobit/libuev/compare/v1.0.3...v1.0.4
+18 -9
View File
@@ -22,10 +22,10 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
.PHONY: all test clean joystick test examples
.PHONY: all test clean joystick test examples bench
#VERSION = $(shell git tag -l | tail -1)
VERSION ?= 1.1.0
VERSION ?= 1.2.0
NAME = libuev
PKG = $(NAME)-$(VERSION)
ARCHIVE = $(PKG).tar.xz
@@ -33,7 +33,11 @@ ARCHIVE = $(PKG).tar.xz
CC ?= $(CROSS)gcc
AR ?= $(CROSS)ar
STRIP ?= $(CROSS)strip
CFLAGS += -fPIC -Os
ifneq ($(STATIC), 1)
CFLAGS += -fPIC
endif
CFLAGS += -Os
CPPFLAGS += -W -Wall -Werror
ARFLAGS = crus
JUNK = *~ *.bak *.map .*.d DEADJOE *.gdb *.elf core core.* *.html
@@ -56,7 +60,11 @@ VER = 1
SOLIB = $(LIBNAME).so.$(VER)
SYMLIB = $(LIBNAME).so
STATICLIB = $(LIBNAME).a
ifeq ($(STATIC), 1)
TARGET = $(STATICLIB)
else
TARGET = $(STATICLIB) $(SOLIB)
endif
export STATICLIB JUNK ROOTDIR CFLAGS CPPFLAGS
@@ -77,9 +85,10 @@ $(STATICLIB): Makefile $(OBJS)
install: strip
@install -d $(DESTDIR)$(libdir)
@install $(SOLIB) $(DESTDIR)$(prefix)/lib/$(SOLIB)
@install $(STATICLIB) $(DESTDIR)$(prefix)/lib/$(STATICLIB)
@ln -sf $(SOLIB) $(DESTDIR)$(prefix)/lib/$(SYMLIB)
@printf " INSTALL $(DESTDIR)$(libdir)/$(TARGET)\n"
@install $(SOLIB) $(DESTDIR)$(libdir)/$(SOLIB)
@install $(STATICLIB) $(DESTDIR)$(libdir)/$(STATICLIB)
@ln -sf $(SOLIB) $(DESTDIR)$(libdir)/$(SYMLIB)
@install -d $(DESTDIR)$(incdir)
@install -m 0644 $(HEADER) $(DESTDIR)$(incdir)/$(HEADER)
@install -d $(DESTDIR)$(datadir)
@@ -97,9 +106,9 @@ strip: $(TARGET)
@$(STRIP) --strip-unneeded $(TARGET)
@size $(TARGET)
bench: Makefile bench.o $(STATICLIB)
@printf " BENCH %s\n" $(STATICLIB)
@$(CC) $(CPPFLAGS) -g -o bench bench.c $(STATICLIB) && ./bench
bench: Makefile $(STATICLIB)
@printf " RUN %s\n" $@
@$(CC) $(CPPFLAGS) -D_GNU_SOURCE -g -o bench bench.c $(STATICLIB) && ./bench
examples: all
@$(MAKE) -C examples
+49 -20
View File
@@ -61,15 +61,16 @@ details, see [this article][4] at [lwn.net](http://lwn.net).
API
---
Here is the interface to [libuEv]. It handles three different types of
events: I/O (files, sockets, message queues, etc.), timers, and signals.
The C interface to [libuEv] is very simple. It handles three different
types of events: I/O (files, sockets, message queues, etc.), timers, and
signals. With a slight caveat on signals
```C
/* Callback example, arg is passed from watcher's *_init()
* w->fd holds the file descriptor, events is set by libuEv
* to indicate if any of UEV_READ and/or UEV_WRITE is ready.
*/
void callback (uev_ctx_t *ctx, uev_t *w, void *arg, int events);
void callback (uev_t *w, void *arg, int events);
/* Event loop functions, notice use of flags! */
int uev_init (uev_ctx_t *ctx);
@@ -95,25 +96,47 @@ events: I/O (files, sockets, message queues, etc.), timers, and signals.
int uev_signal_stop (uev_t *w); /* Stop signal watcher */
```
To be able to set up callbacks to events the developer first need to
create an *event context*, achieved by calling `uev_init()` with a
pointer to a local `uev_ctx_t` variable.
To monitor events the developer first creates an *event context*, this
is achieved by calling `uev_init()` with a pointer to a (thread) local
`uev_ctx_t` variable.
Events are monitored by watchers in [libuEv]. A watcher is nothing more
than a mechnism that polls a file descriptor. Register a watcher with a
callback to the event context by passing the `uev_ctx_t` variable, along
with an `uev_t` variable to each event's `_init()` function.
```C
uev_ctx_t ctx;
When all watchers are registered call the event loop with `uev_run()`
and the argument to the event context. The `flags` parameter is slightly
mysterious, but can be used to integrate [libuEv] into another event loop.
With `flags` set to `UEV_ONCE` the event loop returns after having
served the first event. If `flags` is set to `UEV_ONCE | UEV_NONBLOCK`
the event loop returns immediately if no event is available.
uev_init(&ctx);
```
In the case of errors, stream close, or peer shutdown libuEv handles
much internally, but also lets the callback run. This is useful for
stateful connections to be able to detect EOF.
Then, for each event to be monitored, a *watcher* is registered with the
event context. The watcher, an `uev_t`, is initialized with the proper
file descriptor to monitor, and an event callback function, by calling
the event type's `_init()` function with the `uev_ctx_t` context.
```C
void cleanup_exit(uev_t *w, void *arg, int events)
{
/* Graceful exit, with optional cleanup ... */
uev_exit(w->ctx);
}
uev_t termw;
uev_signal_init(&ctx, &term, cleanup_exit, NULL, SIGTERM);
```
When all watchers are registered, call the *event loop* with `uev_run()`
and the argument to the event context. The `flags` parameter can be
used to integrate [libuEv] into another event loop. With `flags` set to
`UEV_ONCE` the event loop returns after having served the first event.
If `flags` is set to `UEV_ONCE | UEV_NONBLOCK` the event loop returns
immediately if no event is available.
```C
uev_run(&ctx, UEV_NONE);
```
In case of errors, stream close, or peer shutdown, libuEv handles much
internally, but also lets the callback run. This is useful for stateful
connections to be able to detect EOF.
Summary:
@@ -164,7 +187,7 @@ struct js_event {
uint8_t number; /* axis/button number */
} e;
static void joystick_cb(uev_ctx_t *ctx, uev_t *w, void *arg, int events)
static void joystick_cb(uev_t *w, void *arg, int events)
{
read (w->fd, &e, sizeof(e));
@@ -271,3 +294,9 @@ used for inspiration is the very small [Picoev][9] by [Oku Kazuho].
[Dave Zarzycki, Apple]: http://www.youtube.com/watch?v=cD_s6Fjdri8
[libuEv] is developed and maintained by [Joachim Nilsson]
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+6 -5
View File
@@ -70,7 +70,7 @@ static int *pipes;
static uev_t *evio;
static uev_t *evto;
static void read_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *arg, int UNUSED(events))
static void read_cb(uev_t *w, void *arg, int UNUSED(events))
{
int idx, widx;
u_char ch;
@@ -96,7 +96,7 @@ static void read_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *arg, int UNUSED(even
}
}
static void timer_cb(uev_ctx_t UNUSED(*ctx), uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
static void timer_cb(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
{
/* nop */
}
@@ -208,16 +208,17 @@ int main(int argc, char **argv)
if (timers)
uev_timer_init(&ctx, &evto[i], timer_cb, NULL, 0, 0);
args[i].index = i;
uev_io_init(&ctx, &evio[i], read_cb, &args[i], -1, UEV_READ);
#ifdef USE_PIPES
if (pipe(cp) == -1) {
if (pipe2(cp, O_NONBLOCK) == -1) {
#else
if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, cp) == -1) {
#endif
perror("pipe");
exit(1);
}
uev_io_init(&ctx, &evio[i], read_cb, &args[i], cp[0], UEV_READ);
}
for (i = 0; i < 2; i++)
+1 -1
View File
@@ -40,7 +40,7 @@ struct js_event {
uint8_t number; /* axis/button number */
} e;
static void joystick_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void joystick_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
if (read (w->fd, &e, sizeof(e)) < 0)
errx(errno, "Failed reading joystick event");
+10 -6
View File
@@ -69,13 +69,13 @@ static int callback(arg_t *arg, int event, void *foo)
return 42;
}
static void sigsegv_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
warnx("PID %d caused segfault.", getpid());
exit(-1);
}
static void sigchld_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
pid_t pid = waitpid(-1, NULL, WNOHANG);
@@ -83,7 +83,7 @@ static void sigchld_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(ar
warnx("PID %d exited, bye.", pid);
}
static void work_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *arg, int UNUSED(events))
static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
{
int status = 0;
pid_t pid;
@@ -102,15 +102,17 @@ static void work_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *arg, int UNU
if (WIFEXITED(status))
printf("Child exited normally => %d\n", WEXITSTATUS(status));
else if (WCOREDUMP(status))
printf("Child crashed!\n");
printf("Child crashed! %s\n", DO_SEGFAULT
? "As expected, everything is OK."
: "This should not happen!");
else
printf("Child did not exit normally!\n");
}
static void exit_cb(uev_ctx_t *ctx, uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
static void exit_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
printf("Process deadline reached, exiting!\n");
uev_exit(ctx);
uev_exit(w->ctx);
}
int main(void)
@@ -120,6 +122,8 @@ int main(void)
/* Initialize libuEv */
uev_init(&ctx);
/* Setup callbacks */
uev_signal_init(&ctx, &sigsegv_watcher, sigsegv_cb, NULL, SIGSEGV);
uev_signal_init(&ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
uev_timer_init(&ctx, &timeout_watcher, work_cb, &arg, 400, 0);
+8 -8
View File
@@ -40,33 +40,33 @@ static int in, out;
static int period = 0;
static uev_t *watchdog;
static void lifetime_cb(uev_ctx_t *ctx, uev_t UNUSED(*w), void *arg, int UNUSED(events))
static void lifetime_cb(uev_t *w, void *arg, int UNUSED(events))
{
fprintf(stderr, "\nLifetime exceeded, program completed successfully! (arg:%p)\n", arg);
uev_exit(ctx);
uev_exit(w->ctx);
}
/* The pipe watchdog, if it triggers we haven't received data in time. */
static void timeout_cb(uev_ctx_t *ctx, uev_t *UNUSED(w), void *arg, int UNUSED(events))
static void timeout_cb(uev_t *w, void *arg, int UNUSED(events))
{
watchdog = NULL;
fprintf(stderr, "\nTimeout exceeded %p\n", arg);
// uev_timer_stop(w); <-- No need to stop timers with period=0 :)
uev_exit(ctx);
uev_exit(w->ctx);
}
static void periodic_task(uev_ctx_t UNUSED(*ctx), uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
static void periodic_task(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
{
fprintf(stderr, "|");
}
static void signal_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void signal_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
fprintf(stderr, w->signo == SIGINT ? "^Cv" : "^\v");
}
static void pipe_read_cb(uev_ctx_t *UNUSED(ctx), uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
static void pipe_read_cb(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
{
int cnt;
char msg[50];
@@ -80,7 +80,7 @@ static void pipe_read_cb(uev_ctx_t *UNUSED(ctx), uev_t UNUSED(*w), void UNUSED(*
fprintf(stderr, "%.*s.%d ", cnt, msg, cnt);
}
static void pipe_write_cb(uev_ctx_t UNUSED(*ctx), uev_t *w, void *arg, int UNUSED(events))
static void pipe_write_cb(uev_t *w, void *arg, int UNUSED(events))
{
my_t *my = arg;
char *msg = "TESTING";
+1 -3
View File
@@ -123,11 +123,9 @@ int uev_timer_set(uev_t *w, int timeout, int period)
msec2tspec(timeout, &time.it_value);
msec2tspec(period, &time.it_interval);
timerfd_settime(w->fd, 0, &time, NULL);
return uev_watcher_start(w);
}
return 0;
return uev_watcher_start(w);
}
/**
+1 -1
View File
@@ -297,7 +297,7 @@ int uev_run(uev_ctx_t *ctx, int flags)
}
if (w->cb)
w->cb((struct uev *)ctx, w, w->arg);
w->cb(w, w->arg, events[i].events & UEV_EVENT_MASK);
if (UEV_TIMER_TYPE == w->type) {
if (!w->timeout)
+3 -2
View File
@@ -38,6 +38,7 @@
#define UEV_NONE 0
#define UEV_READ EPOLLIN
#define UEV_WRITE EPOLLOUT
#define UEV_EVENT_MASK (UEV_READ | UEV_WRITE)
/* Run flags */
#define UEV_ONCE 1
@@ -73,7 +74,7 @@ typedef struct uev {
int events;
/* Watcher callback with optional argument */
void (*cb)(struct uev *, struct uev *, void *);
void (*cb)(struct uev *, void *, int);
void *arg;
/* Timer watchers, time in milliseconds */
@@ -85,7 +86,7 @@ typedef struct uev {
} uev_t;
/* Generic callback for watchers */
typedef void (uev_cb_t)(uev_ctx_t *ctx, uev_t *w, void *arg, int events);
typedef void (uev_cb_t)(uev_t *w, void *arg, int events);
/* Private methods, do not use directly! */
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);