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