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