xtc_io(3)

---

xtc_io(3)

L1 event-notification engine

XTC_IO(3) Library Functions Manual XTC_IO(3)

xtc_io_init, xtc_io_fini, xtc_io_backend_name, xtc_io_reg_fd, xtc_io_mod_fd, xtc_io_del_fd, xtc_io_poll, xtc_io_aio_submit, xtc_io_wakeupL1 event-notification engine

#include <xtc_io.h>

int
xtc_io_init(xtc_io_t **out);

int
xtc_io_fini(xtc_io_t *io);

const char *
xtc_io_backend_name(void);

int
xtc_io_reg_fd(xtc_io_t *io, int fd, uint32_t interest, void *tag);

int
xtc_io_mod_fd(xtc_io_t *io, int fd, uint32_t interest, void *tag);

int
xtc_io_del_fd(xtc_io_t *io, int fd);

int
xtc_io_poll(xtc_io_t *io, xtc_io_event_t *events, int max, int64_t timeout_ns, int *n_out);

int
xtc_io_aio_submit(xtc_io_t *io, xtc_aio_t *a);

int
xtc_io_wakeup(xtc_io_t *io);

xtc_io is the L1 readiness-notification engine. A single xtc_io_t instance manages a set of registered file descriptors plus an internal cross-thread wakeup pipe.

Exactly one backend is compiled in per binary, picked at configure time:

The portable POSIX poll(2) backend; the floor xtc promises on every Tier 1 platform.
The Linux epoll(7) backend.

() returns the compiled-in backend's name as a static string.

The interest mask passed to ()/() combines:

Notify when the fd is readable.
Notify when the fd is writable.

The flags field of xtc_io_event_t returned from () combines:

Bytes are available to read.
Bytes can be written without blocking.
The peer closed the connection (for sockets and pipes).
An error occurred on the descriptor.
The synthetic wakeup event delivered by xtc_io_wakeup(); the event's tag is NULL.
An async file-I/O completion delivered by (); the event's tag is the submitted xtc_aio_t's tag, and its result is in that struct's res.

xtc_io_aio_submit() queues a native file operation (an xtc_aio_t: XTC_AIO_PREAD, XTC_AIO_PWRITE, or XTC_AIO_FSYNC) and returns immediately. On the io_uring backend it submits the matching IORING_OP and the completion is delivered as an XTC_IO_AIO event that wakes the tagged task, which then reads res (bytes transferred, or a negative errno). A regular file is not pollable, so on a readiness-only backend (epoll, kqueue, poll) this returns XTC_E_NOSYS and the caller offloads the operation to the blocking pool instead; xtc_aio(3) wraps both paths.

xtc_io_reg_fd() registers a file descriptor with the engine. The interest mask must be non-zero; tag is an opaque pointer returned in events. A duplicate registration returns XTC_E_INVAL; the caller must use xtc_io_mod_fd() to change interest or tag on a registered fd.

() unregisters; subsequent operations on that fd return XTC_E_INVAL.

xtc_io_poll() fills up to max events into events and writes the count to *n_out.

timeout_ns is interpreted as:

Non-blocking; return immediately.
Wait at most that many nanoseconds.
Wait indefinitely until at least one fd becomes ready or () is called.

xtc_io_wakeup() may be called from any thread. A blocked xtc_io_poll() returns within bounded time; the wakeup is delivered as a single event with XTC_IO_WAKEUP flag and NULL tag. Multiple wakeups before the next poll coalesce into one event.

XTC_OK on success; XTC_E_INVAL on bad argument; XTC_E_INTERNAL on platform failure; XTC_E_NOMEM when the backend cannot allocate registration storage.

xtc_io_wakeup() is safe to call from any thread. The other functions must be called from a single thread that owns the xtc_io_t instance (the future ).

xtc_io_t *io;
xtc_io_event_t evs[16];
int n;

xtc_io_init(&io);
xtc_io_reg_fd(io, sockfd, XTC_IO_READABLE, my_tag);
xtc_io_poll(io, evs, 16, -1, &n);
for (int i = 0; i < n; i++) {
        if (evs[i].flags & XTC_IO_WAKEUP) handle_wakeup();
        else                              handle(evs[i].tag, evs[i].flags);
}

__os_thread(3), __os_atomic(3), xtc(7)

First appeared in xtc 0.0.1 (M2).

May 25, 2026 Debian

View the mdoc source