libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
xtc_future.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 * a copy of which is in the file LICENSE in the top-level directory
6 * of this distribution.
7 *
8 * src/inc/xtc_future.h
9 * Futures and promises (PLAN.md 2.4.1) -- a one-shot awaitable
10 * value with a write half (xtc_promise_t) and a read half
11 * (xtc_future_t), plus combinators (then / map / when_all /
12 * when_any / with_timeout).
13 *
14 * This is the "task that returns a value" primitive, distinct from
15 * the "task with identity + mailbox" primitive (xtc_proc): code that
16 * just needs one asynchronous result -- a query answer, a lock
17 * grant, a computed value -- uses a future at near-zero overhead
18 * rather than standing up a whole process and mailbox.
19 *
20 * Model. A future carries an intptr_t value and an int status
21 * (the same value/status shape xtc_await uses: the status is an
22 * XTC_* code, XTC_OK on a normal completion). A promise is set
23 * EXACTLY ONCE; the future is then READY forever and every awaiter
24 * -- present or future -- observes the same (value, status).
25 *
26 * Parking. xtc_future_await parks the calling FIBER cooperatively
27 * (the loop keeps serving everyone else) and resumes it when the
28 * promise is set; xtc_future_wait works from a fiber OR a plain OS
29 * thread (e.g. main) and takes a timeout. Both are built on the
30 * same dual-mode park/wake core as xtc_notify, so a promise set
31 * from ANY thread correctly wakes an awaiter on its own loop.
32 *
33 * Ownership. The (promise, future) pair share one reference-counted
34 * cell. Dropping the promise WITHOUT setting it completes the
35 * future with XTC_E_ABORTED (a broken promise is an abort, never a
36 * hang). Each xtc_future_t is consumed by exactly one terminal
37 * operation -- await, wait, or a combinator that takes ownership --
38 * after which the handle must not be reused; the combinators return
39 * a NEW future for the chained result.
40 */
41
42#ifndef XTC_FUTURE_H
43#define XTC_FUTURE_H
44
45#include "xtc_export.h"
46
47#include <stddef.h>
48#include <stdint.h>
49
50#include "xtc.h"
51
52typedef struct xtc_future xtc_future_t;
53typedef struct xtc_promise xtc_promise_t;
54
55/*
56 * PUBLIC: int xtc_future_new_pair __P((xtc_promise_t **, xtc_future_t **));
57 *
58 * Create a linked promise/future pair sharing one cell. On XTC_OK both
59 * *out_prom and *out_fut are non-NULL. Returns XTC_E_INVAL on a NULL
60 * out, XTC_E_NOMEM on allocation failure.
61 */
62XTC_API int xtc_future_new_pair(xtc_promise_t **out_prom,
63 xtc_future_t **out_fut);
64
65/*
66 * PUBLIC: int xtc_promise_set __P((xtc_promise_t *, intptr_t, int));
67 *
68 * Complete the promise with (value, status) and wake every awaiter.
69 * May be called from any thread. A promise is set exactly once: a
70 * second set returns XTC_E_INVAL and changes nothing. Setting also
71 * releases the promise's reference -- after xtc_promise_set the promise
72 * handle is consumed and must not be used again (do NOT also call
73 * xtc_promise_drop). Returns XTC_OK, or XTC_E_INVAL (NULL / already
74 * set).
75 */
76XTC_API int xtc_promise_set(xtc_promise_t *prom, intptr_t value,
77 int status);
78
79/*
80 * PUBLIC: void xtc_promise_drop __P((xtc_promise_t *));
81 *
82 * Abandon a promise WITHOUT setting it: the future completes with
83 * status XTC_E_ABORTED (value 0), so an awaiter never hangs on a
84 * dropped promise. A no-op on NULL or an already-set promise. Do not
85 * use the handle after this.
86 */
87XTC_API void xtc_promise_drop(xtc_promise_t *prom);
88
89/*
90 * PUBLIC: int xtc_future_await __P((xtc_future_t *, intptr_t *));
91 *
92 * Await the result from within a FIBER: parks cooperatively until the
93 * promise is set, then resumes and writes the value to *out (may be
94 * NULL) and returns the promise's status. Consumes the future (frees
95 * the read half); the handle must not be reused. Returns the stored
96 * status (XTC_OK or an XTC_E_* the producer set, or XTC_E_ABORTED for a
97 * dropped promise), or XTC_E_INVAL for a NULL future / call outside a
98 * fiber.
99 */
100XTC_API int xtc_future_await(xtc_future_t *fut, intptr_t *out);
101
102/*
103 * PUBLIC: int xtc_future_wait __P((xtc_future_t *, intptr_t *, int64_t));
104 *
105 * Like xtc_future_await but usable from a plain OS thread (e.g. main)
106 * as well as a fiber, and bounded by timeout_ns (< 0 waits forever,
107 * 0 polls). On timeout returns XTC_E_AGAIN and does NOT consume the
108 * future (it may be awaited again). On completion writes *out, returns
109 * the status, and consumes the future.
110 */
111XTC_API int xtc_future_wait(xtc_future_t *fut, intptr_t *out,
112 int64_t timeout_ns);
113
114/*
115 * PUBLIC: int xtc_future_ready __P((xtc_future_t *, int *));
116 *
117 * Non-blocking readiness check. Sets *is_ready to 1 if the promise is
118 * already set (await/wait would return immediately), else 0. Does NOT
119 * consume the future. Returns XTC_OK or XTC_E_INVAL.
120 */
121XTC_API int xtc_future_ready(xtc_future_t *fut, int *is_ready);
122
123/*
124 * Combinator callbacks.
125 * xtc_future_map_fn transforms a completed value into a new value
126 * (pure, synchronous; runs when the source completes, on the setter's
127 * thread). Receives the source value and status; returns the mapped
128 * value. It may also inspect status to short-circuit.
129 */
130typedef intptr_t (*xtc_future_map_fn)(intptr_t value, int status,
131 void *user);
132
133/*
134 * PUBLIC: int xtc_future_map __P((xtc_future_t *, xtc_future_map_fn, void *, xtc_future_t **));
135 *
136 * Return a NEW future whose value is fn(src_value, src_status, user)
137 * and whose status is the source's status, computed when the source
138 * completes. Consumes the source future. Returns XTC_OK (with
139 * *out_fut set), XTC_E_INVAL, or XTC_E_NOMEM.
140 */
141XTC_API int xtc_future_map(xtc_future_t *src, xtc_future_map_fn fn,
142 void *user, xtc_future_t **out_fut);
143
144/*
145 * then-callback: consumes the source result and returns a NEW future
146 * (the flat-map / chaining case -- "when src completes, start the next
147 * async step"). Ownership of the returned future transfers to the
148 * combinator, which resolves the outer future from it.
149 */
150typedef int (*xtc_future_then_fn)(intptr_t value, int status, void *user,
151 xtc_future_t **out_next);
152
153/*
154 * PUBLIC: int xtc_future_then __P((xtc_future_t *, xtc_future_then_fn, void *, xtc_future_t **));
155 *
156 * When src completes, call fn to produce the next future; the outer
157 * (returned) future completes with THAT future's result. Consumes
158 * src. Returns XTC_OK / XTC_E_INVAL / XTC_E_NOMEM.
159 */
160XTC_API int xtc_future_then(xtc_future_t *src, xtc_future_then_fn fn,
161 void *user, xtc_future_t **out_fut);
162
163/*
164 * PUBLIC: int xtc_future_when_all __P((xtc_future_t **, int, xtc_future_t **));
165 *
166 * Return a future that completes when ALL n input futures have
167 * completed. Its value is n (the count) and its status is XTC_OK if
168 * every input succeeded, else the FIRST non-OK status observed.
169 * Consumes all n input futures (they must not be awaited separately).
170 * Returns XTC_OK / XTC_E_INVAL / XTC_E_NOMEM.
171 */
172XTC_API int xtc_future_when_all(xtc_future_t **futs, int n,
173 xtc_future_t **out_fut);
174
175/*
176 * PUBLIC: int xtc_future_when_any __P((xtc_future_t **, int, xtc_future_t **));
177 *
178 * Return a future that completes as soon as ANY one of the n inputs
179 * completes, carrying that input's (value, status). Consumes all n
180 * inputs. Returns XTC_OK / XTC_E_INVAL / XTC_E_NOMEM.
181 */
182XTC_API int xtc_future_when_any(xtc_future_t **futs, int n,
183 xtc_future_t **out_fut);
184
185/*
186 * PUBLIC: int xtc_future_with_timeout __P((xtc_future_t *, int64_t, xtc_future_t **));
187 *
188 * Return a future that completes with src's result if it completes
189 * within timeout_ns, else completes with XTC_E_AGAIN (value 0).
190 * Consumes src. Requires a running loop (arms a timer). Returns
191 * XTC_OK / XTC_E_INVAL / XTC_E_NOMEM.
192 */
193XTC_API int xtc_future_with_timeout(xtc_future_t *src, int64_t timeout_ns,
194 xtc_future_t **out_fut);
195
196#endif /* XTC_FUTURE_H */