xtc_osproc(3)
---xtc_osproc(3)
OS-process spawn, control socket, and lifecycle
| XTC_OSPROC(3) | Library Functions Manual | XTC_OSPROC(3) |
NAME
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_destroy —
OS-process spawn, control socket, and lifecycle
SYNOPSIS
#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);
DESCRIPTION
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.
xtc_osproc_spawn()
forks a child described by opts. Exactly one of
opts->argv (the child execvp(3)s
a program) or opts->fn (the child runs
fn(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
xtc_osproc_ctrl_fd()
(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.
xtc_osproc_signal()
sends sig to the child.
xtc_osproc_try_wait()
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.
xtc_osproc_wait()
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.
xtc_osproc_destroy()
closes the control socket, releases the handle, and best-effort reaps an
already-exited child; it does not kill a still-running child.
xtc_osproc_isolated_spawn()
spawns a worker running fn over a control socket, the
setup for the request/reply protocol. The parent then ships a framed request
with
xtc_osproc_call()
(which parks for the reply, capped at max_reply
bytes, up to timeout_ns),
while the child loops in
xtc_osproc_serve()
handling framed requests with its handler until the
control socket closes.
IMPLEMENTATION NOTES
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.
RETURN VALUES
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.
SEE ALSO
AUTHORS
The XTC Project.
| June 3, 2026 | Debian |