xtc_loop(3)
---xtc_loop(3)
L2 single-thread event loop, tasks, wakers, timers
| XTC_LOOP(3) | Library Functions Manual | XTC_LOOP(3) |
NAME
xtc_loop_init,
xtc_loop_fini, xtc_loop_run,
xtc_loop_stop, xtc_loop_res,
xtc_task_spawn,
xtc_task_waker,
xtc_task_park_on_timer,
xtc_task_park_on_fd,
xtc_waker_wake,
xtc_timer_set,
xtc_timer_cancel — L2
single-thread event loop, tasks, wakers, timers
SYNOPSIS
#include
<xtc_loop.h>
int
xtc_loop_init(xtc_loop_t
**out);
int
xtc_loop_fini(xtc_loop_t
*loop);
int
xtc_loop_run(xtc_loop_t
*loop);
int
xtc_loop_stop(xtc_loop_t
*loop);
struct xtc_res *
xtc_loop_res(xtc_loop_t
*loop);
int
xtc_task_spawn(xtc_loop_t
*loop, xtc_task_fn
fn, void *user,
xtc_task_t
**out_task);
int
xtc_task_waker(xtc_task_t
*task, xtc_waker_t
*out);
int
xtc_task_park_on_timer(xtc_task_t
*self, int64_t
delay_ns);
int
xtc_task_park_on_fd(xtc_task_t
*self, int fd,
uint32_t interest);
int
xtc_waker_wake(const
xtc_waker_t *w);
int
xtc_timer_set(xtc_loop_t
*loop, int64_t
delay_ns, xtc_timer_fn
fn, void *user,
xtc_timer_t **out);
int
xtc_timer_cancel(xtc_timer_t
*timer);
DESCRIPTION
The L2 event loop drives a single OS thread. A loop owns one xtc_io_t, a FIFO run queue of ready tasks, and a min-heap of pending timers.
A task is a small struct carrying a function pointer, a state, and an opaque user pointer. The function is called by the loop whenever the task becomes runnable; its return value tells the loop what to do next:
XTC_TASK_DONE- The task is finished and is reaped at
xtc_loop_fini(). XTC_TASK_RESCHED- Re-queue the task at the back of the run queue.
XTC_TASK_PENDING- The task is waiting on a wakeup; do not run it again until either its waker fires or the timer / fd it parked on becomes ready.
LIFECYCLE
xtc_loop_init()
allocates a fresh loop with no spawned tasks. Each loop owns a resource
accountant (xtc_res_t) with default caps; access it
via
xtc_loop_res().
xtc_loop_run()
runs until every spawned task has returned
XTC_TASK_DONE and every pending timer has fired or
been cancelled.
xtc_loop_stop()
flips a flag that causes the loop to return after the current task step
completes.
xtc_loop_fini()
frees every task ever spawned, every timer ever created (live or fired), the
loop's xtc_io_t, and the loop struct itself.
TASKS
xtc_task_spawn()
creates a new task in XTC_TASK_RESCHED state and
enqueues it. The function pointer fn is invoked with
the task handle and the user pointer the caller
supplied at spawn. The handle written to *out_task is
valid for the lifetime of the loop.
WAKERS
xtc_task_waker()
fills a xtc_waker_t that the caller may store and
later use to re-queue the parked task via
xtc_waker_wake().
A waker may be fired any number of times: only the first transition from
XTC_TASK_PENDING to
XTC_TASK_RESCHED re-queues the task; subsequent
wakes while the task is already scheduled or running are no-ops. A waker
fired after the task has reached XTC_TASK_DONE is a
safe no-op.
M3 wakers are valid only on the owning thread. Cross-thread wakeup arrives in M5.
PARKING
xtc_task_park_on_timer()
arranges for the task to be re-queued after at least
delay_ns nanoseconds.
xtc_task_park_on_fd()
registers the task with the loop's xtc_io_t for
readiness on fd. When the fd becomes ready, the loop
unregisters it and re-queues the task.
A task may have at most one outstanding park (timer or fd) at a
time. A second park while the first is in flight returns
XTC_E_INVAL. After parking, the task fn must return
XTC_TASK_PENDING.
TIMERS
xtc_timer_set()
schedules a callback to fire after at least delay_ns
nanoseconds. The handle written to *out remains valid
for the lifetime of the loop, including after the timer has fired (see
xtc_timer_cancel()).
xtc_timer_cancel()
prevents a not-yet-fired timer from firing. A cancel after the timer has
already fired is a safe no-op.
RETURN VALUES
XTC_OK on success;
XTC_E_INVAL on a bad argument;
XTC_E_NOMEM on allocation failure;
XTC_E_INTERNAL on platform failure.
THREAD SAFETY
M3 is single-thread. A loop must be created, run, and finalised by the same OS thread. The cross-thread wakeup primitive baked into xtc_io_t exists but is not yet exposed at the loop / task level; that arrives with the multi-loop executor in M5.
EXAMPLES
static int hello(xtc_task_t *self, void *u) {
(void)self; (void)u;
printf("hello\n");
return XTC_TASK_DONE;
}
int main(void) {
xtc_loop_t *loop;
xtc_loop_init(&loop);
xtc_task_spawn(loop, hello, NULL, NULL);
xtc_loop_run(loop);
xtc_loop_fini(loop);
return 0;
}
SEE ALSO
HISTORY
First appeared in xtc 0.0.1 (M3).
| May 25, 2026 | Debian |