xtc_loop(3)

---

xtc_loop(3)

L2 single-thread event loop, tasks, wakers, timers

XTC_LOOP(3) Library Functions Manual XTC_LOOP(3)

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_cancelL2 single-thread event loop, tasks, wakers, timers

#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);

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:

The task is finished and is reaped at ().
Re-queue the task at the back of the run queue.
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.

() allocates a fresh loop with no spawned tasks. Each loop owns a resource accountant (xtc_res_t) with default caps; access it via ().

() runs until every spawned task has returned XTC_TASK_DONE and every pending timer has fired or been cancelled. () flips a flag that causes the loop to return after the current task step completes.

() frees every task ever spawned, every timer ever created (live or fired), the loop's xtc_io_t, and the loop struct itself.

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

() fills a xtc_waker_t that the caller may store and later use to re-queue the parked task via (). 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.

() arranges for the task to be re-queued after at least delay_ns nanoseconds.

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

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

() prevents a not-yet-fired timer from firing. A cancel after the timer has already fired is a safe no-op.

XTC_OK on success; XTC_E_INVAL on a bad argument; XTC_E_NOMEM on allocation failure; XTC_E_INTERNAL on platform failure.

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.

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;
}

xtc_io(3), __os_thread(3), __os_time(3), xtc(7)

First appeared in xtc 0.0.1 (M3).

May 25, 2026 Debian

View the mdoc source