Events

Overview

Events are the primary way modules communicate. Each event has a universal structure with a type field, so any module can inspect any event without knowing its origin.

The payload of an event is a buffer_t of arbitrary size. The structure of the buffer data is defined by the event type. Gantry comes with built-in events, but applications and other modules are free to defined additional event types, see Defining Events.

Usage

Events are allocated in memory blocks. Events can be referenced counted. They are freed when the reference count reaches zero.

event_t* event = NULL;
EVENT_ALLOC(&my_event_type, sizeof(struct my_payload), &event);

struct my_payload* payload = (struct my_payload*)event->data.buf;
payload->value = 123;

EVENT_REF(event); // Increment reference count
EVENT_UNREF(&event); // Decrement reference count
EVENT_UNREF(&event); // Free

Events follow the same memory management rules that apply to memory blocks, see Memory Leak Detection.

Linking Events

There may be times where multiple events belong together. Events contain a next_event field such that events can be chained together. Reference counting an event also applies the operation to events in the chain.

Defining Events

To create you own event, declare an event type in a header and define it in the corresponding source file. Event IDs are automatically checked for collisions at link time.

// my_module.h
#define EVENT_ID_MY_EVENT 42

DECLARE_EVENT_TYPE(my_event_type);

// my_module.c
DEFINE_EVENT_TYPE(EVENT_ID_MY_EVENT, my_event_type, NULL);

Releasing a Payload

If the payload contains a reference-counted data, define an on_free callback to release it when the event is freed. on_free is called when an event is about to be freed. This allows freed events to automatically dereference owned data.

void my_on_free(event_t* event)
{
    struct my_payload* payload = (struct my_payload*)event->data.buf;
    MEM_UNREF(&payload->data_block);
}

DEFINE_EVENT_TYPE(42, my_event_type, my_on_free);

API Reference

typedef void (*event_on_free_t)(event_t *event)

Function called before an event is freed.

Param event:

The event being freed

int event_alloc(const event_type_t *type, size_t payload_size, event_t **event_ptr)

Allocate an event.

An event will be allocated based on the requested size.

Note

It is recommended that you always use the EVENT_ALLOC macro which calls this function with the debug information filled in.

Parameters:
  • type[in] The type of the event

  • payload_size[in] The requested event payload size in bytes

  • event_ptr[out] Pointer to be populated with the address of an event. This pointer must point to a NULL pointer when this function is called. It is only populated when the allocation succeeds.

Returns:

result of mem_alloc

void event_ref(event_t *event)

Increment the reference count of an event and all linked events.

Note

It is recommended that you always use the EVENT_REF macro which calls this function with the debug information filled in.

Parameters:

event[in] The event pointer to be reference counted

void event_unref(event_t **event_ptr)

Dencrement the reference count of an event and all linked events.

Note

It is recommended that you always use the EVENT_UNREF macro which calls this function with the debug information filled in.

Note

If event_ptr already points to a NULL pointer, this function will assume that the event was already freed and do nothing.

Parameters:

event_ptr[inout] A pointer to the event pointer to be dereferenced. If the reference count reaches 0, the event pointer will be set to NULL.

void event_init(event_t *event, const event_type_t *type, size_t payload_size)

Initialize an event structure.

If there is a need to initialize an event in a pre-existing memory block, this helper can be used.

Note

The size is only the length of the event data buffer. When initializing in a memory block ensure the size needed to hold the event header is taken into account.

Parameters:
  • event[inout] Pointer to the event structure to initialize

  • type[in] The type of the event

  • payload_size[in] Size of the event buffer

DECLARE_EVENT_TYPE(_name)

Declare a custom event_type_t to be used by other modules. The event must be defined using DEFINE_EVENT_TYPE in the corresponding source file.

DEFINE_EVENT_TYPE(_id, _name, _on_free)

Define an event_type_t. Event IDs will automatically be checked for collisions.

EVENT_ALLOC(type, payload_size, event_ptr)

Convenience macro for event_alloc with memory tracing.

EVENT_REF(event)

Convenience macro for event_ref with memory tracing.

EVENT_UNREF(event)

Convenience macro for event_unref with memory tracing.

struct event_type_t
#include <event.h>

Event type.

Applications can define event types using DEFINE_EVENT_TYPE. Event types may contain reference counted memory in the payload. In this case on_free should be defined to dereference the event payload when the event is freed.

struct event_t
#include <event.h>

Universal event structure.

STACK_BUFFER(name, size)

Creates a buffer on the stack of a specified size.

struct buffer_t
#include <buffer.h>

Buffer with length.

Used to store data of a variable length. The buffer data is aligned so that it can be interpreted as custom types or structs.