diff --git a/API.md b/API.md index f0fd242..3bcbf6a 100644 --- a/API.md +++ b/API.md @@ -57,6 +57,7 @@ void callback (uev_t *w, void *arg, int events); /* Event loop: Notice the use of flags! */ int uev_init (uev_ctx_t *ctx); +int uev_init1 (uev_ctx_t *ctx, int maxevents); int uev_exit (uev_ctx_t *ctx); int uev_run (uev_ctx_t *ctx, int flags); /* UEV_NONE, UEV_ONCE, and/or UEV_NONBLOCK */ diff --git a/src/private.h b/src/private.h index e2b149b..ad96c7c 100644 --- a/src/private.h +++ b/src/private.h @@ -76,6 +76,7 @@ typedef enum { typedef struct { int running; int fd; /* For epoll() */ + int maxevents; /* For epoll() */ struct uev *watchers; uint32_t workaround; /* For workarounds, e.g. redirected stdin */ } uev_ctx_t; diff --git a/src/uev.c b/src/uev.c index b966433..66d292f 100644 --- a/src/uev.c +++ b/src/uev.c @@ -178,16 +178,46 @@ int _uev_watcher_rearm(uev_t *w) * Create an event loop context * @param ctx Pointer to an uev_ctx_t context to be initialized * + * This function calls @func uev_init1() with @param maxevents set to + * @const UEV_MAX_EVENTS. + * * @return POSIX OK(0) on success, or non-zero on error. */ int uev_init(uev_ctx_t *ctx) { - if (!ctx) { + return uev_init1(ctx, UEV_MAX_EVENTS); +} + +/** + * Create an event loop context + * @param ctx Pointer to an uev_ctx_t context to be initialized + * @param maxevents Maximum number of events in event cache + * + * This function is the same as @func uev_init() except for the + * @param maxevents argument, which controls the number of events + * in the event cache returned to the main loop. + * + * In cases where you have multiple events pending in the cache and some + * event may cause later ones, already sent by the kernel to userspace, + * to be deleted the pointer returned to the event loop for this later + * event may be deleted. + * + * There are two ways around this (accessing deleted memory); 1) use + * this function to initialize your event loop and set @param maxevents + * to 1, 2) use a free list in you application that you garbage collect + * at intervals relevant to your application. + * + * @return POSIX OK(0) on success, or non-zero on error. + */ +int uev_init1(uev_ctx_t *ctx, int maxevents) +{ + if (!ctx || maxevents < 1) { errno = EINVAL; return -1; } memset(ctx, 0, sizeof(*ctx)); + ctx->maxevents = maxevents; return _init(ctx, 0); } @@ -301,7 +331,7 @@ int uev_run(uev_ctx_t *ctx, int flags) continue; ctx->workaround = 0; - while ((nfds = epoll_wait(ctx->fd, ee, UEV_MAX_EVENTS, timeout)) < 0) { + while ((nfds = epoll_wait(ctx->fd, ee, ctx->maxevents, timeout)) < 0) { if (!ctx->running) break; diff --git a/src/uev.h b/src/uev.h index 3ef7d22..61bdd14 100644 --- a/src/uev.h +++ b/src/uev.h @@ -76,6 +76,7 @@ typedef void (uev_cb_t)(uev_t *w, void *arg, int events); /* Public interface */ int uev_init (uev_ctx_t *ctx); +int uev_init1 (uev_ctx_t *ctx, int maxevents); int uev_exit (uev_ctx_t *ctx); int uev_run (uev_ctx_t *ctx, int flags);