Event Queue

Provides an Event loop.

This module offers an event queue framework like libevent or libuev.

An event queue is basically a FIFO queue of events, with some functions to efficiently and safely handle adding and getting events to / from such a queue. An event queue is bound to a thread, but any thread or ISR can put events into a queue.

An event is a structure containing a pointer to an event handler. It can be extended to provide context or arguments to the handler. It can also be embedded into existing structures (see examples).

Compared to msg or mbox, this some fundamental differences:

  1. events are “sender allocated”. Unlike msg.h::msg_send(), event.h::event_post() never blocks or fails.
  2. events contain everything necessary to handle them, thus a thread processing the events of an event queue doesn’t need to be changed in order to support new event types.
  3. events can be safely used (and actually perform best) when used within one thread, e.g., in order to create a state-machine like process flow. This is not (easily) possible using msg queues, as they might fill up.
  4. an event can only be queued in one event queue at the same time. Notifying many queues using only one event object is not possible with this imlementation.

At the core, event.h::event_wait() uses thread flags to implement waiting for events to be queued. Thus event queues can be used safely and efficiently in combination with thread flags and msg queues.

Examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// simple event handler
static void handler(event_t *event)
{
   printf("triggered 0x%08x\n", (unsigned)event);
}

static event_t event = { .handler = handler };
static event_queue_t queue;

int main(void)
{
    event_queue_init(&queue);
    event_loop(&queue);
}

[...] event_post(&queue, &event);

// example for event extended event struct
typedef struct {
    event_t super;
    const char *text;
} custom_event_t;

static void custom_handler(event_t *event)
{
    custom_event_t *custom_event = (custom_event_t *)event;
    printf("triggered custom event with text: \"%s\"\n", custom_event->text);
}

static custom_event_t custom_event = { .super.handler = custom_handler, .text = "CUSTOM EVENT" };

[...] event_post(&queue, &custom_event)

struct event event_t

event structure forward declaration

void(* event_handler_t()

event handler type definition

void event_queue_init(event_queue_t * queue)

Initialize an event queue.

This will set the calling thread as owner of queue.

Parameters

queue:event queue object to initialize

void event_post(event_queue_t * queue, event.h::event_t * event)

Queue an event.

The given event will be posted on the given queue. If the event is already queued when calling this function, the event will not be touched and remain in the previous position on the queue. So reposting an event while it is already on the queue will have no effect.

Parameters

queue:event queue to queue event in
event:event to queue in event queue

void event_cancel(event_queue_t * queue, event.h::event_t * event)

Cancel a queued event.

This will remove a queued event from an event queue.

Note

Due to the underlying list implementation, this will run in O(n).

Parameters

queue:event queue to remove event from
event:event to remove from queue

event.h::event_t * event_get(event_queue_t * queue)

Get next event from event queue, non-blocking.

In order to handle an event retrieved using this function, call event->handler(event).

Parameters

queue:event queue to get event from

Return values

  • pointer to next event
  • NULL if no event available
event.h::event_t * event_wait(event_queue_t * queue)

Get next event from event queue, blocking.

This function will block until an event becomes available.

In order to handle an event retrieved using this function, call event->handler(event).

Parameters

queue:event queue to get event from

Return values

  • pointer to next event
void event_loop(event_queue_t * queue)

Simple event loop.

This function will forever sit in a loop, waiting for events to be queued and executing their handlers.

It is pretty much defined as:

1
2
3
while ((event = event_wait(queue))) {
    event->handler(event);
}

Parameters

queue:event queue to process

THREAD_FLAG_EVENT

Thread flag use to notify available events in an event queue.

1
(0x1)
EVENT_QUEUE_INIT

event_queue_t static initializer

1
{ .waiter = (thread_t *)sched_active_thread }
struct event

event structure

clist.h::clist_node_t list_node

event queue list entry

event.h::event_handler_t handler

pointer to event handler function

struct event_queue_t

event queue structure

clist.h::clist_node_t event_list

list of queued events

sched.h::thread_t * waiter

thread ownning event queue