]> git.ozlabs.org Git - ccan/blob - ccan/coroutine/coroutine.h
coroutine: Stack allocation
[ccan] / ccan / coroutine / coroutine.h
1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
2 #ifndef CCAN_COROUTINE_H
3 #define CCAN_COROUTINE_H
4 /*#define CCAN_COROUTINE_DEBUG 1*/
5 #include "config.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <assert.h>
11
12 #include <ccan/compiler/compiler.h>
13 #include <ccan/typesafe_cb/typesafe_cb.h>
14
15 /**
16  * struct coroutine_stack
17  *
18  * Describes a stack suitable for executing a coroutine.  This
19  * structure is always contained within the stack it describes.
20  */
21 struct coroutine_stack {
22         uint64_t magic;
23         size_t size;
24         int valgrind_id;
25 };
26
27 /**
28  * struct coroutine_state
29  *
30  * Describes the state of an in-progress coroutine.
31  */
32 struct coroutine_state;
33
34 /*
35  * Stack management
36  */
37
38 /**
39  * COROUTINE_STK_OVERHEAD - internal stack overhead
40  *
41  * Number of bytes of a stack which coroutine needs for its own
42  * tracking information.
43  */
44 #define COROUTINE_STK_OVERHEAD  sizeof(struct coroutine_stack)
45
46 /**
47  * COROUTINE_MIN_STKSZ - Minimum coroutine stack size
48  *
49  * Contains the minimum size for a coroutine stack (not including
50  * overhead).  On systems with MINSTKSZ, guaranteed to be at least as
51  * large as MINSTKSZ.
52  */
53 #define COROUTINE_MIN_STKSZ             2048
54
55 /**
56  * COROUTINE_STACK_MAGIC_BUF - Magic number for coroutine stacks in a user
57  *                             supplied buffer
58  */
59 #define COROUTINE_STACK_MAGIC_BUF       0xc040c040574cb00f
60
61 /**
62  * COROUTINE_STACK_MAGIC_ALLOC - Magic number for coroutine stacks
63  *                               allocated by this module
64  */
65 #define COROUTINE_STACK_MAGIC_ALLOC     0xc040c040574ca110
66
67 /**
68  * coroutine_stack_init - Prepare a coroutine stack in an existing buffer
69  * @buf: buffer to use for the coroutine stack
70  * @bufsize: size of @buf
71  * @metasize: size of metadata to add to the stack (not including
72  *            coroutine internal overhead)
73  *
74  * Prepares @buf for use as a coroutine stack, returning a
75  * coroutine_stack *, allocated from within the buffer.  Returns NULL
76  * on failure.
77  *
78  * This will fail if the bufsize < (COROUTINE_MIN_STKSZ +
79  * COROUTINE_STK_OVERHEAD + metasize).
80  */
81 struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize,
82                                              size_t metasize);
83
84 /**
85  * coroutine_stack_alloc - Allocate a coroutine stack
86  * @totalsize: total size to allocate
87  * @metasize: size of metadata to add to the stack (not including
88  *            coroutine internal overhead)
89  *
90  * Allocates a coroutine stack of size @totalsize, including both
91  * internal overhead (COROUTINE_STK_OVERHEAD) and metadata of size
92  * @metasize.  Where available this will also create a guard page, so
93  * that overruning the stack will result in an immediate crash, rather
94  * than data corruption.
95  *
96  * This will fail if the totalsize < (COROUTINE_MIN_STKSZ +
97  * COROUTINE_STK_OVERHEAD + metasize).
98  */
99 struct coroutine_stack *coroutine_stack_alloc(size_t bufsize, size_t metasize);
100
101 /**
102  * coroutine_stack_release - Stop using a coroutine stack
103  * @stack: coroutine stack to release
104  * @metasize: size of metadata
105  *
106  * This releases @stack, making it no longer suitable for use as a
107  * coroutine stack.  @metasize must be equal to the metasize passed to
108  * coroutine_stack_init.
109  */
110 void coroutine_stack_release(struct coroutine_stack *stack, size_t metasize);
111
112 /**
113  * coroutine_stack_check - Validate and return a coroutine stack
114  * @stack: stack to check
115  * @abortstr: the location to print on aborting, or NULL.
116  *
117  * Debugging check if @stack doesn't appear to be a valid coroutine
118  * stack, and @abortstr is non-NULL it will be printed and the
119  * function will abort.
120  *
121  * Returns @stack if it appears valid, NULL if not (it can never
122  * return NULL if @abortstr is set).
123  */
124 struct coroutine_stack *coroutine_stack_check(struct coroutine_stack *stack,
125                                               const char *abortstr);
126
127 /**
128  * coroutine_stack_to_metadata - Returns pointer to user's metadata
129  *                               allocated within the stack
130  * @stack: coroutine stack
131  * @metasize: size of metadata
132  *
133  * Returns a pointer to the metadata area within @stack.  This is of
134  * size given at initialization time, and won't be overwritten by
135  * coroutines executing on the stack.  It's up to the caller what to
136  * put in here. @metasize must be equal to the value passed to
137  * coroutine_stack_init().
138  */
139 static inline void *coroutine_stack_to_metadata(struct coroutine_stack *stack,
140                                                 size_t metasize)
141 {
142 #if HAVE_STACK_GROWS_UPWARDS
143         return (char *)stack - metasize;
144 #else
145         return (char *)stack + COROUTINE_STK_OVERHEAD;
146 #endif
147 }
148
149 /**
150  * coroutine_stack_from_metadata - Returns pointer to coroutine stack
151  *                                 pointer given pointer to user metadata
152  * @metadat: user metadata within a stack
153  * @metasize: size of metadata
154  *
155  * Returns a pointer to the coroutine_stack handle within a stack.
156  * The argument must be a pointer returned by
157  * coroutine_stack_to_metadata() at an earlier time. @metasize must be
158  * equal to the value passed to coroutine_stack_init().
159  */
160 static inline struct coroutine_stack *
161 coroutine_stack_from_metadata(void *metadata, size_t metasize)
162 {
163 #if HAVE_STACK_GROWS_UPWARDS
164         return (struct coroutine_stack *)((char *)metadata + metasize);
165 #else
166         return (struct coroutine_stack *)((char *)metadata
167                                           - COROUTINE_STK_OVERHEAD);
168 #endif
169 }
170
171 /**
172  * coroutine_stack_size - Return size of a coroutine stack
173  * @stack: coroutine stack
174  *
175  * Returns the size of the coroutine stack @stack.  This does not
176  * include the overhead of struct coroutine_stack or metdata.
177  */
178 size_t coroutine_stack_size(const struct coroutine_stack *stack);
179
180 /*
181  * Coroutine switching
182  */
183
184 #if HAVE_UCONTEXT
185 #include <ucontext.h>
186 #define COROUTINE_AVAILABLE             1
187 #else
188 #define COROUTINE_AVAILABLE             0
189 #endif
190
191 struct coroutine_state {
192 #if HAVE_UCONTEXT
193         ucontext_t uc;
194 #endif /* HAVE_UCONTEXT */
195 };
196
197 #if COROUTINE_AVAILABLE
198
199 /**
200  * coroutine_init - Prepare a coroutine for execution
201  * @cs: coroutine_state structure to initialize
202  * @fn: function to start executing in the coroutine
203  * @arg: argument for @fn
204  * @stack: stack to use for the coroutine
205  *
206  * Prepares @cs as a new coroutine which will execute starting with
207  * function @fn, using stack @stack.
208  */
209 void coroutine_init_(struct coroutine_state *cs,
210                      void (*fn)(void *), void *arg,
211                      struct coroutine_stack *stack);
212 #define coroutine_init(cs, fn, arg, stack)                              \
213         coroutine_init_((cs),                                           \
214                         typesafe_cb(void, void *, (fn), (arg)),         \
215                         (arg), (stack))
216
217 /**
218  * coroutine_jump - Irreversibly switch to executing a coroutine
219  * @to: coroutine to switch to
220  *
221  * Immediately jump to executing coroutine @to (at whatever point in
222  * execution it was up to).  Never returns.
223  */
224 void NORETURN coroutine_jump(const struct coroutine_state *to);
225
226 /**
227  * coroutine_switch - Switch coroutines
228  * @from: coroutine in which to store current execution state
229  * @to: coroutine to switch to
230  *
231  * Stop executing the current routine, saving its state in @from, and
232  * switch to executing the coroutine @to.  Returns only when something
233  * switches or jumps back to @from.
234  */
235 void coroutine_switch(struct coroutine_state *from,
236                       const struct coroutine_state *to);
237
238 #else
239
240 static inline void coroutine_init(struct coroutine_state *cs,
241                                   void (*fn)(void *), void *arg,
242                                   struct coroutine_stack *stack)
243 {
244         assert(0);
245 }
246
247 static inline void NORETURN coroutine_jump(const struct coroutine_state *to)
248 {
249         assert(0);
250 }
251
252 static inline void coroutine_switch(struct coroutine_state *from,
253                                     const struct coroutine_state *to)
254 {
255         assert(0);
256 }
257
258 #endif /* !COROUTINE_AVAILABLE */
259
260 #endif /* CCAN_COROUTINE_H */