Event Primitives – AxlEvent, AxlCancellable, AxlWait

The foundational synchronization primitives. All three compose: an AxlCancellable is an AxlEvent with stop-token semantics; the wait helpers drive a throwaway AxlLoop until an event fires, a condition holds, a timeout elapses, or Ctrl-C is received.

  • AxlEvent – one-shot latch wrapping a UEFI event. Replaces the older AxlCompletion (same mechanical behavior, UEFI-native name).

  • AxlCancellable – typed stop token shared across async ops; cancel it once and every op observing it aborts with AXL_CANCELLED.

  • AxlWait – interruptible wait helpers (axl_wait_for, axl_wait_for_flag, axl_wait_ms, …) built on AxlLoop.

A note on naming: “event” appears three times in AXL docs – the event loop (the dispatcher), an event source (a thing registered with the loop), and AxlEvent (one kind of source). UEFI carries the same overload; an AxlEvent is a one-shot latch backed by a UEFI event, and the event loop dispatches them.

Headers: <axl/axl-event.h>, <axl/axl-cancellable.h>, <axl/axl-wait.h>.

API Reference

AxlEvent

Defines

axl_event_new()

Captures the caller’s file/line for leak reporting via the tier-1 resource registry. See docs/AXL-Runtime.md §4.2.1.

Typedefs

typedef struct AxlEvent AxlEvent
typedef struct AxlCancellable AxlCancellable
typedef void *AxlEventHandle

AxlEventHandle:

Raw UEFI event handle (EFI_EVENT). Used where firmware owns the event — protocol completion tokens, protocol-notify events. For AXL-managed events use AxlEvent and pass axl_event_handle(e) where a handle is required (e.g., axl_loop_add_event).

Functions

AxlEvent *axl_event_new_impl(const char *file, int line)

Create a new, unsignalled event.

Returns:

new AxlEvent, or NULL on failure. Free with axl_event_free().

void axl_event_free(AxlEvent *e)

Free an event. NULL-safe.

Parameters:
  • e – event (NULL-safe)

void axl_event_signal(AxlEvent *e)

Signal the event. Idempotent, NULL-safe.

Safe from any context — protocol notifications, nested callbacks, interrupt-like handlers.

Parameters:
  • e – event (NULL-safe)

void axl_event_reset(AxlEvent *e)

Reset the event to an unsignalled state. NULL-safe.

Drops any pending signal so the same event can be reused across multiple wait cycles.

Parameters:
  • e – event (NULL-safe)

bool axl_event_is_set(const AxlEvent *e)

Fast check: is this event currently signalled?

Reads an internal flag without driving the loop. Transitions:

  • axl_event_signal(e) → is_set becomes true

  • axl_event_reset(e) → is_set becomes false

  • successful axl_event_wait[_timeout] → is_set becomes false (the wait consumed the signal via CheckEvent in the loop dispatch; the flag mirrors the backend state)

For the full wait-for-signal behavior with timeout and cancel support, use axl_event_wait_timeout().

Parameters:
  • e – event (NULL-safe)

Returns:

true between signal and the next reset / successful wait, else false. Returns false for NULL.

AxlEventHandle axl_event_handle(const AxlEvent *e)

Get the raw UEFI event handle wrapped by this AxlEvent.

Used when registering the event with the loop via axl_loop_add_event, which takes a handle so the same entry point serves AXL-managed events and firmware-owned ones alike.

Parameters:
  • e – event (NULL-safe, returns NULL)

Returns:

the wrapped handle, or NULL for NULL / uninitialized.

int axl_event_wait(AxlEvent *e, AxlCancellable *cancel)

Wait indefinitely for the event to be signalled.

The CPU idles between events. Returns early on Ctrl-C or a signalled cancellable. Equivalent to axl_event_wait_timeout(e, cancel, 0).

Parameters:
  • e – event

  • cancel – optional cancel token (NULL = only Ctrl-C)

Returns:

0 on signal, -1 on invalid arg, AXL_CANCELLED on Ctrl-C or cancel.

int axl_event_wait_timeout(AxlEvent *e, AxlCancellable *cancel, uint64_t timeout_us)

Wait for the event with a timeout.

The CPU idles between events. A timeout_us of 0 means wait forever. Returns early on Ctrl-C or a signalled cancellable.

Parameters:
  • e – event

  • cancel – optional cancel token

  • timeout_us – timeout in microseconds (0 = forever)

Returns:

0 on signal, -1 on timeout or invalid arg, AXL_CANCELLED on Ctrl-C or cancel.

AxlCancellable

Defines

axl_cancellable_new()

Captures the caller’s file/line for leak reporting via the tier-1 resource registry. See docs/AXL-Runtime.md §4.2.1.

Typedefs

typedef struct AxlCancellable AxlCancellable

Functions

AxlCancellable *axl_cancellable_new_impl(const char *file, int line)

Create a new, unsignalled cancellable.

Returns:

new AxlCancellable, or NULL on failure. Free with axl_cancellable_free().

void axl_cancellable_free(AxlCancellable *c)

Free a cancellable. NULL-safe.

Must only be called after every async op that observes this cancellable has completed (via its callback) or is otherwise no longer holding a reference. Freeing while an op still references it results in a dangling event handle.

Parameters:
  • c – cancellable (NULL-safe)

void axl_cancellable_cancel(AxlCancellable *c)

Cancel every async op currently observing this cancellable.

Idempotent — calling more than once is safe and has no additional effect. Safe to call from any context (protocol notifications, nested callbacks). NULL-safe.

Parameters:
  • c – cancellable (NULL-safe)

bool axl_cancellable_is_cancelled(const AxlCancellable *c)

Check whether the cancellable has been signalled.

Parameters:
  • c – cancellable (NULL-safe)

Returns:

true if axl_cancellable_cancel() was called, else false. Returns false for NULL.

void axl_cancellable_reset(AxlCancellable *c)

Reset the cancellable to an unsignalled state. NULL-safe.

Drops any pending cancel signal so the same cancellable can be reused for a fresh batch of async ops. Only call once all ops that might have observed the prior signal have completed.

Parameters:
  • c – cancellable (NULL-safe)

AxlWait

Typedefs

typedef struct AxlCancellable AxlCancellable
typedef bool (*AxlCondFn)(void *ctx)

AxlCondFn:

Condition predicate. Returns true when the wait should end.

typedef void (*AxlTickFn)(void *ctx)

AxlTickFn:

Periodic side-effect called between waits. Typical use is to drive a UEFI protocol state machine forward (e.g. call protocol->Poll) so the condition can become true.

Functions

void axl_sleep(uint64_t seconds)

Sleep for the specified number of seconds. CPU idles; Ctrl-C returns early.

void axl_msleep(uint64_t milliseconds)

Sleep for the specified number of milliseconds. CPU idles; Ctrl-C returns early.

void axl_usleep(uint64_t microseconds)

Sleep for the specified number of microseconds (rounded up to ms granularity). CPU idles; Ctrl-C returns early.

int axl_wait_for_flag(volatile const bool *flag, AxlCancellable *cancel, uint64_t timeout_us)

Wait until *flag becomes true, with optional cancel + timeout.

CPU idles between 1ms checks. Returns 0 immediately if *flag is already true, or AXL_CANCELLED if cancel was already signalled.

Parameters:
  • flag – flag to observe

  • cancel – optional cancel token (NULL = only Ctrl-C)

  • timeout_us – timeout in microseconds (0 = forever)

Returns:

0 on true, -1 on timeout or invalid arg, AXL_CANCELLED on Ctrl-C or an observed cancellable.

int axl_wait_for_word(volatile const uint64_t *word, uint64_t not_ready_value, AxlCancellable *cancel, uint64_t timeout_us)

Wait until *word stops matching not_ready_value.

Covers UEFI completion-token Status polls, DMA flags, and any “keep checking this memory word until it changes” pattern. CPU idles between 1ms checks.

Parameters:
  • word – memory word to observe

  • not_ready_value – value that means “keep waiting”

  • cancel – optional cancel token

  • timeout_us – timeout in microseconds (0 = forever)

Returns:

0 on change, -1 on timeout or invalid arg, AXL_CANCELLED on Ctrl-C or an observed cancellable.

int axl_wait_ms(AxlCancellable *cancel, uint64_t ms)

Interruptible sleep with cancellable support.

The long form of axl_msleep &#8212; use this when you need to inspect the return code (Ctrl-C vs elapsed) or pass a shared AxlCancellable. The CPU idles for the duration.

Parameter order note: the rest of the wait family places cancel between the subject and the timeout. Sleep has no subject, so cancel comes first. The relative position (cancel immediately before the duration/timeout) is consistent with the other helpers.

Parameters:
  • cancel – optional cancel token (NULL = only Ctrl-C)

  • ms – milliseconds to sleep (0 returns immediately)

Returns:

0 on elapsed, AXL_CANCELLED on Ctrl-C or cancel.

int axl_wait_for(AxlCondFn cond_fn, void *cond_ctx, AxlCancellable *cancel, uint64_t timeout_us)

Wait until cond_fn returns true, with timeout + optional cancel.

cond_fn is evaluated immediately and then every 1ms. CPU idles between evaluations.

Parameters:
  • cond_fn – predicate

  • cond_ctx – opaque context passed to cond_fn

  • cancel – optional cancel token

  • timeout_us – timeout in microseconds (0 = forever)

Returns:

0 on cond_fn true, -1 on timeout or invalid arg, AXL_CANCELLED on Ctrl-C or cancel.

int axl_wait_for_with_tick(AxlCondFn cond_fn, void *cond_ctx, AxlTickFn tick_fn, void *tick_ctx, uint64_t tick_us, AxlCancellable *cancel, uint64_t timeout_us)

Wait until cond_fn returns true, running tick_fn each period.

cond_fn is evaluated immediately and then each time tick_fn runs. Use this form when the condition only becomes true after an external state machine is advanced (e.g. calling protocol->Poll on a UEFI driver).

Parameters:
  • cond_fn – predicate (required)

  • cond_ctx – opaque context for cond_fn

  • tick_fn – periodic side-effect (may be NULL)

  • tick_ctx – opaque context for tick_fn

  • tick_us – tick period in microseconds (minimum 1ms)

  • cancel – optional cancel token

  • timeout_us – timeout in microseconds (0 = forever)

Returns:

0 on cond_fn true, -1 on timeout or invalid arg, AXL_CANCELLED on Ctrl-C or cancel.