Specifications

CHAPTER 5. IMPLEMENTATION 48
Event Loop
The start up of the daemon is completed by entering the main event loop. This event loop
is implemented by the GLib library. In combination with functions provided by GLib it is
possible to add callback functions to the event loop. A callback function is invoked as soon as
a specified event occurs. The source of an event can be a timeout or the modification of a file
descriptor (file, pipe or socket).
If a module needs to poll a kernel interface, it needs to add its callback function to the
event loop by using a timeout mechanism. This is accomplished by using GLib’s function
g timeout add():
g_timeout_add(guint interval, GSourceFunc function, gpointer data);
The argument interval states the interval between the event loop calls the function
passed by the argument function. The GLib data type guint corresponds to the standard
C unsigned int type. Each time the event lo op calls the callback function, it passes the
gpointer data to the function. The GLib data type gpointer corresponds to a standard C
void pointer. This pointer is arbitrary—e.g. it can be a pointer to a data structure. Once the
callback function is running it has to return either TRUE or FALSE. In the event the function
returns TRUE, it will be invoked again as soon as the time specified by interval is elapsed.
Once the callback function returns FALSE, it is removed from the event loop and will not be
executed again.
Modules receiving input events from an interface which does not need to be polled use
another approach to add callback functions to the event loop. GLib provides the data type
GIOChannel representing an I/O channel. A GIOChannel is associated with a file descriptor
referencing a file, pipe or socket. Various functions are provided by GLib in order to access
data from a GIOChannel. A GIOChannel can easily be assigned as event source, too. This is
achieved by defining a watch using the GLib function g io add watch(). The combination
of a GIOChannel and a watch offers a comfortable way to observe a file descriptor. Since
various user space interfaces for input events are implemented either as file, pipe or socket
this combination is very suitable for implementing an Input Abstraction Layer module. The
following source code shows how a watch for a GIOChannel is added to the event loop:
/* Define file descriptor and GIOChannel. */
int event_fd;
GIOChannel *io_channel;
/* Create file descriptor for /dev/interface and associate it with io_channel. */
event_fd = open("/dev/interface", O_RDONLY);
io_channel = g_io_channel_unix_new(event_fd);
/* Add a watch of the io_channel to the event loop. */
g_io_add_watch(io_channel, G_IO_IN | G_IO_ERR, event_callback, data);
The file /dev/interface is a placeholder for an input event interface implemented as a
file. After a file descriptor is acquired, it is assigned to io channel. The watch is created
by calling g io add watch(). The supplied argument io channel represents the GIOChannel