xtc_accel(3)

---

xtc_accel(3)

park a fiber on a GPU/NPU completion; enumerate accelerators

XTC_ACCEL(3) Library Functions Manual XTC_ACCEL(3)

xtc_accel_probe, xtc_accel_wait_fence, xtc_accel_run_blockingpark a fiber on a GPU/NPU completion; enumerate accelerators

#include <xtc.h>
#include <xtc_accel.h>

int
xtc_accel_probe(xtc_accel_dev_t *out, int max, int *out_n);

int
xtc_accel_wait_fence(int fence_fd, int64_t timeout_ns);

int
xtc_accel_run_blocking(int (*fn)(void *), void *arg, int *out_result);

An accelerator -- a GPU or an NPU (neural / vision processing unit, also called a VPU) -- is, at the layer a concurrency runtime cares about, an asynchronous I/O device: the caller submits an opaque command buffer or compiled graph, the coprocessor runs it, and it signals completion through a fence. On Linux both device kinds are DRM devices (/dev/dri/renderD* for a render GPU, /dev/accel/accel* for an NPU) whose completions are the same kernel object -- a dma-fence exported as a pollable sync_file file descriptor, the identical readiness event the loop already multiplexes for sockets and pipes. A GPU fence fd and an NPU fence fd are indistinguishable to poll(2), so they are handled by one API here.

The xtc_accel facility does exactly one thing: it parks the calling fiber on such a completion and wakes it when the device is done. It is a tensor library, a device-memory allocator, or a vendor-SDK portability layer. libxtc links no GPU/NPU runtime (Level(Zero), CUDA, Vulkan, OpenVINO, ...): the consumer links whichever runtime drives the device, submits the work, and hands xtc_accel_probe the resulting fence fd. The abstraction stops at the fence; submission and the compute itself live above it.

() enumerates the accelerator devices present on the host into out[0 ..max], writing the total number found to *out_n (which may exceed max if the buffer was too small; only the first max are written). Each xtc_accel_dev_t reports a kind (XTC_ACCEL_KIND_GPU or XTC_ACCEL_KIND_NPU), a short name, the device node path, and the backing kernel driver name if cheaply known (for example ‘xe’ or ‘intel_vpu’). These are for device selection and observability by the consumer and its runtime; libxtc opens none of them. The device kind is a tag only -- it never changes how a fence is waited on. Probing opens and submits nothing.

() parks the calling fiber until the completion fence fence_fd signals or timeout_ns elapses (negative waits forever). The fence fd is a pollable sync_file the consumer's runtime produced when it submitted work (from a Level(Zero) event or fence, an exported DRM sync object, a VK_KHR_external_fence_fd Vulkan fence, a CUDA event bridged to an eventfd(2), and so on). While waiting the fiber holds no OS thread -- the wait rides the loop's normal readiness path via xtc_proc_wait_fd(3). libxtc does not own, duplicate, or close fence_fd; the caller retains ownership. It must be called from within a fiber.

() runs the synchronous accelerator call fn(arg) on the xtc_blocking(3) thread pool, parking the calling fiber until it returns and storing fn's return value in *out_result (may be NULL). It is the fallback for runtimes that expose only a blocking submit-and-wait with no pollable fence. It holds one pool thread for the duration of fn, so it suits coarse-grained inference rather than thousands of tiny operations per second; prefer xtc_accel_wait_fence() when a fence fd is available.

xtc_accel_probe() returns XTC_OK on success, including when zero devices are found (absence is not an error), or XTC_E_INVAL on a bad argument.

xtc_accel_wait_fence() returns XTC_OK when the fence signals, XTC_E_AGAIN on timeout (the fence never fired), XTC_E_INVAL on a bad file descriptor, or XTC_E_NOSYS when the library was built without accelerator support.

xtc_accel_run_blocking() returns XTC_OK (fn ran; see *out_result), XTC_E_INVAL for a NULL fn, or an xtc_blocking(3) error if the work could not be dispatched. It works regardless of whether accelerator support was built in.

Accelerator support is selected at configure time with --with-accel=auto|yes|no (default auto: enabled where the Linux DRM/accel subsystem is present). When it is not built in, () reports zero devices and xtc_accel_wait_fence() returns XTC_E_NOSYS, following the same “always linkable, NOSYS when unsupported” convention as the TLS and cryptography modules; xtc_accel_run_blocking() is unaffected.

xtc_blocking(3), xtc_proc(3), xtc_io(3)

The xtc_accel facility appeared in libxtc 1.30.

July 23, 2026 Debian

View the mdoc source