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