Event loop abstraction library
© Freebox, Nicolas Pouillon, 11 Oct 2011
1 Purpose
There are many existing event loops. Each framework creates its own, this is understandable (language, coding style, datatypes). We can name some event loops: glib (under gtk), CFRunLoop (in CoreFoundation, under Cocoa), QCoreApplication (in Qt), libevent, etc..
An utility library agnostic to one particular toolkit must ensure adaptability. This library aims to provide an uniform event loop API for such utility libraries.
As libraries may exist once in a system and yet get linked to different programs, adaptation must been done at runtime. Therefore, libela provides the said adaptation layer through some opaque structures and runtime function dispatch.
- 1 Purpose
- 2 Usage
- 3 Modules & Headers
- 4 Examples
2 Usage
Conceptual
An event loop is an utility objects that handles file descriptor availability and timers. It calls registered functions either:
input data is available on a file descriptor,
output queue of a file descriptor is not full any more,
a timer expires.
In libela, client (user) code registers sources, and each source can monitor:
at most one file descriptor (file, socket, etc.),
a timeout for file descriptor activity.
A pure timer can be created by not setting a file descriptor to a source, a file descriptor source can be set without a timer.
Each source can register exactly one callback function.
User API
Event loop usage
Client code has to create an ELA context either calling ela_create, which will create an event loop with the first available backend, or by explicitely calling an event loop wrapper constructor like ela_libevent.
After successful initialization, user may create and populate sources, and control the running event loop.
Source usage
As each backend needs its own source structures, Sources must be allocated and deleted through ela_source_alloc and ela_source_free.
Callback function and its private data are registered on source creation. They cannot be changed dynamically.
A source may watch a file descriptor through ela_set_fd. Timeout can be set through ela_set_timeout. Timeout is reset on each activity on the file descriptor, if relevant.
A source is only actually watched for when it is added to the event loop through ela_add. It may be removed with ela_remove. Dandling event source are harmless.
When they fire, event sources stay registered to the event loop by default. They are automatically removed if user passes ELA_EVENT_ONCE as flag to either ela_set_fd or ela_set_timeout.
Event loop life cycle
User may use ela-provided wrappers to run the event loop with ela_run. In case the backend is known (or wrapped in another library), the mainloop handling can be done from another control path than ela's (like gtk_main() or QApplication::exec()).
Anytime, user may want to exit the event loop. This can be done with ela_exit.
Once the user is done with ela and all the sources have explicitely been freed, user may call ela_close.
Backends implementation
Ela backends must implement all callbacks defined in struct ela_el_backend, and must implment a constructor method returning a pointer to an struct ela_el structure. This structure may be inherited in order to add private data to the context, but must contain the base struct ela_el strucure provided in this header for the standard ela calls to work.
Backends are free to define their own struct ela_event_source structures. The API does not define anything for them.
3 Modules & Headers
Modules
Name | Description |
---|---|
User API | Client code API |
Backend API | Event loop adapter |
Backends | Backend-specific calls |
Headers
Name | Description |
---|---|
ela/backend.h | Libela implementor's API |
ela/cf.h | CoreFoundation backend |
ela/ela.h | Libela user API |
ela/libevent.h | libevent backend |
User API module reference
Client code API More
Related headers
Name | Description |
---|---|
ela/ela.h | Libela user API |
Members
Types
- struct ela_el
- typedef [...] ela_error_t
- typedef void (ela_handler_func)(struct ela_event_source *source, int fd, uint32_t mask, void *data)
Event loop handling
- void ela_close(struct ela_el *ctx)
- struct ela_el * ela_create(const char *preferred)
- void ela_exit(struct ela_el *ctx)
- void ela_run(struct ela_el *ctx)
Event source allocation
- ela_error_t ela_source_alloc(struct ela_el *context, ela_handler_func *func, void *priv, struct ela_event_source **ret)
- void ela_source_free(struct ela_el *context, struct ela_event_source *src)
Event source handling
- ela_error_t ela_add(struct ela_el *ctx, struct ela_event_source *source)
- ela_error_t ela_remove(struct ela_el *ctx, struct ela_event_source *source)
Event source setup
- ela_error_t ela_set_fd(struct ela_el *ctx, struct ela_event_source *src, int fd, uint32_t flags)
- ela_error_t ela_set_timeout(struct ela_el *ctx, struct ela_event_source *src, const struct timeval *tv, uint32_t flags)
Source source type control
Description
Backend API module reference
Event loop adapter More
Related headers
Name | Description |
---|---|
ela/backend.h | Libela implementor's API |
Members
Type
- struct ela_el_backend
Function
- void ela_regsiter(const struct ela_el_backend *backend)
Description
Backends module reference
Backend-specific calls More
Related headers
Name | Description |
---|---|
ela/cf.h | CoreFoundation backend |
ela/libevent.h | libevent backend |
Members
Functions
- struct ela_el * ela_cf(CFRunLoopRef event)
- CFRunLoopRef ela_cf_get_runloop(struct ela_el *ela)
- struct ela_el * ela_libevent(struct event_base *event)
Description
ela/backend.h header reference
[Backend API module]
Libela implementor's API More
Inclusion list
Members
Types
- struct ela_el
- struct ela_el_backend
Function
- void ela_regsiter(const struct ela_el_backend *backend)
Description
Members detail
This macro is declared in ela/backend.h source file, line 12.
This struct is declared in ela/backend.h source file, line 93.
this struct is an event loop context structure. Implementations may decide to inherit this declaration and add other internal fields like:
struct my_event_loop_adapter
{
struct ela_el base;
struct my_event_loop *loop;
};
Then allocate a struct my_event_loop_adapter adapter and
return &adapter->base;
.
Field | Description |
---|---|
const struct ela_el_backend *backend; | Pointer to the event loop backend. |
This struct is declared in ela/backend.h source file, line 25.
Functions to be implemented by a event loop backend
Field | Description |
---|---|
ela_error_t (*source_alloc)(struct ela_el *context, ela_handler_func *func, void *priv, struct ela_event_source **ret) ; | Allocate an new event source structure. See ela_source_alloc |
void (*source_free)(struct ela_el *context, struct ela_event_source *src) ; | Release an event source structure. See ela_source_free |
ela_error_t (*set_fd)(struct ela_el *context, struct ela_event_source *src, int fd, uint32_t flags) ; | FD watcher registration. See ela_set_fd |
ela_error_t (*set_timeout)(struct ela_el *context, struct ela_event_source *src, const struct timeval *tv, uint32_t flags) ; | Timeout. See ela_set_timeout |
ela_error_t (*add)(struct ela_el *context, struct ela_event_source *src) ; | Watcher registration. See ela_add |
ela_error_t (*remove)(struct ela_el *context, struct ela_event_source *src) ; | Watcher unregistration. See ela_remove |
void (*exit)(struct ela_el *context) ; | Make the event loop exit. See ela_exit |
void (*run)(struct ela_el *context) ; | Run the event loop. See ela_run |
void (*close)(struct ela_el *context) ; | Close the event loop. See ela_close |
const char *name; | Backend name for enumeration and selection |
struct ela_el *(*create)(void ) ; | Standalone constructor |
void ela_regsiter(const struct ela_el_backend *backend)
This function is declared in ela/backend.h source file, line 107.
this function registers a backend to the global libela backend list. This provides a new backend to ela_create.
Parameters list:
- backend: The backend to register
ela/cf.h header reference
[Backends module]
CoreFoundation backend More
Inclusion list
Members
Functions
- struct ela_el * ela_cf(CFRunLoopRef event)
- CFRunLoopRef ela_cf_get_runloop(struct ela_el *ela)
Description
Members detail
This macro is declared in ela/cf.h source file, line 19.
struct ela_el * ela_cf(CFRunLoopRef event)
This function is declared in ela/cf.h source file, line 31.
this function creates an adapter to core foundation runloop.
The return value is an event loop, or NULL if core foundation support is unavailable.
CFRunLoopRef ela_cf_get_runloop(struct ela_el *ela)
This function is declared in ela/cf.h source file, line 40.
this function retrieves the runloop under the ELA one. Returns NULL if the ela is not an actual CFRunLoop.
Parameters list:
- ela: Abstract event loop
The return value is a CFRunLoop reference, if applicable
ela/ela.h header reference
[User API module]
Libela user API More
Members
Types
- typedef [...] ela_error_t
- typedef void (ela_handler_func)(struct ela_event_source *source, int fd, uint32_t mask, void *data)
Event loop handling
- void ela_close(struct ela_el *ctx)
- struct ela_el * ela_create(const char *preferred)
- void ela_exit(struct ela_el *ctx)
- void ela_run(struct ela_el *ctx)
Event source allocation
- ela_error_t ela_source_alloc(struct ela_el *context, ela_handler_func *func, void *priv, struct ela_event_source **ret)
- void ela_source_free(struct ela_el *context, struct ela_event_source *src)
Event source handling
- ela_error_t ela_add(struct ela_el *ctx, struct ela_event_source *source)
- ela_error_t ela_remove(struct ela_el *ctx, struct ela_event_source *source)
Event source setup
- ela_error_t ela_set_fd(struct ela_el *ctx, struct ela_event_source *src, int fd, uint32_t flags)
- ela_error_t ela_set_timeout(struct ela_el *ctx, struct ela_event_source *src, const struct timeval *tv, uint32_t flags)
Source source type control
Description
Members detail
This macro is declared in ela/ela.h source file, line 68.
Dont auto reinsert
This macro is declared in ela/ela.h source file, line 53.
Read available action
This macro is declared in ela/ela.h source file, line 63.
Timeout action
This macro is declared in ela/ela.h source file, line 58.
Write available action
ela_error_t ela_add(struct ela_el *ctx, struct ela_event_source *source)
This function is declared in ela/ela.h source file, line 171.
this function registers a watch and/or timeout in the event loop.
Parameters list:
- ctx: The event loop considered
- source: Source to unregister
The return value is 0 or ENOENT
void ela_close(struct ela_el *ctx)
This function is declared in ela/ela.h source file, line 231.
this function frees the event loop.
Parameters list:
- ctx: The event loop to close
Note the context given to the constructor is left alive. Caller is responsible for it.
struct ela_el * ela_create(const char *preferred)
This function is declared in ela/ela.h source file, line 245.
this function creates an event loop using the first available registered backend.
This makes no preference in the backend.
Parameters list:
- preferred: Preferred backend name
The return value is a valid ela context, or NULL.
This typedef is declared in ela/ela.h source file, line 78.
this typedef is the ela error code. Values are taken from the standard errno codes. See man 7 errno. No error is guaranteed to be 0.
void ela_exit(struct ela_el *ctx)
This function is declared in ela/ela.h source file, line 218.
this function exits the event loop.
You may exit the event loop even if it was not explicitely started with ela_run.
For instance, if you run a GTK application, this will make the GLib mainloop exit even if you called gtk_main() rather than ela_run().
Parameters list:
- ctx: The event loop to exit
This typedef is declared in ela/ela.h source file, line 48.
this typedef is a callback function type on FD readiness or timeout.
Parameters list:
- source: Event source
- fd: Relevant file descriptor, if any
- mask: Bitmask of events available
- data: Callback private data
ela_error_t ela_remove(struct ela_el *ctx, struct ela_event_source *source)
This function is declared in ela/ela.h source file, line 184.
this function unregisters a watch, action, timeout, etc. in the event loop.
Parameters list:
- ctx: The event loop considered
- source: Source to unregister
The return value is 0 or ENOENT
void ela_run(struct ela_el *ctx)
This function is declared in ela/ela.h source file, line 201.
this function runs the event loop.
The event loop processes events until:
the event loop is broken through ela_exit,
the underlying event loop is broken,
no event sources are left in the loop
Parameters list:
- ctx: The event loop to run
ela_error_t ela_set_fd(struct ela_el *ctx, struct ela_event_source *src, int fd, uint32_t flags)
This function is declared in ela/ela.h source file, line 135.
this function sets a file descriptor for watching in the event loop.
Parameters list:
- ctx: The event loop context
- src: Event source handle, for unregistration
- fd: File descriptor to watch for
- flags: Bitmask of events to watch for The only relevant flags are ELA_EVENT_ONCE, ELA_EVENT_READABLE and ELA_EVENT_WRITABLE.
The return value is Whether things went all right
The action stays watched on the FD until unregistration. No implicit unregistration occurs.
ela_error_t ela_set_timeout(struct ela_el *ctx, struct ela_event_source *src, const struct timeval *tv, uint32_t flags)
This function is declared in ela/ela.h source file, line 158.
this function sets a timeout on which event is called if there is no event on the associated fd. If no fd is associated, only the timeout may get fired.
Parameters list:
- ctx: The event loop context
- src: Event source handle, for unregistration
- tv: Timeout expiration value, relative
- flags: Bitmask of events to watch for. The only relevant flag is ELA_EVENT_ONCE.
The return value is Whether things went all right
The action is fired only once, and gets unregistered afterwards.
ela_error_t ela_source_alloc(struct ela_el *context, ela_handler_func *func, void *priv, struct ela_event_source **ret)
This function is declared in ela/ela.h source file, line 98.
this function allocates a new event source structure for future usage for any type of event watching.
Parameters list:
- ctx: The event loop context
- func: Callback to call on event ready state
- priv: Callback's private data
- ret: (out) Event source handle
The return value is 0 if all went right, or an error
void ela_source_free(struct ela_el *context, struct ela_event_source *src)
This function is declared in ela/ela.h source file, line 112.
this function frees an event source structure allocated with ela_source_alloc.
Parameters list:
- ctx: The event loop context
- src: Event source handle to free
This macro is for internal use only.
This macro is declared in ela/ela.h source file, line 30.
This macro is for internal use only.
This macro is declared in ela/ela.h source file, line 13.
ela/libevent.h header reference
[Backends module]
libevent backend More
Inclusion list
Members
Function
- struct ela_el * ela_libevent(struct event_base *event)
Description
Members detail
This macro is declared in ela/libevent.h source file, line 12.
struct ela_el * ela_libevent(struct event_base *event)
This function is declared in ela/libevent.h source file, line 30.
this function creates an adapter to libevent.
The return value is an event loop, or NULL if libevent support is unavailable.
4 Examples
An event loop may be explicitely created or allocated from the first available event loop backend. For instance, a code taking the backend name from the command line can be:
const char *backend_name = argc > 1 ? argv[1] : NULL;
struct ela_el *el = ela_create(backend_name);
if ( el == NULL ) {
fprintf(stderr, "No suitable event loop\n");
return 1;
}
Once created, the event loop may be used to create event sources referencing an existing callback function:
struct ela_event_source *source;
ela_error_t err = ela_source_alloc(el, cb, NULL, &source);
Then a timeout may be set on the source:
struct timeval tv = {0, 500000};
ela_set_timeout(el, source, &tv, 0);
The source may monitor a file descriptor as well:
ela_set_fd(el, source, fd, ELA_EVENT_READABLE);
A source callback function may filter incoming events:
static
void cb(struct ela_event_source *source, int fd,
uint32_t mask, void *data)
{
printf("callback. Flags: %02x\n", (int)mask);
if ( mask & ELA_EVENT_TIMEOUT )
printf("Timeout !\n");
}
Once all setup is done, source may be added to the loop:
ela_add(el, source);
Finally, cleanup code:
ela_source_free(el, source);
ela_close(el);