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