1130 lines34.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 size_t mytask_stack_size = 8192 * sizeof(void *);
29 void *res = NULL;
30 bool canceled = Task_Run(mytask_stack_size, maintask, &param, &res);
31 }
32
33`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:
34
35 #!C
36 bool mytask(void *param, void **res){
37
38 // do your thing here
39
40 return canceled;
41 }
42
43When `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.
44
45Within your main task, create `Task`s and `Task_Await()` them when you want to wait for their result:
46
47 #!C
48 Task task1;
49 Task_ctor(&task1, mytask_stack_size, adifferenttask, &task1param);
50
51 void *result;
52 bool canceled = Task_Await(&task1, &result);
53
54 Task_dtor(&task1);
55
56 // use the result
57
58When a task needs to wait for something, and wants to allow other tasks to run, it should use a `Future`:
59
60 #!C
61 Future future;
62 Future_ctor(&future);
63
64 // pass the future to the background-thing-which-might-take-a-while
65
66 void *res;
67 bool canceled = Future_Await(&future, &res);
68
69 Future_dtor(&future);
70
71When the background-thing-which-might-take-a-while has a result:
72
73 #!C
74 Future_SetResult(future, false, result);
75
76### ASleep
77
78`ASleep()` needs its own system to be started to work:
79
80 #!C
81 ASleep_StartSystem()
82 // Run tasks here which may now use ASLeep()
83 ASleep_StopSystem();
84
85Note that `ASleep_StartSystem()` / `ASleep_StopSystem()` is only needed once per process.
86
87Sleeping in a task:
88
89 #!C
90 bool mytask(void *param, void **result){
91 ..
92 ASleep(time_to_sleep);
93 ..
94 }
95
96### Generators
97
98Your code needs to be in a `Coroutine` to use a `Generator`:
99
100 #!C
101 void *mycoroutine(void *param){
102 // You can use a Generator here
103 }
104
105 Coroutine_Run(StackSpace, mycoroutine, NULL, NULL);
106
107You will need a generator function:
108
109 #!C
110 void *yield_my_things(void *param){
111 bool domore = true;
112
113 // loop/call functions to find more values to yield, and when you have one:
114 domore = Generator_Yield(thing);
115 // .. if domore is false, exit your generator - it is being destructed
116
117 // not actually used by generators, but this is a useful convention for bubbling
118 // the flag out to calling functions.
119 return (void *)domore;
120 }
121
122And to use it:
123
124 #!C
125 Generator gen;
126 Generator_ctor(&gen, generator_stack_size, yield_my_things, "..");
127 void *thing;
128 while(Generator_Next(&gen, &thing)){
129 // use thing - a value yielded by your generator
130 }
131 Generator_dtor(&gen);
132
133### Coroutines
134
135While you can use coroutines directly, it's designed as a system to support more useful patterns, like `Async` and `Generators`.
136
137Your coroutine will need to have a start function:
138
139 #!C
140 void *start(void *param){
141 ...
142 }
143
144When there is no coroutine running, start your 'main' coroutine:
145
146 #!C
147 if (Coroutine_Run(coroutine_stack_size, comain, param, &result)){
148 // handle the failure
149 }
150
151Create other coroutines like this:
152
153 #!C
154 Coroutine *cor = Coroutine_New(start);
155
156When you want a Coroutine to be queued to run:
157
158 #!C
159 Coroutine_Continue(cor, value, run_early);
160
161`value` will be start function's parameter, or the value returned from the yield.
162
163Within the Coroutine, to yield a value, and allow other `Coroutine`s to run:
164
165 #!C
166 void *Coroutine_Yield(value, on_yield, void *me);
167
168The on_yield function is called after the coroutine has been 'wait'ed, but before the next coroutine is resumed.
169
170## How it Works
171
172The coroutine system uses the stack divided into smaller stacks for the coroutines. This means you may need to consider whether each coroutine's stack size, is right for each Coroutine, and whether your C stack size is enough for the number of coroutines you might run.
173
174Each 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.
175
176## Style
177
178The 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()`.
179
180 #!C
181 Something *oneofthem = Something_New();
182 // use oneofthem
183 Something_Delete(oneofthem);
184
185Can be also be done like this, and this will run faster:
186
187 #!C
188 Something oneofthem;
189 Something_ctor(&oneofthem);
190 // use oneofthem
191 Something_dtor(&oneofthem);
192
193The 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.
194
195## Usage
196
197When you are using coroutines or generators:
198
199 #!C
200 void *myfunc(void *){
201 // your function here
202 }
203
204 size_t coroutine_stack_size = 8192 * sizeov(void *);
205 if (Coroutine_Run(coroutine_stack_size, myfunc, (void *)myparam, NULL)){
206 // handle the failure
207 }
208
209You can make many calls to `Coroutine_Run()` or `Task_Run()`. `Coroutine_Run()` ensures the system is started, and that `myfunc` is called
210from inside a Coroutine. In paeticular, if the Coroutine system is running and `Coroutine_Run()` is called from inside a coroutine, then `myfunc` is simply called.
211
212## Stack Overruns
213
214The C stack is divided into smaller stacks. There's one, the startup stack, to give some room for `start` in `Coroutine_RunSystem` to work, and then each `Coroutine` has its own stack. 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:
215
216* Use less stack. This is, sometimes, the right advice, especially if the startup stack overruns. The expectation is that very little is done by `start` in `Coroutine_RunSystem`. If your situation needs more doing, you can...
217
218* increase the stack size for your `Coroutine`. 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...
219
220* monitor stack headroom, and add another stack chunk if you need to:
221
222In this last case you'll need to add some code at key points:
223
224 #!C
225 void *myfunction(void *param){
226 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_STACK){
227 void *result;
228 Coroutine_Err err = Coroutine_Chain(my_stack_size, myfunction, param, &result);
229 if (err){
230 // handle failure
231 }
232 return result;
233 }
234 // do everything normally
235 }
236
237More realistically:
238
239 #!C
240 struct myfunctionparams {
241 int a;
242 char *b;
243 struct dog *d;
244 }
245
246 void *mychain(void *param){
247 struct myfunctionparams *myparams = (struct myfunctionparams *)params;
248 return (void *)myfunction(myparams->a, myparams->b, *myparams->d);
249 }
250
251 int myfunction(int a, char *b, struct dog d){
252 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_STACK){
253 struct myfunctionparams params = {
254 a,
255 b,
256 &d
257 };
258 void *result;
259 Coroutine_Err err = Coroutine_Chain(my_stack_size, mychain, &params, &result);
260 if (err){
261 // handle failure
262 }
263 return (int)(intptr_t)result;
264 }
265 }
266
267And if you want to panic if the C stack overruns:
268
269 #!C
270 if (Coroutine_GetStackHeadroom() < MIN_ALLOWED_COROUTINE_STACK){
271 if (Coroutine_HasCoroutinesInFreePool() ||
272 (char *)Coroutine_GetCStackTop() - c_stack_end >= MIN_ALLOWED_C_STACK) {
273 struct myfunctionparams params = {
274 a,
275 b,
276 &d
277 };
278 void *result;
279 if (Coroutine_Chain(my_stack_size, mychain, &params, &result)){
280 // handle failure
281 }
282 return (int)(intptr_t)result;
283 }
284 // panic now
285 }
286
287## Configuring for Your Use Case
288
289There's a number of adjustments which you may need to make for your situation. This are, mostly, in `cor_platform.h`.
290
291There's some options in `coroutine.h` which you may need to adjust:
292
293Coroutine_NS(name)
294: This allows the `Coroutine_???()` functions to be given a different naming convention.
295
296COROUTINE_STARTUP_STACK_SIZE
297: The amount of stack set aside for `start` in `Coroutine_RunSystem()`.
298
299COROUTINE_MINIMUM_STACK_SIZE
300: The minimum stack size you'll ask for. The C stack is managed as a heap. If one of the free blocks in that
301heap is big enough for your new Coroutine, and has spare, if that spare is too small for a `Coroutine` wanting
302`COROUTINE_MINIMUM_STACK_SIZE` of stack, then the whole free block is given to your new Coroutine, instead
303of being split into two.
304
305`cor_platform.h` focuses on customisation for your particular use case.
306
307_Cor_thread_local
308: How to declare a variable to be thread local
309
310COROUTINE_HAVE_ALLOCA_H
311: Whether your system can `#incude <alloca.h>`.
312
313_Cor_Mutex and related routines
314: Your system's mutex.
315
316_Cor_Realtime_Now
317: Return a realtime clock value compatible with _Cor_Semaphore_Wait.
318
319_Cor_Semaphore and related routines
320: Semaphores on your system.
321
322_Cor_Thread and related routines
323: Threads on your system.
324
325# API
326
327## Task & Future
328
329The pattern for using async is:
330
331 #!C
332 bool mymaintask(void *param, void **result){
333 // do your main task things here, like starting more tasks
334 }
335
336 void *res = NULL;
337 bool canceled = Task_Run(mymaintask, NULL, &res);
338
339To create and wait for a task:
340
341 #!C
342 Task task1;
343 Task_ctor(&task1, asynctask1, &task1param);
344 void *res = NULL;
345 bool canceled = Task_Await(&task1, void **res)
346 Task_dtor(&task1);
347
348or, if you prefer new & delete:
349
350 #!C
351 Task *task1 = Task_New(asynctask1, &task1param);
352 void *res = NULL;
353 bool canceled = Task_Await(task1, void **res)
354 Task_Delete(task1);
355
356Inside 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:
357
358 #!C
359 Future future;
360 Future_ctor(&future);
361
362 // keep &future to hand for when the background thing completes
363 bool canceled = Future_Await(&future, NULL);
364
365 Future_dtor(&future);
366
367`Future_New()` and `Future_Delete()` are also available if you prefer that style.
368
369Inside the callback when the background thing is complete:
370
371 #!C
372 // result is a void *
373 Future_SetResult(future, result, false);
374
375or, if something went wrong:
376
377 #!C
378 // exception is a void *
379 Future_SetResult(future, exception, true);
380
381Back in the task, you can respond to the future:
382
383 #!C
384 ... Future_Await has returned
385 if (canceled){
386 // exit quickly - you've been canceled
387 // you could, for example, use the future's result as an exception, or error code here
388 }
389 // carry on - the future's result may be an actual result, that's up to you
390
391
392##### void Future_ctor(Future *fut)
393
394fut
395: The `Future` being constructed
396
397Initialise a future. When you no longer need it, use `Future_dtor()`.
398
399##### Future *Future_New()
400
401(returns)
402: The new future
403
404Allocates and initialises a future, When you no longer need it, use `Future_Delete()`.
405
406##### void Future_dtor(Future *fut)
407
408fut
409: The `Future` being destructed
410
411Destruct a future previously constructed with `Future_ctor()`.
412
413##### void Future_Delete(Future *fut)
414
415fut
416: The `Future` to be destructed and freed
417
418Delete (finalise and free) a future previously new'ed with `Future_New()`
419
420##### void Future_SetResult(Future *fut, bool canceled, void *value)
421
422fut
423: The `Future` whose result is being set
424
425canceled
426: The future's `canceled` setting
427
428value
429: The future's result `value`
430
431Set 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.
432
433The `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 *`.
434
435##### bool Future_GetResult(Future *fut, void **res)
436
437(returns)
438: The `canceled` value of the `Future`.
439
440res
441: Where to store the value of the `Future`. This may be `NULL`.
442
443Get the result of a future.
444
445##### typedef void (*Future_Watcher)(void *me, Future *fut)
446
447A `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.
448
449##### void Future_AddWatcher(Future *fut, Future_Watcher watcher, void *me)
450
451fut
452: the `Future` to add a watcher to
453
454watcher
455: the callback to call when the `Future` has a result.
456
457me
458: the `me` value to pass to `watcher` when it is called back.
459
460Add 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.
461
462##### void Future_RemoveWatcher(Future *fut, Future_Watcher watcher, void *me)
463
464fut
465: the `Future` to remove a watcher from
466
467watcher
468: the callback of the watcher to remove.
469
470me
471: the `me` value of the watcher to remove.
472
473Remove 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.
474
475##### bool Future_Await(Future *fut, void **res)
476
477(returns)
478: whether the `Future` was canceled.
479
480fut
481: The `Future` to wait for.
482
483res
484: Where to store the `value` of the future when it is has a result. May be `NULL`.
485
486The current `Task` is paused until the `Future` has a result. Other `Task`s are run while this one is waiting.
487
488##### typedef bool (*Task_Entry)(void *param, void **res)
489
490The entry function to an `Task`.
491
492##### void Task_ctor(Task *tsk, Task_Entry entry, void *param)
493
494tsk
495: The task to construct.
496
497entry
498: The entry function for the task.
499
500param
501: The value for `param` to pass to `entry`.
502
503Initialises an `Task`. When you have finished with an `Task` you must finalise it using `Task_dtor()`
504
505 #!C
506 Task tsk;
507 Task_ctor(&tsk, mytask, myparam);
508 // tsk will run if you wait for a task or future
509 Task_Await(&tsk, NULL);
510 Task_dtor(&tsk);
511
512##### Task *Task_New(Task_Entry entry, void *param)
513
514(returns)
515: The new `Task`.
516
517entry
518: The entry function for the task.
519
520param
521: The value for `param` to pass to `entry`.
522
523This allocates and initialises a new `Task`. When you have finished with your task, you must `Task_Delete()` it.
524
525 #!C
526 Task *tsk = Task_New(mytask, myparam);
527 // tsk will run if you wait for a task or future
528 Task_Await(tsk, NULL);
529 Task_Delete(tsk);
530
531##### void Task_dtor(Task *tsk)
532
533tsk
534: The `Task` to destruct.
535
536This finalises an `Task` you ealier initalised with `Task_ctor()`. It is an error to attempt to destruct a task which is running.
537
538 #!C
539 Task tsk;
540 Task_ctor(&tsk, mytask, myparam);
541 // use tsk
542 Task_dtor(&tsk);
543
544##### void Task_Delete(Task *tsk)
545
546tsk
547: The `Task` to delete.
548
549This 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.
550
551 #!C
552 Task *tsk = Task_New(mytask, myparam);
553 // use tsk
554 Task_Delete(tsk);
555
556##### static inline bool Task_Await(Task *tsk, void **res)
557
558(returns)
559: Whether the task was canceled.
560
561tsk
562: The `Task` to wait for.
563
564res
565: Where to store the `Task`'s value when it finishes. This may be NULL.
566
567The current `Task` waits for `tsk` to finish, and returns the result.
568
569##### void Task_Cancel(Task *tsk, void *cancel_value)
570
571tsk
572: The task to cancel.
573
574cancel_value
575: The value to set on any future this task waits on.
576
577This marks a task as canceled. When that task waits on a future that future will be canceled too, using `cancel_value`.
578
579##### static inline bool Task_IsCanceled(Task *tsk)
580
581(returns)
582: Whether the task is canceled.
583
584tsk
585: The task to get its canceled setting from.
586
587##### static inline Future *Task_GetAwaitedFuture(Task *tsk)
588
589(returns)
590: The future the task is waiting on. May be NULL.
591
592tsk
593: Teh task to read the future it is waiting on.
594
595Return the future a task is waiting on.
596
597##### bool Task_Run(Task_Entry start, void *value, void **res)
598
599(returns)
600: Whether `start` was canceled.
601
602start
603: The function to use as the main task.
604
605value
606: The value to pass to `start`.
607
608res
609: Where to store the result of `start`.
610
611Runs `start` as an `Task`. When `start` returns all other tasks must have been destructed, using `Task_dtor()` or `Task_Delete()`.
612
613## ASleep
614
615##### void ASleep_StartSystem()
616
617You must start the `ASleep` system to use it. This needs to happen per process. Once you've finished with `ASleep` you must `ASleep_StopSystem()`.
618
619 #!C
620 ASleep_StartSystem();
621 // Now you can use ASleep() on any thread
622 ASleep_StopSystem();
623
624##### void ASleep_StopSystem()
625
626Call this to stop the `ASleep` system.
627
628##### bool ASleep(float delay, void **value)
629
630(returns)
631: Whether the task was canceled.
632
633delay
634: How many seconds to delay for.
635
636value
637: Where to store the cancellation value. This may be NULL.
638
639Sleep for `delay` seconds. `*value` will be set to `NULL` if the sleep is successful, and the `cancel_value` if the task is canceled.
640
641## Generator
642
643The pattern for a `Generator` is:
644
645#### A loop which uses the `Generator
646
647 #!C
648 Generator gen;
649 Generator_ctor(&gen, generator_stack_size, mygen, &param);
650
651 void *value;
652 while(Generator_Next(&gen, &value)){
653 // use value here
654 }
655 // value is now the return value from the Generator
656
657 Generator_dtor(&gen);
658
659Or:
660
661 #!C
662 Generator *gen = Generator_New(generator_stack_size, mygen, &param);
663
664 void *value;
665 while(Generator_Next(gen, &value)){
666 // use value here
667 }
668
669 Generator_Delete(gen);
670
671`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.
672The `generator_stack_size` is the stack amount made available to your generator.
673
674#### A generator function
675
676 #!C
677 void *mygen(void *param){
678 bool domore = true;
679 // The parameter is a pointer to a string of chars
680 for (char *str = param; *str; ++str) {
681 // The value yielded is a pointer to a character in the string
682 domore = Generator_Yield(str);
683 if (!domore){
684 break;
685 }
686 }
687
688 return (void *)domore;
689 }
690
691The `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.
692
693##### void Generator_ctor(Generator *gen, size_t generator_stack_size, void *(*start)(void *), void *param)
694
695gen
696: The `Generator` to construct.
697
698generator_stack_size
699: The amount of stack given to the generator.
700
701start
702: The function which is the start/entry-point of the `Generator`.
703
704param
705: The value to pass to `start`.
706
707Initialise a `Generator`. When you no longer need the `Generator`, use `Generator_dtor()` to destruct it.
708
709 #!C
710 Generator gen;
711 Generator_ctor(&gen, generator_stack_size, mystart, &params);
712
713 // Generator is used
714
715 // ... later:
716 Generator_dtor(&gen);
717
718##### Generator *Generator_New(size_t generator_stack_size, void *(*start)(void *), void *param)
719
720generator_stack_size
721: The amount of stack to give to the generator.
722
723start
724: The function which is the start/entry-point of the `Generator`.
725
726param
727: The value to pass to `start`.
728
729`new` a `Generator` - malloc, and initialise it. When you no longer need the `Generator` use `Generator_dtor` to finalise it.
730
731 #!C
732 Generator *gen = Generator_New(mystart, &params);
733
734 // Generator is used
735
736 // ... later:
737 Generator_Delete(gen);
738
739##### void Generator_dtor(Generator *gen)
740
741gen
742: The `Generator` to destruct.
743
744Finalise a `Generator`. Once a `Generator` is no longer needed, it must be finalised:
745
746 #!C
747 // earlier...
748 Generator gen;
749 Generator_ctor(&gen, generator_stack_size, mystart, &params);
750
751 // Generator is used
752
753 // the Generator is no longer needed
754 Generator_dtor(&gen);
755
756
757##### void Generator_Delete(Generator *gen)
758
759gen
760: The `Generator` to delete.
761
762Finalise then `free()` a `Generator`. Once a `new`ed `Generator` is no longer needed, it must be deleted:
763
764 #!C
765 // earlier...
766 Generator *gen = Generator_New(mystart, &params);
767
768 // Generator is used
769
770 // the Generator is no longer needed
771 Generator_Delete(gen);
772
773
774##### bool Generator_Next(Generator *gen, void **value)
775
776(returns)
777: Whether there is a next value. `true` - there is a next value; `false` - the `Generator` has finished
778
779gen
780: The `Generator` to get the next value from.
781
782value
783: Where to store the next value.
784
785Get the next value yielded by the `Generator`.
786
787 #!C
788 void *value;
789 while(Generator_Next(gen, &value)){
790 // use value here
791 }
792
793The `Generator` feeds values to its client using `Generator_Yield()` - it is these values which `Generator_Next()` sets, in the example, `value` to.
794
795 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`.
796
797##### bool Generator_Yield(void *value)
798
799(returns)
800: Whether the `Generator` should do more.
801
802value
803: The `Generator`'s next value.
804
805Yield a value from a `Generator`.
806
807 #!C
808 bool domore = Generator_Yield(value);
809
810`value` is then provided by `Generator_Next()` as the next value from the generator.
811
812The `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.
813
814## Coroutine
815
816##### Coroutine_Err
817
818The enum of errors:
819
820Coroutine_OK
821: Everything is OK. This is 0
822
823Coroutine_Err_SystemNotRunning
824: A `Coroutine` must be running to do this
825
826Coroutine_Err_SystemRunning
827: The `Coroutine` system must not be running to do this
828
829Coroutine_Err_NoStack
830: Not enough stack is available
831
832Coroutine_Err_CoroutineFromWrongThread
833: Trying to do something on one thread to a `Coroutine` from a different thread
834
835Coroutine_Err_ACoroutineIsAlreadyRunning
836: Trying `Coroutine_RunCoroutine` a `Coroutine`
837
838Coroutine_Err_ExitWithRunningCoroutines
839: All `Coroutine`s must be complete
840
841Coroutine_Err_StackOverrun
842: Stack overrun detected
843
844Coroutine_Err_InternalInsistency
845: Something didn't match inside the system
846
847Coroutine_Err_CouldNotInitialiseSystem
848: Something went wrong initialising (eg couldn't create a lock)
849
850Coroutine_Err_WrongState
851: It's in the wrong statem, eg trying to `Coroutine_Continue` a completed `Coroutine`
852
853Coroutine_Err_Canceled
854: It's canceled
855
856##### Coroutine_SetStackLimit(void *limit)
857
858limit
859: The location (low address) of the stack's end.
860
861Set the limit of the stack. This is used to determine more accurately whether `Coroutine_CanStartCoroutine()`
862
863##### Coroutine_Report Coroutine_GetReport()
864
865(returns)
866: A report from this run of the Coroutine system.
867
868 #!C
869 typedef struct Coroutine_Report {
870 unsigned coroutines_created;
871 unsigned coroutines_pool_size;
872 unsigned lowest_headroom;
873 } Coroutine_Report;
874
875coroutines_created
876: How many coroutines were created
877
878coroutines_pool_size
879: 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.
880
881lowest_headroom
882: The lowest headroom (unused
883
884largest_stack
885: The largest stack requested for any `Coroutine`.
886
887##### Coroutine_CheckIntegrity()
888
889(returns)
890: `Coroutine_Err` for any problem
891
892Check the integrity of the coroutine system, and `printf()` any problems.
893
894##### Coroutine_Start
895
896 #!C
897 void *(*)(void *param)
898
899The 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()`.
900
901##### Coroutine_SystemStart
902
903 #!C
904 Coroutine_Err (*)(void *)
905
906The entry function for `Coroutine_RunSystem`.
907
908##### Coroutine_Err Coroutine_RunSystem(Coroutine_SystemStart start, void *value)
909
910(returns)
911: `Coroutine_OK` or an error. If the system starts, this will be the value returned by `start`.
912
913start
914: The function to call with the `Coroutine` system started. It is expected that this routine will
915start a `Coroutine`.
916
917value
918: The value to pass to `start`.
919
920##### Coroutine *Coroutine_New(size_t size, Coroutine_Start start)
921
922(returns)
923A new Coroutine, or `NULL` if there was a failure, such as insufficient stack for the new Coroutine.
924
925size
926: The stack size given to this Coroutine.
927
928start
929: The routine called to start the Coroutine.
930
931Create 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.
932
933##### Coroutine_Err Coroutine_Run_Coroutine(Coroutine *cor, void *value)
934
935(returns)
936: any problem, or `Coroutine_OK`
937
938cor
939: The Coroutine to run.
940
941value
942: The value to pass to the Coroutine's `start` routine.
943
944Run 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.
945
946##### Coroutine_Err Coroutine_Run(size_t size, Coroutine_Start start, void *value, void **result)
947
948(returns)
949: `Coroutine_OK` or any problem
950
951size
952: The stack size to give to the Corotuine.
953
954start
955: The routine to start the Coroutine.
956
957value
958: The value to pass to `start()`.
959
960result
961: Where to store the return value from `start(value)`. This may be `NULL`.
962
963`start(value)` is called from within a coroutine and its value returned in `*result`.
964If this completes without any failure, `false` is returned, otherwise, typically
965because `Coroutine_New()` returned `NULL`, `true` is returned. `result` may be `NULL` if you don't
966need the resturn value from `start()`.
967When the coroutine system is active - you are already running in a coroutine - `start(value)`
968is simply called and its result returned in `*result`. When the Coroutine system is not running,
969`Coroutine_Run()` starts it, creates a `Coroutine` and runs that Coroutine to call `start(calue)`
970and return value is returned in `*result`, then stops the Coroutine system. If you need to force
971a new Coroutine to be created, with a particular stack size to call `start(value)`, then use
972`Coroutine_Chain()` instead.
973
974The total stack allowed for all coroutines running on any thread is the size of the call stack on that thread.
975
976##### void Coroutine_Delete(Coroutine *cor)
977
978cor
979: The Coroutine to delete.
980
981Use `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.
982
983##### Coroutine_Err Coroutine_Continue(Coroutine *cor, void *value, bool early)
984
985(returns)
986: `Coroutine_OK` or any error.
987
988cor
989: The Coroutine to continue.
990
991value
992: The value to return from `cor`'s yield function.
993
994early
995: Whether to continue `cor` early (`true`), or late (`false`). Early means before other Coroutines which are waiting
996to be called, whereas late means after them.
997
998Continue 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 will be run next, or after all the other, currently runnable, coroutines. If the `Coroutine` is already runnable, nothing is done, and `false` is returned. If the `Coroutine` is free, or complete, nothing is done and `true` is returned to show there was a problem.
999
1000##### void *Coroutine_Yield(void *value, Coroutine_YieldCallback on_yield, void *this)
1001
1002value
1003: The value to yield fropm the coroutine.
1004
1005on_yield
1006: A callback to be called once this Coroutine has yielded, but before another one has been continued.
1007
1008this
1009: The parameter to pass to `on_yield`.
1010
1011Yield `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()`.
1012
1013##### void *Coroutine_GetValue(Coroutine *cor)
1014
1015(returns)
1016: The Coroutine's value - the last yielded or returned value.
1017
1018cor
1019: The Coroutine to query.
1020
1021Return the `Coroutine`'s value - the value last yielded, or returned by its `start` routine.
1022
1023##### Coroutine *Coroutine_GetActive()
1024
1025(returns)
1026: The currently active Coroutine.
1027
1028Return whihc coroutine is currently running, ie the caller's `Coroutine`.
1029
1030##### bool Coroutine_IsRunning(Coroutine *cor)
1031
1032(returns)
1033: Whether `cor` is running - it's the active coroutine or waiting to be continued.
1034
1035cor
1036: The Coroutine to query.
1037
1038Return 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.
1039
1040##### bool Coroutine_IsComplete(Coroutine *cor)
1041
1042(returns)
1043: Whether `cor` is complete, ie has returned from `start()`./
1044
1045cor
1046: The Coroutine to query.
1047
1048Return whether the given coroutine is complete - is has returned from its `start` function.
1049
1050##### intptr_t Coroutine_GetStackHeadroom()
1051
1052(returns)
1053: The amount of stack headroom.
1054
1055Return 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.
1056
1057##### bool Coroutine_CanStartCoroutine(size_t size)
1058
1059(returns)
1060: Whether a Coroutine with the given amount of stack could be created.
1061
1062size
1063: The amount of stack in the Coroutine we might want to create.
1064
1065Return whether the coroutine system can start a new coroutine. This check can only be done with the coroutine system active (currently running
1066a 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
1067stack use `Coroutine_SetStackLimit()`
1068
1069##### void *Coroutine_GetStackHWM(void)
1070
1071(returns)
1072: The lowest address where the active Coroutine's stack has grown to ever.
1073
1074Find 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:
1075
1076 #!C
1077 Coroutine_ClearStackForHWM();
1078 char *before = (char *)Coroutine_GetStackHWM();
1079 // do the thing you want to measure here
1080 char *after = (char *)Coroutine_GetStackHWM();
1081 intptr_t amount_used = before - after;
1082
1083##### void Coroutine_ClearStackForHWM(void)
1084
1085Fill 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:
1086
1087 #!C
1088 Coroutine_ClearStackForHWM();
1089 char *before = (char *)Coroutine_GetStackHWM();
1090 // do the thing you want to measure here
1091 char *after = (char *)Coroutine_GetStackHWM();
1092 intptr_t amount_used = before - after;
1093
1094##### void *Coroutine_GetCStackTop()
1095
1096(returns)
1097: Where the Coroutine system has reached in the C stack.
1098
1099Return an address which is near to the top of used C stack.
1100
1101##### Coroutine_Err Coroutine_Chain(size_t size, Coroutine_Start start, void *value, void **result)
1102
1103(returns)
1104: Whether there was a problem. `Coroutine_OK` - `start(value)` was run; an error - there was a problem.
1105
1106size
1107: The amount of stack to give the chained Coroutine.
1108
1109start
1110: The entry point ot the chained Coroutine.
1111
1112value
1113: The value to pass to `start()`
1114
1115result
1116: Where to store the return value from `start(value)`. This may be `NULL`.
1117
1118Run `start` with `value` on a new coroutine, and return its return value in `*result`. `result`
1119may be NULL. `Coroutine_Run()` returns `false` if nothing fails, and `true` if something went wrong,
1120usually when `Coroutine_New()` ran out of stack. `stack_size` is the amount of stack made available
1121to the chained Coroutine.
1122It is expected that `Coroutine_Chain()` will be used when your coroutine is running short
1123of stack - it is not an alternative to `Coroutine_Run()`.
1124
1125##### void Coroutine_Dump_()
1126
1127*Do not use this function in production code*
1128
1129This prints the current state of the Coroutine system. It is used for development, and is not part of the official interface.
1130