xtc_supervisor(3)

---

xtc_supervisor(3)

OTP-style supervisor trees

XTC_SUPERVISOR(3) Library Functions Manual XTC_SUPERVISOR(3)

xtc_sup_start, xtc_sup_add_child, xtc_sup_stop, xtc_sup_join, xtc_sup_alive, xtc_sup_n_children, xtc_sup_n_alive, xtc_sup_n_restarts — OTP-style supervisor trees

#include <xtc.h>
#include <xtc_orc.h>

int
xtc_sup_start(xtc_loop_t *loop, const xtc_sup_opts_t *opts, const xtc_child_spec_t *children, int n_children, xtc_supervisor_t **out_sup);

int
xtc_sup_add_child(xtc_supervisor_t *sup, const xtc_child_spec_t *spec, xtc_pid_t *out_pid);

int
xtc_sup_stop(xtc_supervisor_t *sup);

int
xtc_sup_join(xtc_supervisor_t *sup, int64_t timeout_ns);

int
xtc_sup_alive(const xtc_supervisor_t *sup);

int
xtc_sup_n_children(const xtc_supervisor_t *sup);

int
xtc_sup_n_alive(const xtc_supervisor_t *sup);

int
xtc_sup_n_restarts(const xtc_supervisor_t *sup);

xtc_supervisor is an OTP-style supervisor: it owns a set of child specs, spawns them, observes failures, and restarts them per the configured strategy. Failures isolate to children; the supervisor's own liveness is independent of any single child.

control which children get restarted on a child crash:

Only the crashed child restarts.
All children restart.
The crashed child and all started after it (right siblings) restart, in order.
Children spawned dynamically; not all known up front.

Under XTC_SUP_ONE_FOR_ALL and XTC_SUP_REST_FOR_ONE the supervisor asks every affected child to exit and then WAITS until each one's cleanup has completed -- until it has left the process table, which happens only after all of its xtc_proc_at_exit(3) hooks have returned -- before it starts any replacement. A replacement therefore never runs beside a predecessor that still holds a shared resource.

The wait is bounded, at 5 seconds. If an old child has not finished cleaning up by then, the supervisor does NOT start a replacement beside it; it stops instead, which its caller observes through ().

Releases before 1.50 killed the siblings, marked them dead and respawned at once, so a replacement could run while its predecessor was still inside an exit hook.

Restart policies per child:

Always restart on exit (normal or crash).
Restart on abnormal exit only.
Never restart; one-shot.

Restart intensity: opts.max_restarts restarts within opts.period_ns exhausts the supervisor; it gives up and exits. Default: 1 in 5 seconds.

for the XTC_SUP_SIMPLE_OFO strategy, set opts.max_children > 0 to cap the number of live dynamic children; () returns XTC_E_RESOURCE once the cap is reached (a slot freed by a child's DOWN is reusable). opts.max_children == 0 is unbounded. () returns the number of children the supervisor manages: every static child (from xtc_sup_start(), alive or not) plus every dynamic child that is alive or being restarted. A dynamic child that exits for good (XTC_RESTART_TEMPORARY, or XTC_RESTART_TRANSIENT with a normal exit) is removed from the supervisor and no longer counted (before 1.55.1 its slot was kept forever); () returns only the currently-live children (pool utilization).

() spawns the supervisor and its initial children. Returns XTC_OK with *out_sup set, or XTC_E_INVAL on bad args (notably n_children ); empty supervisors not supported, see examples/06_sqlxtc/main.c for a one-listener-child workaround .

() adds one child to a running supervisor from a xtc_child_spec_t, returning the new child's pid in *out_pid. This is the dynamic path used with a supervisor, whose children are spawned on demand rather than all listed up front.

() asynchronously requests shutdown. Children get ‘EXIT’ signals; the supervisor exits when all are done. xtc_sup_join() waits up to timeout_ns for the supervisor to exit, then frees it (-1 waits forever, 0 polls once). It returns XTC_OK once the supervisor has exited and been freed; the pointer is then invalid. If the supervisor is still running when the wait ends it returns XTC_E_AGAIN and frees nothing: the pointer stays valid, so the caller can xtc_sup_stop() it and join again. Call it from outside the supervisor's loop thread. Releases before 1.50 ignored the wait's result and freed the supervisor anyway, so a join that timed out returned XTC_OK and freed memory the still-running supervisor was using.

xtc_app(3), xtc_proc(3), xtc_svr(3), xtc(7)

Appeared in xtc 0.1.

May 28, 2026 Debian

View the mdoc source