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.

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  

NameDescription
User APIClient code API
Backend APIEvent loop adapter
BackendsBackend-specific calls

Headers  

NameDescription
ela/backend.hLibela implementor's API
ela/cf.hCoreFoundation backend
ela/ela.hLibela user API
ela/libevent.hlibevent backend

User API module reference

Client code API More

Related headers  

NameDescription
ela/ela.hLibela user API

Members  

Types  

Event loop handling  

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  

Client code API

Backend API module reference

Event loop adapter More

Related headers  

NameDescription
ela/backend.hLibela implementor's API

Members  

Type  

Function  

Description  

Event loop adapter

Backends module reference

Backend-specific calls More

Related headers  

NameDescription
ela/cf.hCoreFoundation backend
ela/libevent.hlibevent backend

Members  

Functions  

Description  

Backend-specific calls

ela/backend.h header reference
[Backend API module]

Libela implementor's API More

Inclusion list  

Members  

Types  

Function  

Description  

Libela implementor's API

Members detail  

#define ELA_BACKEND_H  

This macro is declared in ela/backend.h source file, line 12.

struct ela_el  

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;

.

FieldDescription
const struct ela_el_backend *backend;Pointer to the event loop backend.

struct ela_el_backend  

This struct is declared in ela/backend.h source file, line 25.

Functions to be implemented by a event loop backend

FieldDescription
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  

Description  

CoreFoundation backend

Members detail  

#define ELA_CF_H  

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  

Event loop handling  

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  

Libela user API

Members detail  

#define ELA_EVENT_ONCE  

This macro is declared in ela/ela.h source file, line 68.

Dont auto reinsert

#define ELA_EVENT_READABLE  

This macro is declared in ela/ela.h source file, line 53.

Read available action

#define ELA_EVENT_TIMEOUT  

This macro is declared in ela/ela.h source file, line 63.

Timeout action

#define ELA_EVENT_WRITABLE  

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.

typedef int ela_error_t  

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

typedef void (ela_handler_func)(struct ela_event_source *source, int fd, uint32_t mask, void *data)   

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:

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

#define ELA_EXPORT  

This macro is for internal use only.

This macro is declared in ela/ela.h source file, line 30.

#define ELA_H_  

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  

Description  

libevent backend

Members detail  

#define ELA_LIBEVENT_H  

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);

Valid XHTML 1.0 StrictGenerated by nipo on Tue Oct 11 18:49:11 2011 using MkDoc