libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
xtc_orc.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * @stability stable
4 * Use of this source code is governed by the ISC License.
5 *
6 * src/inc/xtc_orc.h
7 * L4 orchestration: supervisor. M10 ships ONE_FOR_ONE strategy
8 * with restart intensity (max-N-restarts-per-W-seconds). The
9 * other strategies (one_for_all, rest_for_one, simple_one_for_one)
10 * and the gen_server / app / registry layer arrive in M10.5.
11 *
12 * A supervisor is itself an xtc_proc that monitors its children
13 * and acts on their DOWN messages. Restart intensity is enforced
14 * by counting child deaths in a sliding window; if the rate
15 * exceeds max_restarts/period_ns, the supervisor exits up the
16 * tree.
17 */
18
19#ifndef XTC_ORC_H
20#define XTC_ORC_H
21
22#include "xtc_export.h"
23
24#include <stdint.h>
25
26#include "xtc.h"
27#include "xtc_loop.h"
28#include "xtc_proc.h"
29
30/*
31 * Restart strategies. M10 implements ONE_FOR_ONE; the others have
32 * named slots so callers can configure for the future and get a
33 * clear XTC_E_NOSYS for an unrecognized strategy value. All four
34 * strategies below are implemented.
35 */
36typedef enum xtc_restart_strategy {
37 XTC_SUP_ONE_FOR_ONE = 0,
38 XTC_SUP_ONE_FOR_ALL = 1, /* M10.5 */
39 XTC_SUP_REST_FOR_ONE = 2, /* M10.5 */
40 XTC_SUP_SIMPLE_OFO = 3 /* M10.5 */
41} xtc_restart_strategy_t;
42
43typedef enum xtc_restart_policy {
44 XTC_RESTART_PERMANENT = 0, /* always restart on exit */
45 XTC_RESTART_TRANSIENT = 1, /* restart only on abnormal exit */
46 XTC_RESTART_TEMPORARY = 2 /* never restart */
47} xtc_restart_policy_t;
48
49/* Forward declaration: the L2 multi-loop executor (xtc_exec.h). A
50 * supervisor may be given one so it places children across loops and
51 * owns the executor's stop on its own exit. */
52struct xtc_exec;
53
54typedef struct xtc_child_spec {
55 size_t size; /* sizeof(xtc_child_spec_t): XTC_CHILD_SPEC_INIT */
56 const char *name; /* optional, for logs */
57 xtc_proc_fn fn;
58 void *arg;
59 xtc_restart_policy_t policy;
60 size_t mailbox_cap; /* 0 = default */
61 int loop; /* exec loop index to place this
62 * child on (only when the supervisor
63 * has an exec); 0 = loop 0 */
65
66/* Every spec, including each element of an xtc_sup_start / xtc_app_start
67 * array, carries .size; the library strides an array by children[0].size
68 * and requires every element to carry that same size. */
69#define XTC_CHILD_SPEC_INIT { .size = sizeof(xtc_child_spec_t) }
70
71typedef struct xtc_sup_opts {
72 size_t size; /* sizeof(xtc_sup_opts_t) */
73 xtc_restart_strategy_t strategy;
74 int max_restarts; /* default 3 */
75 int64_t period_ns; /* default 5 s */
76 struct xtc_exec *exec; /* optional: place children
77 * across its loops and stop
78 * it when the supervisor exits;
79 * NULL = single-loop */
80 int max_children; /* 0 = unbounded; > 0 caps the
81 * dynamic child count
82 * (xtc_sup_add_child returns
83 * XTC_E_RESOURCE at the cap) --
84 * the simple_one_for_one pool
85 * bound */
87
88#define XTC_SUP_OPTS_DEFAULT { \
89 .size = sizeof(xtc_sup_opts_t), \
90 .strategy = XTC_SUP_ONE_FOR_ONE, \
91 .max_restarts = 3, \
92 .period_ns = 5LL * 1000 * 1000 * 1000, \
93 .exec = NULL, \
94 .max_children = 0 \
95}
96
97typedef struct xtc_supervisor xtc_supervisor_t;
98
99/*
100 * PUBLIC: int xtc_sup_start __P((xtc_loop_t *, const xtc_sup_opts_t *, const xtc_child_spec_t *, int, xtc_supervisor_t **));
101 * PUBLIC: int xtc_sup_add_child __P((xtc_supervisor_t *, const xtc_child_spec_t *, xtc_pid_t *));
102 * PUBLIC: int xtc_sup_stop __P((xtc_supervisor_t *));
103 * PUBLIC: int xtc_sup_n_children __P((const xtc_supervisor_t *));
104 * PUBLIC: int xtc_sup_n_alive __P((const xtc_supervisor_t *));
105 * PUBLIC: int xtc_sup_n_restarts __P((const xtc_supervisor_t *));
106 * PUBLIC: int xtc_sup_alive __P((const xtc_supervisor_t *));
107 */
108
109/*
110 * Start a supervisor on `loop` with `n_children` initial children.
111 * The supervisor itself runs as a process; the returned handle lets
112 * callers query/stop it from outside.
113 */
114XTC_API int xtc_sup_start(xtc_loop_t *loop,
115 const xtc_sup_opts_t *opts,
116 const xtc_child_spec_t *children,
117 int n_children,
118 xtc_supervisor_t **out_sup);
119
120/* Ask the supervisor to terminate. Non-blocking; returns immediately
121 * after setting the flag and sending a kick. Children get DOWN'd as
122 * the supervisor processes its mailbox; supervisor exits.
123 *
124 * Safe to call from any thread, multiple times. */
125XTC_API int xtc_sup_stop(xtc_supervisor_t *sup);
126
127/* Dynamically add a child to a running supervisor (the
128 * SIMPLE_ONE_FOR_ONE pattern: a pool of identical children spawned on
129 * demand). Routed through the supervisor proc so it owns the
130 * monitor; returns the new child's pid. Must be called from within a
131 * proc (it awaits the supervisor's reply). Keep spec->name alive for
132 * the child's lifetime. */
133XTC_API int xtc_sup_add_child(xtc_supervisor_t *sup, const xtc_child_spec_t *spec,
134 xtc_pid_t *out_pid);
135
136/* Wait for the supervisor to actually exit, then free its handle.
137 * Must be called from outside the supervisor's loop thread.
138 * timeout_ns < 0 = forever, 0 = poll-once. After a successful join
139 * the handle is invalid. */
140int xtc_sup_join(xtc_supervisor_t *sup, int64_t timeout_ns);
141
142XTC_API int xtc_sup_n_children(const xtc_supervisor_t *sup);
143XTC_API int xtc_sup_n_alive(const xtc_supervisor_t *sup);
144XTC_API int xtc_sup_n_restarts(const xtc_supervisor_t *sup);
145XTC_API int xtc_sup_alive(const xtc_supervisor_t *sup);
146
147#endif /* XTC_ORC_H */