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