2 contributors
780 lines25.3 KB
1Stackful coroutines in C.
2
3* `Async` coroutines which can pause, waiting for a future.
4* `Generator` coroutines used as generators for loops.
5* `Coroutine` the coroutine engine used by `Async` and `Generator`.
6
7Your code doesn't need to do anything special to be a coroutine, and only standard, or commonly available libraries are needed.
8
9## Prerequisites
10
11The goal was to make a system which can be used 'out of the box'. These libraries rely on as much as possible on C's cross-platform comfort zone. C's standard libraries are used as far as possible, but, as `threads.h` is not usually supported, `pthread.h` has been used instead.
12
13You will need to build & link the code as part of your system - `coroutine/async.c`, `coroutine/generator.c` and `coroutine/coroutine.c` - ensure the headers, `include/*`, are available on your include path.
14
15## Quick Start
16
17### Async
18
19To run an Async program:
20
21 #include "async.h"
22 main(){
23 Async_StartSystem();
24 void *res = NULL;
25 bool canceled = Async_Run(asyncmain, &param, &res);
26 Async_StopSystem();
27 }
28
29Async runs tasks, switching between them when the current task waits on an `Async_Future`. `asyncmain()` is run as a task. The start function for any task looks like this:
30
31 bool mytask(void *param, void **res){
32
33 // do your thing here
34
35 return canceled;
36 }
37
38When `Task` returns from its start function, it returns whether it was canceled. Canceled `Task`s are assumed to have not finished what they were doing.
39
40Within your async task, create `Async_Task`s and `Async_Task_Await()` them when you want to wait for their result:
41
42 Async_Task task1;
43 Async_Task_ctor(&task1, adifferenttask, &task1param);
44
45 void *result;
46 bool canceled = Async_Task_Await(&task1, &result);
47
48 Async_Task_dtor(&task1);
49
50 // use the result
51
52When a task needs to wait for something, and wants to allow other tasks to run, it should use a `Future`:
53
54 Async_Future future;
55 Async_Future_ctor(&future);
56
57 // pass the future to the background-thing-which-might-take-a-while
58
59 void *res;
60 bool canceled = Async_Future_Await(&future, &res);
61
62 Async_Future_dtor(&future);
63
64When the background-thing-which-might-take-a-while has a result:
65
66 Async_Future_SetResult(future, false, result);
67
68### Generators
69
70The coroutine system needs to be started, either through `Async_StartSystem()`, or directly with `Coroutine_StartSystem()` if you don't want to do async things.
71
72You will need a generator function:
73
74 void *yield_my_things(void *param){
75 bool domore = true;
76
77 // loop/call functions to find more values to yield, and when you have one:
78 domore = Generator_Yield(thing);
79 // .. if domore is false, exit your generator - it is being destructed
80
81 // not actually used by generators, but this is a useful convention for bubbling
82 // the flag out to calling functions.
83 return (void *)domore;
84 }
85
86And to use it:
87
88 Generator gen;
89 Generator_ctor(&gen, yield_my_things, "..");
90 void *thing;
91 while(Generator_Next(&gen, &thing)){
92 // use thing - a value yielded by your generator
93 }
94 Generator_dtor(&gen);
95
96### Coroutines
97
98While you can use coroutines directly, it's designed as a system to support more useful patterns, like `Async` and `Generators`.
99
100The Coroutines system must be started:
101
102 Coroutine_StartSystem();
103 // use coroutines here
104 Coroutine_StopSystem();
105
106Your coroutine will need to have a start function:
107
108 void *start(void *param){
109 ...
110 }
111
112When there is no coroutine running, start your 'main' coroutine:
113
114 void *result = Coroutine_Run(comain, param);
115
116Create other coroutines like this:
117
118 Coroutine *cor = Coroutine_New(start);
119
120When you want a Coroutine to run, or to return from a yield:
121
122 Coroutine_Continue(cor, value, run_early);
123
124`value` will be start function's parameter, or the value returned from the yield.
125
126Within the Coroutine, to yield a value:
127
128 void *Coroutine_Yield(value, on_yield, void *me);
129
130The on_yield function is called after the coroutine has been 'wait'ed, but before the next coroutine is resumed.
131
132## How it Works
133
134The coroutine system uses the stack, divided into smaller stacks, for the coroutines. This means you may need to consider whether the coroutine stack size, set by `COROUTINE_STARTUP_STACK_SIZE`, is right for your application, and whether your stack size is enough for the number of coroutines you might run.
135
136Each of your threads has its own stack - the coroutine system can be run (or not) independantly on each thread. For some special cases, you may want to adjust each of your thread's stack sizes depending on how it is used.
137
138## Style
139
140The style is influenced by C++. For example, where possible, a `Something *Something_New(a, b, c)` and `Something_Delete(Something *)`, where a `Something` is `malloc`ed, will have corresponding `Somthing_ctor(Somthing *, a, b, c)` and `Something_dtor(Something *)` to initialise and finalise a `Something` on the stack, or within another object. Using `.._ctor()` and `.._dtor()` will be faster as they avoid the `malloc()` and `free()`.
141
142 Something *oneofthem = Something_New();
143 // use oneofthem
144 Something_Delete(oneofthem);
145
146Can be also be done like this, and this will run faster:
147
148 Something oneofthem;
149 Something_ctor(&oneofthem);
150 // use oneofthem
151 Something_dtor(&oneofthem);
152
153The exception is `Coroutine_New()` and `Coroutine_Delete()`. The returned `Coroutine` is somewhere on your thread's stack - its memory is managed by the coroutine system, and is allocated and freed quickly.
154
155## Usage
156
157When you are using coroutines or generators:
158
159 void *myfunc(void *){
160 // your function here
161 }
162
163 Coroutine_StartSystem();
164 Coroutine_Run(myfunc, (void *)myparam);
165 Coroutine_StopSystem();
166
167If you also use async, then:
168
169 bool myfunc(void *myparam, void **res){
170 // your async function here
171 }
172
173 Async_StartSystem();
174 void *res = NULL;
175 bool canceled = Async_Run(myfunc, myparam, &res);
176 Async_StopSystem();
177
178While the system is started, you can make many calls to `Coroutine_Run()` or `Async_Run()`. A running system is thread local - each thread you want to use coroutines on will need to be `Coroutine_StartSystem()`ed or `Async_StartSystem()`ed.
179
180## Stack Overruns
181
182The C stack is divided down into smaller stacks. There's one to give some work room between `..StartSystem()` and `..Run()`, and one for each coroutine. These have guard markers which are checked to see if the stack has overrun. If there is a stack overrun, the system cannot continue - a message is output and the programe exited. There's a number of ways to avoid this issue:
183
184* Use less stack. This is, sometimes, the right advice, especially if the startup stack overrins. The expectation is that very little is done between `.._StartSystem()` and `..Run()`. If your situation needs more doing, you can...
185
186* increase the stack size. Adjust `COROUTINE_STACK_SIZE` (for startup) or `COROUTINE_STARTUP_STACK_SIZE` (for coroutines) as appropriate. If your use case is even more demanding, such as if you want 1000s of coroutines (so you need small stack chunks), /and/ some of them can recurse an unknown amount (so you need a deep stack for that coroutine), then you can...
187
188* monitor stack headroom, and add another stack chunk if you need to:
189
190In this last case you'll need to add some code at key points:
191
192 void *myfunction(void *param){
193 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_STACK){
194 return Coroutine_Chain(myfunction, param);
195 }
196 // do everything normally
197 }
198
199More realistically:
200
201 struct myfunctionparams {
202 int a;
203 char *b;
204 struct dog *d;
205 }
206
207 void *mychain(void *param){
208 struct myfunctionparams *myparams = (struct myfunctionparams *)params;
209 return (void *)myfunction(myparams->a, myparams->b, *myparams->d);
210 }
211
212 int myfunction(int a, char *b, struct dog d){
213 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_STACK){
214 struct myfunctionparams params = {
215 a,
216 b,
217 &d
218 };
219 return (int)Coroutine_Chain(mychain, &params);
220 }
221 }
222
223And if you want to panic if the C stack overruns:
224
225 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_COROUTINE_STACK){
226 if (Coroutine_HasCoroutinesInFreePool() ||
227 (char *)Coroutine_GetCStackTop() - c_stack_end >= MIN_ALLOWED_C_STACK) {
228 struct myfunctionparams params = {
229 a,
230 b,
231 &d
232 };
233 return (int)Coroutine_Chain(mychain, &params);
234 }
235 // panic now
236 }
237
238# API
239
240## Async
241
242The pattern for using async is:
243
244 void *myasyncmaintask(void *param){
245 // do your main async task things here, like starting more tasks
246 }
247
248 Async_StartSystem();
249 void *res = NULL;
250 bool canceled = Async_Run(myasyncmaintask, NULL, &res);
251 Async_StopSystem();
252
253To create and wait for an async task:
254
255 Async_Task task1;
256 Async_Task_ctor(&task1, asynctask1, &task1param);
257 void *res = NULL;
258 bool canceled = Async_Task_Await(&task1, void **res)
259 Async_Task_dtor(&task1);
260
261or, if you prefer new & delete:
262
263 Async_Task *task1 = Async_Task_New(asynctask1, &task1param);
264 void *res = NULL;
265 bool canceled = Async_Task_Await(task1, void **res)
266 Async_Task_Delete(task1);
267
268Inside your task, when there is something to wait for and you want other tasks to run while your task is waiting, you will need a future:
269
270 Async_Future future;
271 Async_Future_ctor(&future);
272
273 // keep &future to hand for when the background thing completes
274 bool canceled = Async_Future_Await(&future, NULL);
275
276 Async_Future_dtor(&future);
277
278`Async_Future_New()` and `Async_Future_Delete()` are also available if you prefer that style.
279
280Inside the callback when the background thing is complete:
281
282 // result is a void *
283 Async_Future_SetResult(future, result, false);
284
285or, if something went wrong:
286
287 // exception is a void *
288 Async_Future_SetResult(future, exception, true);
289
290Back in the task, you can respond to the future:
291
292 ... Async_Future_Await has returned
293 if (canceled){
294 // exit quickly - you've been canceled
295 // you could, for example, use the future's result as an exception, or error code here
296 }
297 // carry on - the future's result may be an actual result, that's up to you
298
299
300##### void Async_Future_ctor(Async_Future *fut)
301
302fut
303: The `Async_Future` being constructed
304
305Initialise a future. When you no longer need it, use `Async_Future_dtor()`.
306
307##### Async_Future *Async_Future_New()
308
309(returns)
310: The new future
311
312Allocates and initialises a future, When you no longer need it, use `Async_Future_Delete()`.
313
314##### void Async_Future_dtor(Async_Future *fut)
315
316fut
317: The `Async_Future` being destructed
318
319Destruct a future previously constructed with `Async_Future_ctor()`.
320
321##### void Async_Future_Delete(Async_Future *fut)
322
323fut
324: The `Async_Future` to be destructed and freed
325
326Delete (finalise and free) a future previously new'ed with `Async_Future_New()`
327
328##### void Async_Future_SetResult(Async_Future *fut, bool canceled, void *value)
329
330fut
331: The `Async_Future` whose result is being set
332
333canceled
334: The future's `canceled` setting
335
336value
337: The future's `value` of the result
338
339Set the result of a future. This has an effect only the first time its done, ie a completed future can't be canceled and a canceled future can't be completed. When an `Async_Future` has a result, its watchers are called back.
340
341The `value` of a future might be a result if the future completes (when `canceled == false`), or could be some sort of exception value if `canceled == true`. The interpretation of a future's `value` is up to the user - as far as the async system is concerned, it's only a `void *`.
342
343##### bool Async_Future_GetResult(Async_Future *fut, void **res)
344
345(returns)
346: The `canceled` value of the `Async_Future`.
347
348res
349: Where to store the value of the `Async_Future`. This may be `NULL`.
350
351Get the result of a future.
352
353##### typedef void (*Future_Watcher)(void *me, Async_Future *fut)
354
355A `Future_Watcher` is a callback called when a future has a result. The `me` parameter is the one passed to `Async_Future_AddWatcher()`. `fut` is the future which has just got its result.
356
357##### void Async_Future_AddWatcher(Async_Future *fut, Future_Watcher watcher, void *me)
358
359fut
360: the `Async_Future` to add a watcher to
361
362watcher
363: the callback to call when the `Async_Future` has a result.
364
365me
366: the `me` value to pass to `watcher` when it is called back.
367
368Add a watcher (callback) to be called when the future has a result. If the future is already complete, `watcher` is immediately called. The `me` value is passed to the watcher as its `me` parameter. It is assumed that a watcher, identified by the `(watcher, me)` pair, will only be added once.
369
370##### void Async_Future_RemoveWatcher(Async_Future *fut, Future_Watcher watcher, void *me)
371
372fut
373: the `Async_Future` to remove a watcher from
374
375watcher
376: the callback of the watcher to remove.
377
378me
379: the `me` value of the watcher to remove.
380
381Remove a watcher from a future. It is not an error if no watcher matching `(watcher, me)` is found - it has probably already been called back.
382
383##### bool Async_Future_Await(Async_Future *fut, void **res)
384
385(returns)
386: whether the `Async_Future` was canceled.
387
388fut
389: The `Async_Future` to wait for.
390
391res
392: Where to store the `value` of the future when it is has a result. May be `NULL`.
393
394The current `Async_Task` is paused until the `Async_Future` has a result. Other `Async_Task`s are run while this one is waiting.
395
396##### typedef bool (*Async_Entry)(void *param, void **res)
397
398The entry function to an `Async_Task`.
399
400##### void Async_Task_ctor(Async_Task *tsk, Async_Entry entry, void *param)
401
402tsk
403: The task to construct.
404
405entry
406: The entry function for the task.
407
408param
409: The value for `param` to pass to `entry`.
410
411Initialises an `Async_Task`. When you have finished with an `Async_Task` you must finalise it using `Async_Task_dtor()`
412
413 Async_Task tsk;
414 Async_Task_ctor(&tsk, mytask, myparam);
415 // tsk will run if you wait for a task or future
416 Async_Task_Await(&tsk, NULL);
417 Async_Task_dtor(&tsk);
418
419##### Async_Task *Async_Task_New(Async_Entry entry, void *param)
420
421(returns)
422: The new `Async_Task`.
423
424entry
425: The entry function for the task.
426
427param
428: The value for `param` to pass to `entry`.
429
430This allocates and initialises a new `Async_Task`. When you have finished with your task, you must `Async_Delete()` it.
431
432 Async_Task *tsk = Async_New(mytask, myparam);
433 // tsk will run if you wait for a task or future
434 Async_Task_Await(tsk, NULL);
435 Async_Task_Delete(tsk);
436
437##### void Async_Task_dtor(Async_Task *tsk)
438
439tsk
440: The `Async_Task` to destruct.
441
442This finalises an `Async_Task` you ealier initalised with `Async_Task_ctor()`. It is an error to attempt to destruct a task which is running.
443
444 Async_Task tsk;
445 Async_Task_ctor(&tsk, mytask, myparam);
446 // use tsk
447 Async_Task_dtor(&tsk);
448
449##### void Async_Task_Delete(Async_Task *tsk)
450
451tsk
452: The `Async_Task` to delete.
453
454This finalises and frees an `Async_Task` you ealier new'ed with `Async_Task_New()`. It is an error to attempt to delete a task which is running.
455
456 Async_Task *tsk = Async_Task_New(mytask, myparam);
457 // use tsk
458 Async_Task_Delete(tsk);
459
460##### static inline bool Async_Task_Await(Async_Task *tsk, void **res)
461
462(returns)
463: Whether the task was canceled.
464
465tsk
466: The `Async_Task` to wait for.
467
468res
469: Where to store the `Async_Task`'s value when it finishes. This may be NULL.
470
471The current `Async_Task` waits for `tsk` to finish, and returns the result.
472
473##### void Async_Task_Cancel(Async_Task *tsk, void *cancel_value)
474
475tsk
476: The task to cancel.
477
478cancel_value
479: The value to set on any future this task waits on.
480
481This marks a task as canceled. When that task waits on a future that future will be canceled too, using `cancel_value`.
482
483##### static inline bool Async_Task_IsCanceled(Async_Task *tsk)
484
485(returns)
486: Whether the task is canceled.
487
488tsk
489: The task to get its canceled setting from.
490
491##### static inline Async_Future *Async_Task_GetAwaitedFuture(Async_Task *tsk)
492
493(returns)
494: The future the task is waiting on. May be NULL.
495
496tsk
497: Teh task to read the future it is waiting on.
498
499Return the future a task is waiting on.
500
501##### bool Async_Sleep(float delay, void **value)
502
503(returns)
504: Whether the task was canceled.
505
506delay
507: How many seconds to delay for.
508
509value
510: Where to store the cancellation value. This may be NULL.
511
512Sleep for `delay` seconds. `*value` will be set to NULL if the sleep is successful, and the `cancel_value` if the task is canceled.
513
514##### void Async_StartSystem()
515
516Start the async system on this thread. If you want to use async features, use this instead of `Coroutine_StartSystem()`. When you have finished with the async system, use `Async_StopSystem()`.
517
518 Async_StartSystem();
519 // used async here
520 Async_StopSystem();
521
522##### bool Async_Run(Async_Entry start, void *value, void **res)
523
524(returns)
525: Whether `start` was canceled.
526
527start
528: The function to use as the main task.
529
530value
531: The value to pass to `start`.
532
533res
534: Where to store the result of `start`.
535
536Runs `start` as an `Async_Task`. When `start` returns all other tasks must have been destructed, using `Async_Task_dtor()` or `Async_Task_Delete()`.
537
538##### void Async_StopSystem()
539
540Stops the async system. When you have finished using the async system, you must stop it.
541
542 Async_Start();
543 // use the async system
544 Async_Stop();
545
546## Generator
547
548The pattern for a `Generator` is:
549
550#### A loop which uses the `Generator
551
552 Generator gen;
553 Generator_ctor(&gen, mygen, &param);
554
555 void *value;
556 while(Generator_Next(&gen, &value)){
557 // use value here
558 }
559 // value is now the return value from the Generator
560
561 Generator_dtor(&gen);
562
563Or:
564
565 Generator *gen = Generator_New(mygen, &param);
566
567 void *value;
568 while(Generator_Next(gen, &value)){
569 // use value here
570 }
571
572 Generator_Delete(gen);
573
574`Generator`s yield a series of `void *`s - what the `void *`s mean is up to you. `Generator_Next()` returns a `bool` to indicate whether the `Generator` has finished.
575
576#### A generator function
577
578 void *mygen(void *param){
579 bool domore = true;
580 // The parameter is a pointer to a string of chars
581 for (char *str = param; *str; ++str) {
582 // The value yielded is a pointer to a character in the string
583 domore = Generator_Yield(str);
584 if (!domore){
585 break;
586 }
587 }
588
589 return (void *)domore;
590 }
591
592The `bool` returned from `Generator_Yield()` indicates whether the generator function should yield more values. When it is `false` the `Generator` is being finalised - your generator function should close files, and release any other resources it has claimed, before exiting.
593
594##### void Generator_ctor(Generator *gen, void *(*start)(void *), void *param)
595
596gen
597: The `Generator` to construct.
598
599start
600: The function which is the start/entry-point of the `Generator`.
601
602param
603: The value to pass to `start`.
604
605Initialise a `Generator`. When you no longer need the `Generator`, use `Generator_dtor()` to destruct it.
606
607 Generator gen;
608 Generator_ctor(&gen, mystart, &params);
609
610 // Generator is used
611
612 // ... later:
613 Generator_dtor(&gen);
614
615##### Generator *Generator_New(void *(*start)(void *), void *param)
616
617start
618: The function which is the start/entry-point of the `Generator`.
619
620param
621: The value to pass to `start`.
622
623`new` a `Generator` - malloc, and initialise it. When you no longer need the `Generator` use `Generator_dtor` to finalise it.
624
625 Generator *gen = Generator_New(mystart, &params);
626
627 // Generator is used
628
629 // ... later:
630 Generator_Delete(gen);
631
632##### void Generator_dtor(Generator *gen)
633
634gen
635: The `Generator` to destruct.
636
637Finalise a `Generator`. Once a `Generator` is no longer needed, it must be finalised:
638
639 // earlier...
640 Generator gen;
641 Generator_ctor(&gen, mystart, &params);
642
643 // Generator is used
644
645 // the Generator is no longer needed
646 Generator_dtor(&gen);
647
648
649##### void Generator_Delete(Generator *gen)
650
651gen
652: The `Generator` to delete.
653
654Finalise then `free()` a `Generator`. Once a `new`ed `Generator` is no longer needed, it must be deleted:
655
656 // earlier...
657 Generator *gen = Generator_New(mystart, &params);
658
659 // Generator is used
660
661 // the Generator is no longer needed
662 Generator_Delete(gen);
663
664
665##### bool Generator_Next(Generator *gen, void **value)
666
667(returns)
668: Whether there is a next value. `true` - there is a next value; `false` - the `Generator` has finished
669
670gen
671: The `Generator` to get the next value from.
672
673value
674: Where to store the next value.
675
676Get the next value yielded by the `Generator`.
677
678 void *value;
679 while(Generator_Next(gen, &value)){
680 // use value here
681 }
682
683The `Generator` feeds values to its client using `Generator_Yield()` - it is these values which `Generator_Next()` sets, in the example, `value` to.
684
685 When a `Generator` is finished it returns from `start`. When you call `Generator_Yield()` on a finished `Generator` it returns `false` and `value` will be the return value from `start`.
686
687##### bool Generator_Yield(void *value)
688
689(returns)
690: Whether the `Generator` should do more.
691
692value
693: The `Generator`'s next value.
694
695Yield a value from a `Generator`.
696
697 bool domore = Generator_Yield(value);
698
699`value` is then provided by `Generator_Next()` as the next value from the generator.
700
701The `bool` returned by `Generator_Yield()` says whether more values should be provided by your generator function. `true` - provide more values if there are any. `false` - close files, free memory, free up any other resources and `return`. `false` is returned when the `Generator` is being finalised before it has finished, ie the client has exited its `for`-loop early.
702
703## Coroutine
704
705##### void Coroutine_StartSystem()
706
707Start the coroutine system on this thread. When you've finished with `Coroutine` must call `Coroutine_Stop()`.
708
709 Coroutine_Start();
710 // prepare
711 void *result = Coroutine_Run(...);
712 // use result
713 Coroutine_Stop();
714
715`Coroutine` can be started & stopped many times. While `Coroutine` is started, `Coroutine_Run()` can be called any number of times.
716
717The total stack allowed for all coroutines running on any thread is the size of the call stack on that thread.
718
719##### void Coroutine_StopSystem()
720
721Stop the coroutine system on this thread.
722
723##### Coroutine_Start
724
725 void *(*)(void *param)
726
727The entry function for a coroutine. The `param` is the value passed to `Coroutine_Continue`, and the `void *` return value can be accessed through the `Coroutine` object using `Coroutine_GetValue()`.
728
729##### Coroutine *Coroutine_New(Coroutine_Start start)
730
731Create a new `Coroutine`. The `Coroutine` system must be started to create a `Coroutine`. The stack size available to the coroutine will be `COROUTINE_STACK_SIZE` defined in `coroutine.h`. When you have finished with your `Coroutine`, use `Coroutine_Delete()` to delete it.
732
733##### void Coroutine_Run_Coroutine(Coroutine *cor, void *value)
734
735Run the `Coroutine` and return when it returns. This is how to start coroutines running in the coroutine system. It is an error for the run coroutine to return before all other coroutines have completed.
736
737##### void *Coroutine_Run(Coroutine_Start start, void *value)
738
739Convenience wrapper for `Coroutine_Run_Coroutine` which creates the `Coroutine` and retrieves its result.
740
741##### void Coroutine_Delete(Coroutine *cor)
742
743Use `Coroutine_Delete()` to delete a coroutine when it is no longer needed. It is an error to attempt to delete a coroutine which is running.
744
745##### void Coroutine_Continue(Coroutine *cor, void *value, bool early)
746
747Continue the given `Coroutine`. `value` is passed to the coroutine, as `param` to the `start` function, or as the return value from `Coroutine_Yield`. `early` determines whether the continued coroutine is added to the head of tail of the list of runable coroutines.
748
749##### void *Coroutine_Yield(void *value, Coroutine_YieldCallback on_yield, void *this)
750
751Yield `value` from the current coroutine; this coroutine is moved to the list of coroutines waiting to be continued. The next runable coroutine is run - either by its start routine being called with `value` as its `param`, or by `value`being returned from its `Coroutine_Yield()`.
752
753##### void *Coroutine_GetValue(Coroutine *cor)
754
755Return the `Coroutine`'s value - the value last yielded, or returned by its `start` routine.
756
757##### Coroutine *Coroutine_GetActive()
758
759Return whihc coroutine is currently running, ie the caller's `Coroutine`.
760
761##### bool Coroutine_IsRunning(Coroutine *cor)
762
763Return whether the given coroutine is still running - it may be running, ready to run, or waiting to be continued, but won't have returned from its `start` function.
764
765##### int Coroutine_GetStackHeadroom()
766
767Return the headroom available in the current coroutine's stack. This can be used to detect when your coroutine is nearing its stack limit, and then use `Coroutine_Chain()` to continue in a new chunk of coroutine stack.
768
769##### bool Coroutine_HasCoroutinesInFreePool()
770
771Return whether the coroutine system has any coroutine stacks available in its coroutine stack free pool.
772
773##### void *Coroutine_GetCStackTop()
774
775Return an address which is near to the top of used C stack.
776
777##### void *Coroutine_Chain(Coroutine_Start start, void *value)
778
779Run `start` with `value` on a new coroutine, and return its return value. It is expected that `Coroutine_Chain()` will be used when your coroutine is running short of stack - it is not an alternative to `Coroutine_Run()`.
780