xtc_osproc(3)

---

xtc_osproc(3)

OS-process spawn, control socket, and lifecycle

XTC_OSPROC(3) Library Functions Manual XTC_OSPROC(3)

xtc_osproc_spawn, xtc_osproc_isolated_spawn, xtc_osproc_pid, xtc_osproc_ctrl_fd, xtc_osproc_signal, xtc_osproc_call, xtc_osproc_serve, xtc_osproc_try_wait, xtc_osproc_wait, xtc_osproc_destroyOS-process spawn, control socket, and lifecycle

#include <xtc.h>
#include <xtc_osproc.h>

int
xtc_osproc_spawn(const xtc_osproc_opts_t *opts, xtc_osproc_t **out);

int
xtc_osproc_isolated_spawn(const char *name, int (*fn)(int ctrl_fd, void *arg), void *arg, xtc_osproc_t **out);

long
xtc_osproc_pid(const xtc_osproc_t *p);

int
xtc_osproc_ctrl_fd(const xtc_osproc_t *p);

int
xtc_osproc_signal(const xtc_osproc_t *p, int sig);

int
xtc_osproc_call(xtc_osproc_t *p, const void *req, size_t req_len, void **reply, size_t *reply_len, size_t max_reply, int64_t timeout_ns);

int
xtc_osproc_serve(int ctrl_fd, xtc_osproc_handler_fn handler, void *arg);

int
xtc_osproc_try_wait(xtc_osproc_t *p, int *status);

int
xtc_osproc_wait(xtc_osproc_t *p, int *status, int64_t timeout_ns);

void
xtc_osproc_destroy(xtc_osproc_t *p);

These functions run work in a separate operating-system process -- the “default-to-fork” tier -- as opposed to xtc_proc(3), which spawns an in-process fiber. Use this tier for un-cooperative or untrusted work that must not run in a loop thread, and for one-process-per-connection isolation.

() forks a child described by opts. Exactly one of opts->argv (the child execvp(3)s a program) or opts->fn (the child runs (ctrl_fd, arg) and _exit(2)s with its return value) must be set. When opts->ctrl_socket is non-zero an AF_UNIX SOCK_STREAM socketpair is created; the parent end is returned by () (it is O_NONBLOCK and O_CLOEXEC, pollable with xtc_proc(3) or wrappable with xtc_net(3)), and the child end is delivered to a forked callback as its ctrl_fd argument or, for an exec'd program, in the environment variable XTC_CTRL_FD.

() sends sig to the child. () reaps the child without blocking, returning XTC_OK and the raw waitpid(2) status if it has exited or XTC_E_AGAIN if it is still running. () parks the calling fiber until the child exits (or timeout_ns elapses; a negative value waits forever), then reaps it; it never blocks the loop thread. () closes the control socket, releases the handle, and best-effort reaps an already-exited child; it does not kill a still-running child.

() spawns a worker running fn over a control socket, the setup for the request/reply protocol. The parent then ships a framed request with () (which parks for the reply, capped at max_reply bytes, up to timeout_ns), while the child loops in () handling framed requests with its handler until the control socket closes.

On Linux (>= 5.3) a pidfd(2) backs xtc_osproc_wait() so the caller parks on a readable descriptor with no process-wide SIGCHLD handler; elsewhere xtc_osproc_wait() falls back to a cooperative waitpid(2) WNOHANG poll that yields between probes. The library never installs a SIGCHLD handler, so it does not collide with an embedder's signal handling.

An xtc executor is multi-threaded; fork(2) duplicates only the calling thread. The exec path is therefore safe. A fn (fork-only) callback runs in a half-initialised child and must restrict itself to async-signal-safe work until it re-initialises its own runtime.

xtc_osproc_spawn() returns XTC_OK on success, or XTC_E_INVAL, XTC_E_NOMEM, or XTC_E_INTERNAL. The wait functions return XTC_OK (exited), XTC_E_AGAIN (running or timed out), or a negative error. On a platform without fork(2) (Windows) every function returns XTC_E_NOSYS.

xtc_proc(3), xtc_net(3), xtc_sync(3)

The XTC Project.

June 3, 2026 Debian

View the mdoc source