Loading...
Searching...
No Matches
Event Queue

Provides an Event loop. More...

Detailed Description

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. In most cases, the owning thread of a queue is set during the queue's initialization. But it is also possible to initialize a queue in a detached state from a different context and to set the owning thread at a later point of time using the event_queue_claim() function.

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_send(), 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 implementation.

At the core, 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:

// 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_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 = container_of(event, custom_event_t, super);
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.super)
#define container_of(PTR, TYPE, MEMBER)
Returns the container of a pointer to a member.
Definition container.h:62
#define printf(...)
A wrapper for the printf() function that passes arguments through unmodified, but fails to compile if...
Definition stdio.h:60
void event_post(event_queue_t *queue, event_t *event)
Queue an event.
static void event_loop(event_queue_t *queue)
Simple event loop.
Definition event.h:463
static void event_queue_init(event_queue_t *queue)
Initialize an event queue.
Definition event.h:187
event queue structure
Definition event.h:156
event structure
Definition event.h:148
event_handler_t handler
pointer to event handler function
Definition event.h:150

Files

file  event.h
 Event API.
 
file  callback.h
 Provides a callback-with-argument event type.
 
file  periodic.h
 Provides functionality to trigger periodic events.
 
file  periodic_callback.h
 Provides functionality to trigger periodic event callbacks.
 
file  source.h
 Provides functionality to trigger multiple events at once.
 
file  thread.h
 Provides utility functions for event handler threads.
 
file  timeout.h
 Provides functionality to trigger events after timeout.
 

Data Structures

struct  event
 event structure More...
 
struct  PTRTAG
 event queue structure More...
 

Macros

#define THREAD_FLAG_EVENT   (0x1)
 Thread flag use to notify available events in an event queue.
 
#define EVENT_QUEUE_INIT   { .waiter = thread_get_active() }
 event_queue_t static initializer
 
#define EVENT_QUEUE_INIT_DETACHED   { .waiter = NULL }
 static initializer for detached event queues
 

Typedefs

typedef struct event event_t
 event structure forward declaration
 
typedef void(* event_handler_t) (event_t *)
 event handler type definition
 
typedef struct PTRTAG event_queue_t
 event queue structure
 

Functions

static void event_queues_init (event_queue_t *queues, size_t n_queues)
 Initialize an array of event queues.
 
static void event_queue_init (event_queue_t *queue)
 Initialize an event queue.
 
static void event_queues_init_detached (event_queue_t *queues, size_t n_queues)
 Initialize an array of event queues not binding it to a thread.
 
static void event_queue_init_detached (event_queue_t *queue)
 Initialize an event queue not binding it to a thread.
 
static void event_queues_claim (event_queue_t *queues, size_t n_queues)
 Bind an array of event queues to the calling thread.
 
static void event_queue_claim (event_queue_t *queue)
 Bind an event queue to the calling thread.
 
void event_post (event_queue_t *queue, event_t *event)
 Queue an event.
 
void event_cancel (event_queue_t *queue, event_t *event)
 Cancel a queued event.
 
bool event_is_queued (const event_queue_t *queue, const event_t *event)
 Check if an event is already queued.
 
event_tevent_get (event_queue_t *queue)
 Get next event from event queue, non-blocking.
 
event_tevent_wait_multi (event_queue_t *queues, size_t n_queues)
 Get next event from the given event queues, blocking.
 
static event_tevent_wait (event_queue_t *queue)
 Get next event from event queue, blocking.
 
event_tevent_wait_timeout (event_queue_t *queue, uint32_t timeout)
 Get next event from event queue, blocking until timeout expires.
 
event_tevent_wait_timeout64 (event_queue_t *queue, uint64_t timeout)
 Get next event from event queue, blocking until timeout expires.
 
event_tevent_wait_timeout_ztimer (event_queue_t *queue, ztimer_clock_t *clock, uint32_t timeout)
 Get next event from event queue, blocking until timeout expires.
 
static void event_loop_multi (event_queue_t *queues, size_t n_queues)
 Simple event loop with multiple queues.
 
static void event_loop (event_queue_t *queue)
 Simple event loop.
 
void event_sync (event_queue_t *queue)
 Synchronize with the last event on the queue.
 

Macro Definition Documentation

◆ EVENT_QUEUE_INIT

#define EVENT_QUEUE_INIT   { .waiter = thread_get_active() }

event_queue_t static initializer

Definition at line 128 of file event.h.

◆ EVENT_QUEUE_INIT_DETACHED

#define EVENT_QUEUE_INIT_DETACHED   { .waiter = NULL }

static initializer for detached event queues

Definition at line 133 of file event.h.

◆ THREAD_FLAG_EVENT

#define THREAD_FLAG_EVENT   (0x1)

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

Definition at line 122 of file event.h.

Typedef Documentation

◆ event_handler_t

typedef void(* event_handler_t) (event_t *)

event handler type definition

Definition at line 143 of file event.h.

◆ event_t

typedef struct event event_t

event structure forward declaration

Definition at line 138 of file event.h.

Function Documentation

◆ event_cancel()

void event_cancel ( event_queue_t queue,
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
[in]queueevent queue to remove event from
[in]eventevent to remove from queue

◆ event_get()

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
[in]queueevent queue to get event from
Returns
pointer to next event
NULL if no event available

◆ event_is_queued()

bool event_is_queued ( const event_queue_t queue,
const event_t event 
)

Check if an event is already queued.

Parameters
[in]queueevent queue to check
[in]eventevent to check
Returns
true if event is in queue
false otherwise

◆ event_loop()

static void event_loop ( event_queue_t queue)
inlinestatic

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:

while ((event = event_wait(queue))) {
event->handler(event);
}
static event_t * event_wait(event_queue_t *queue)
Get next event from event queue, blocking.
Definition event.h:354
Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queueevent queue to process

Definition at line 463 of file event.h.

◆ event_loop_multi()

static void event_loop_multi ( event_queue_t queues,
size_t  n_queues 
)
inlinestatic

Simple event loop with multiple queues.

This function will forever sit in a loop, waiting for events to be queued and executing their handlers. If more than one queue contains an event, the queue with the lowest index is chosen. Thus, a lower index in the queues array translates into a higher priority of the queue.

It is pretty much defined as:

while ((event = event_wait_multi(queues, n_queues))) {
event->handler(event);
}
event_t * event_wait_multi(event_queue_t *queues, size_t n_queues)
Get next event from the given event queues, blocking.
See also
event_wait_multi
Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queuesEvent queues to process
[in]n_queuesNumber of queues passed with queues

Definition at line 435 of file event.h.

◆ event_post()

void event_post ( event_queue_t queue,
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.

Precondition
queue should be initialized
Parameters
[in]queueevent queue to queue event in
[in]eventevent to queue in event queue

◆ event_queue_claim()

static void event_queue_claim ( event_queue_t queue)
inlinestatic

Bind an event queue to the calling thread.

This function must only be called once and only if the given queue is not yet bound to a thread.

Precondition
(queue->waiter == NULL)
Parameters
[out]queueevent queue object to bind to a thread

Definition at line 248 of file event.h.

◆ event_queue_init()

static void event_queue_init ( event_queue_t queue)
inlinestatic

Initialize an event queue.

This will set the calling thread as owner of queue.

Parameters
[out]queueevent queue object to initialize

Definition at line 187 of file event.h.

◆ event_queue_init_detached()

static void event_queue_init_detached ( event_queue_t queue)
inlinestatic

Initialize an event queue not binding it to a thread.

Parameters
[out]queueevent queue object to initialize

Definition at line 212 of file event.h.

◆ event_queues_claim()

static void event_queues_claim ( event_queue_t queues,
size_t  n_queues 
)
inlinestatic

Bind an array of event queues to the calling thread.

This function must only be called once and only if the given queue is not yet bound to a thread.

Precondition
(queues[i].waiter == NULL for i in {0, ..., n_queues - 1})
Parameters
[out]queuesevent queue objects to bind to a thread
[in]n_queuesnumber of queues in queues

Definition at line 228 of file event.h.

◆ event_queues_init()

static void event_queues_init ( event_queue_t queues,
size_t  n_queues 
)
inlinestatic

Initialize an array of event queues.

This will set the calling thread as owner of each queue in queues.

Parameters
[out]queuesevent queue objects to initialize
[in]n_queuesnumber of queues in queues

Definition at line 169 of file event.h.

◆ event_queues_init_detached()

static void event_queues_init_detached ( event_queue_t queues,
size_t  n_queues 
)
inlinestatic

Initialize an array of event queues not binding it to a thread.

Parameters
[out]queuesevent queue objects to initialize
[in]n_queuesnumber of queues in queues

Definition at line 198 of file event.h.

◆ event_sync()

void event_sync ( event_queue_t queue)

Synchronize with the last event on the queue.

Blocks until the last event on the queue at the moment of calling this is processed.

Warning
May not be called from the event queue, as it would block forever.
If the queue has no waiter, this will block until the queue is claimed. See event_queue_claim()
Parameters
[in]queueevent queue to sync with

Usage example:

event_post(queue, my_event);
// When event_sync() returns, my_event will have been processed.
event_sync(queue);
void event_sync(event_queue_t *queue)
Synchronize with the last event on the queue.

◆ event_wait()

static event_t * event_wait ( event_queue_t queue)
inlinestatic

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

Warning
There can only be a single waiter on a queue!
Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queueevent queue to get event from
Returns
pointer to next event

Definition at line 354 of file event.h.

◆ event_wait_multi()

event_t * event_wait_multi ( event_queue_t queues,
size_t  n_queues 
)

Get next event from the given event queues, blocking.

This function will block until an event becomes available. If more than one queue contains an event, the queue with the lowest index is chosen. Thus, a lower index in the queues array translates into a higher priority of the queue.

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

Warning
There can only be a single waiter on a queue!
Note
This function can be suitable for having a single thread handling both real-time and non-real-time events. However, a real time event can be delayed for the whole duration a single non-real-time event takes (in addition to all other sources of latency). Thus, the slowest to handle non-real-time event must still execute fast enough to add an amount of latency (on top of other sources of latency) that is acceptable to the real-time event with the strictest requirements.
Precondition
0 < n_queues (expect blowing assert() otherwise)
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queuesArray of event queues to get event from
[in]n_queuesNumber of event queues passed in queues
Returns
pointer to next event

◆ event_wait_timeout()

event_t * event_wait_timeout ( event_queue_t queue,
uint32_t  timeout 
)

Get next event from event queue, blocking until timeout expires.

Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queuequeue to query for an event
[in]timeoutmaximum time to wait for an event to be posted in us
Returns
pointer to next event if event was taken from the queue
NULL if timeout expired before an event was posted

◆ event_wait_timeout64()

event_t * event_wait_timeout64 ( event_queue_t queue,
uint64_t  timeout 
)

Get next event from event queue, blocking until timeout expires.

Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queuequeue to query for an event
[in]timeoutmaximum time to wait for an event to be posted in us
Returns
pointer to next event if event was taken from the queue
NULL if timeout expired before an event was posted

◆ event_wait_timeout_ztimer()

event_t * event_wait_timeout_ztimer ( event_queue_t queue,
ztimer_clock_t clock,
uint32_t  timeout 
)

Get next event from event queue, blocking until timeout expires.

This function is the same as event_wait_timeout() with the difference that it uses ztimer instead of xtimer as timer backend.

Precondition
The queue must have a waiter (i.e. it should have been claimed, or initialized using event_queue_init, event_queues_init)
Parameters
[in]queuequeue to query for an event
[in]clockztimer clock to use
[in]timeoutmaximum time to wait for an event, time unit depends on the used ztimer clock
Returns
pointer to next event if event was taken from the queue
NULL if timeout expired before an event was posted