The Evented IO Library - KQueue/EPoll abstraction

The evio.h library, is a KQueue/EPoll abstraction for edge triggered events and is part of's core.

It should be noted that exactly like epoll and kqueue, evio.h might produce unexpected results if forked after initialized, since this will cause the epoll/kqueue data to be shared across processes, even though these processes will not have access to new file descriptors (i.e. fd 90 on one process might reference file "A" while on a different process the same fd (90) might reference file "B").

This documentation isn't relevant for users. implements evio.h callbacks and evio.h cannot be used without removing facil.h and facil.c from the project.

This file is here as quick reference to anyone interested in maintaining or learning about how it's insides work.

Event Callbacks

Event callbacks are defined during the linking stage and are hardwired once compilation is complete.

void evio_on_data(void *) - called when the file descriptor has incoming data. This is one-shot triggered, meaning it will not be called again unless the evio_add (or evio_set_timer) are called.

void evio_on_ready(void *) - called when the file descriptor is ready to send data (outgoing).

void evio_on_error(void *) - called when a file descriptor raises an error while being polled.

void evio_on_close(void *) - called when a file descriptor was closed REMOTELY. evio_on_close will NOT get called when a connection is closed locally, unless using sock.h's callback, the sock_on_close function.

Notice: Both EPoll and KQueue will not raise an event for an fd that was closed using the native close function, so unless using sock.h or calling evio_on_close, the evio_on_close callback will only be called for remote events.

Notice: The on_open event is missing by design, as it is expected that any initialization required for the on_open event will be performed before attaching the file descriptor (socket/timer/pipe) to evio using evio_add.

The evio API


intptr_t evio_create(void)

Creates the epoll or kqueue object.

It's impossible to add or remove file descriptors from the polling system before calling this method.

Returns -1 on error, otherwise returns a unique value representing the epoll or kqueue object. The returned value can be safely ignored.

NOTE: Once an epoll / kqueue object was opened, fork should be avoided, since ALL the events will be shared among the forked processes (while not ALL the file descriptors are expected to be shared).


int evio_review(const int timeout_millisec)

Reviews any pending events (up to EVIO_MAX_EVENTS) and calls any callbacks.

Waits up to timeout_millisec for events to occur.

Returns -1 on error, otherwise returns the number of events handled.


void evio_close(void);

Closes the epoll / kqueue object, releasing it's resources (important if forking!).


int evio_isactive(void)

Returns true if the evio is available for adding or removing file descriptors.


int evio_add(int fd, void *callback_arg)

Adds a file descriptor to the polling object (ONE SHOT).

Returns -1 on error, otherwise return value is system dependent and can be safely ignored.


intptr_t evio_open_timer(void)

Creates a timer file descriptor, system dependent.

Returns -1 on error, or a valid fd on success.

NOTE: Systems have a limit on the number of timers that can be opened.


intptr_t evio_set_timer(int fd, void *callback_arg, unsigned long milliseconds)

Adds a timer file descriptor, so that callbacks will be called for it's events.

Returns -1 on error, otherwise return value is system dependent.

Known Issues