1135 lines34.2 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. These are, mostly, in `cor_platform.h` and `cor_platform_inc.h`.
290
291There's some options in `coroutine.h` which you may need to adjust:
292
293COROUTINE_STARTUP_STACK_SIZE
294: The amount of stack set aside for `start` in `Coroutine_RunSystem()`.
295
296COROUTINE_MINIMUM_STACK_SIZE
297: The minimum stack size you'll ask for. The C stack is managed as a heap. If one of the free blocks in that
298heap is big enough for your new Coroutine, and has spare, if that spare is too small for a `Coroutine` wanting
299`COROUTINE_MINIMUM_STACK_SIZE` of stack, then the whole free block is given to your new Coroutine, instead
300of being split into two.
301
302`cor_platform.h` has customisations for your particular use case.
303
304_Cor_thread_local
305: How to declare a variable to be thread local
306
307COROUTINE_HAVE_ALLOCA_H
308: Whether your system can `#incude <alloca.h>`.
309
310_Cor_Mutex and related routines
311: Your system's mutex.
312
313_Cor_Realtime_Now
314: Return a realtime clock value compatible with _Cor_Semaphore_Wait.
315
316_Cor_Semaphore and related routines
317: Semaphores on your system.
318
319_Cor_Thread and related routines
320: Threads on your system.
321
322`cor_platform_inc.h` has more customisation for your particular use case, for coroutine.h to use.
323
324Coroutine_NS(name)
325: This allows the `Coroutine_???()` functions to be given a different naming convention.
326
327Coroutine_API_FUNC(TYPE)
328: This allows tagging of functions to be accessible to loaded dlls.
329
330# API
331
332## Task & Future
333
334The pattern for using async is:
335
336 #!C
337 bool mymaintask(void *param, void **result){
338 // do your main task things here, like starting more tasks
339 }
340
341 void *res = NULL;
342 bool canceled = Task_Run(mymaintask, NULL, &res);
343
344To create and wait for a task:
345
346 #!C
347 Task task1;
348 Task_ctor(&task1, asynctask1, &task1param);
349 void *res = NULL;
350 bool canceled = Task_Await(&task1, void **res)
351 Task_dtor(&task1);
352
353or, if you prefer new & delete:
354
355 #!C
356 Task *task1 = Task_New(asynctask1, &task1param);
357 void *res = NULL;
358 bool canceled = Task_Await(task1, void **res)
359 Task_Delete(task1);
360
361Inside 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:
362
363 #!C
364 Future future;
365 Future_ctor(&future);
366
367 // keep &future to hand for when the background thing completes
368 bool canceled = Future_Await(&future, NULL);
369
370 Future_dtor(&future);
371
372`Future_New()` and `Future_Delete()` are also available if you prefer that style.
373
374Inside the callback when the background thing is complete:
375
376 #!C
377 // result is a void *
378 Future_SetResult(future, result, false);
379
380or, if something went wrong:
381
382 #!C
383 // exception is a void *
384 Future_SetResult(future, exception, true);
385
386Back in the task, you can respond to the future:
387
388 #!C
389 ... Future_Await has returned
390 if (canceled){
391 // exit quickly - you've been canceled
392 // you could, for example, use the future's result as an exception, or error code here
393 }
394 // carry on - the future's result may be an actual result, that's up to you
395
396
397##### void Future_ctor(Future *fut)
398
399fut
400: The `Future` being constructed
401
402Initialise a future. When you no longer need it, use `Future_dtor()`.
403
404##### Future *Future_New()
405
406(returns)
407: The new future
408
409Allocates and initialises a future, When you no longer need it, use `Future_Delete()`.
410
411##### void Future_dtor(Future *fut)
412
413fut
414: The `Future` being destructed
415
416Destruct a future previously constructed with `Future_ctor()`.
417
418##### void Future_Delete(Future *fut)
419
420fut
421: The `Future` to be destructed and freed
422
423Delete (finalise and free) a future previously new'ed with `Future_New()`
424
425##### void Future_SetResult(Future *fut, bool canceled, void *value)
426
427fut
428: The `Future` whose result is being set
429
430canceled
431: The future's `canceled` setting
432
433value
434: The future's result `value`
435
436Set 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.
437
438The `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 *`.
439
440##### bool Future_GetResult(Future *fut, void **res)
441
442(returns)
443: The `canceled` value of the `Future`.
444
445res
446: Where to store the value of the `Future`. This may be `NULL`.
447
448Get the result of a future.
449
450##### typedef void (*Future_Watcher)(void *me, Future *fut)
451
452A `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.
453
454##### void Future_AddWatcher(Future *fut, Future_Watcher watcher, void *me)
455
456fut
457: the `Future` to add a watcher to
458
459watcher
460: the callback to call when the `Future` has a result.
461
462me
463: the `me` value to pass to `watcher` when it is called back.
464
465Add 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.
466
467##### void Future_RemoveWatcher(Future *fut, Future_Watcher watcher, void *me)
468
469fut
470: the `Future` to remove a watcher from
471
472watcher
473: the callback of the watcher to remove.
474
475me
476: the `me` value of the watcher to remove.
477
478Remove 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.
479
480##### bool Future_Await(Future *fut, void **res)
481
482(returns)
483: whether the `Future` was canceled.
484
485fut
486: The `Future` to wait for.
487
488res
489: Where to store the `value` of the future when it is has a result. May be `NULL`.
490
491The current `Task` is paused until the `Future` has a result. Other `Task`s are run while this one is waiting.
492
493##### typedef bool (*Task_Entry)(void *param, void **res)
494
495The entry function to an `Task`.
496
497##### void Task_ctor(Task *tsk, Task_Entry entry, void *param)
498
499tsk
500: The task to construct.
501
502entry
503: The entry function for the task.
504
505param
506: The value for `param` to pass to `entry`.
507
508Initialises an `Task`. When you have finished with an `Task` you must finalise it using `Task_dtor()`
509
510 #!C
511 Task tsk;
512 Task_ctor(&tsk, mytask, myparam);
513 // tsk will run if you wait for a task or future
514 Task_Await(&tsk, NULL);
515 Task_dtor(&tsk);
516
517##### Task *Task_New(Task_Entry entry, void *param)
518
519(returns)
520: The new `Task`.
521
522entry
523: The entry function for the task.
524
525param
526: The value for `param` to pass to `entry`.
527
528This allocates and initialises a new `Task`. When you have finished with your task, you must `Task_Delete()` it.
529
530 #!C
531 Task *tsk = Task_New(mytask, myparam);
532 // tsk will run if you wait for a task or future
533 Task_Await(tsk, NULL);
534 Task_Delete(tsk);
535
536##### void Task_dtor(Task *tsk)
537
538tsk
539: The `Task` to destruct.
540
541This finalises an `Task` you ealier initalised with `Task_ctor()`. It is an error to attempt to destruct a task which is running.
542
543 #!C
544 Task tsk;
545 Task_ctor(&tsk, mytask, myparam);
546 // use tsk
547 Task_dtor(&tsk);
548
549##### void Task_Delete(Task *tsk)
550
551tsk
552: The `Task` to delete.
553
554This 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.
555
556 #!C
557 Task *tsk = Task_New(mytask, myparam);
558 // use tsk
559 Task_Delete(tsk);
560
561##### static inline bool Task_Await(Task *tsk, void **res)
562
563(returns)
564: Whether the task was canceled.
565
566tsk
567: The `Task` to wait for.
568
569res
570: Where to store the `Task`'s value when it finishes. This may be NULL.
571
572The current `Task` waits for `tsk` to finish, and returns the result.
573
574##### void Task_Cancel(Task *tsk, void *cancel_value)
575
576tsk
577: The task to cancel.
578
579cancel_value
580: The value to set on any future this task waits on.
581
582This marks a task as canceled. When that task waits on a future that future will be canceled too, using `cancel_value`.
583
584##### static inline bool Task_IsCanceled(Task *tsk)
585
586(returns)
587: Whether the task is canceled.
588
589tsk
590: The task to get its canceled setting from.
591
592##### static inline Future *Task_GetAwaitedFuture(Task *tsk)
593
594(returns)
595: The future the task is waiting on. May be NULL.
596
597tsk
598: Teh task to read the future it is waiting on.
599
600Return the future a task is waiting on.
601
602##### bool Task_Run(Task_Entry start, void *value, void **res)
603
604(returns)
605: Whether `start` was canceled.
606
607start
608: The function to use as the main task.
609
610value
611: The value to pass to `start`.
612
613res
614: Where to store the result of `start`.
615
616Runs `start` as an `Task`. When `start` returns all other tasks must have been destructed, using `Task_dtor()` or `Task_Delete()`.
617
618## ASleep
619
620##### void ASleep_StartSystem()
621
622You must start the `ASleep` system to use it. This needs to happen per process. Once you've finished with `ASleep` you must `ASleep_StopSystem()`.
623
624 #!C
625 ASleep_StartSystem();
626 // Now you can use ASleep() on any thread
627 ASleep_StopSystem();
628
629##### void ASleep_StopSystem()
630
631Call this to stop the `ASleep` system.
632
633##### bool ASleep(float delay, void **value)
634
635(returns)
636: Whether the task was canceled.
637
638delay
639: How many seconds to delay for.
640
641value
642: Where to store the cancellation value. This may be NULL.
643
644Sleep for `delay` seconds. `*value` will be set to `NULL` if the sleep is successful, and the `cancel_value` if the task is canceled.
645
646## Generator
647
648The pattern for a `Generator` is:
649
650#### A loop which uses the `Generator
651
652 #!C
653 Generator gen;
654 Generator_ctor(&gen, generator_stack_size, mygen, &param);
655
656 void *value;
657 while(Generator_Next(&gen, &value)){
658 // use value here
659 }
660 // value is now the return value from the Generator
661
662 Generator_dtor(&gen);
663
664Or:
665
666 #!C
667 Generator *gen = Generator_New(generator_stack_size, mygen, &param);
668
669 void *value;
670 while(Generator_Next(gen, &value)){
671 // use value here
672 }
673
674 Generator_Delete(gen);
675
676`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.
677The `generator_stack_size` is the stack amount made available to your generator.
678
679#### A generator function
680
681 #!C
682 void *mygen(void *param){
683 bool domore = true;
684 // The parameter is a pointer to a string of chars
685 for (char *str = param; *str; ++str) {
686 // The value yielded is a pointer to a character in the string
687 domore = Generator_Yield(str);
688 if (!domore){
689 break;
690 }
691 }
692
693 return (void *)domore;
694 }
695
696The `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.
697
698##### void Generator_ctor(Generator *gen, size_t generator_stack_size, void *(*start)(void *), void *param)
699
700gen
701: The `Generator` to construct.
702
703generator_stack_size
704: The amount of stack given to the generator.
705
706start
707: The function which is the start/entry-point of the `Generator`.
708
709param
710: The value to pass to `start`.
711
712Initialise a `Generator`. When you no longer need the `Generator`, use `Generator_dtor()` to destruct it.
713
714 #!C
715 Generator gen;
716 Generator_ctor(&gen, generator_stack_size, mystart, &params);
717
718 // Generator is used
719
720 // ... later:
721 Generator_dtor(&gen);
722
723##### Generator *Generator_New(size_t generator_stack_size, void *(*start)(void *), void *param)
724
725generator_stack_size
726: The amount of stack to give to the generator.
727
728start
729: The function which is the start/entry-point of the `Generator`.
730
731param
732: The value to pass to `start`.
733
734`new` a `Generator` - malloc, and initialise it. When you no longer need the `Generator` use `Generator_dtor` to finalise it.
735
736 #!C
737 Generator *gen = Generator_New(mystart, &params);
738
739 // Generator is used
740
741 // ... later:
742 Generator_Delete(gen);
743
744##### void Generator_dtor(Generator *gen)
745
746gen
747: The `Generator` to destruct.
748
749Finalise a `Generator`. Once a `Generator` is no longer needed, it must be finalised:
750
751 #!C
752 // earlier...
753 Generator gen;
754 Generator_ctor(&gen, generator_stack_size, mystart, &params);
755
756 // Generator is used
757
758 // the Generator is no longer needed
759 Generator_dtor(&gen);
760
761
762##### void Generator_Delete(Generator *gen)
763
764gen
765: The `Generator` to delete.
766
767Finalise then `free()` a `Generator`. Once a `new`ed `Generator` is no longer needed, it must be deleted:
768
769 #!C
770 // earlier...
771 Generator *gen = Generator_New(mystart, &params);
772
773 // Generator is used
774
775 // the Generator is no longer needed
776 Generator_Delete(gen);
777
778
779##### bool Generator_Next(Generator *gen, void **value)
780
781(returns)
782: Whether there is a next value. `true` - there is a next value; `false` - the `Generator` has finished
783
784gen
785: The `Generator` to get the next value from.
786
787value
788: Where to store the next value.
789
790Get the next value yielded by the `Generator`.
791
792 #!C
793 void *value;
794 while(Generator_Next(gen, &value)){
795 // use value here
796 }
797
798The `Generator` feeds values to its client using `Generator_Yield()` - it is these values which `Generator_Next()` sets, in the example, `value` to.
799
800 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`.
801
802##### bool Generator_Yield(void *value)
803
804(returns)
805: Whether the `Generator` should do more.
806
807value
808: The `Generator`'s next value.
809
810Yield a value from a `Generator`.
811
812 #!C
813 bool domore = Generator_Yield(value);
814
815`value` is then provided by `Generator_Next()` as the next value from the generator.
816
817The `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.
818
819## Coroutine
820
821##### Coroutine_Err
822
823The enum of errors:
824
825Coroutine_OK
826: Everything is OK. This is 0
827
828Coroutine_Err_SystemNotRunning
829: A `Coroutine` must be running to do this
830
831Coroutine_Err_SystemRunning
832: The `Coroutine` system must not be running to do this
833
834Coroutine_Err_NoStack
835: Not enough stack is available
836
837Coroutine_Err_CoroutineFromWrongThread
838: Trying to do something on one thread to a `Coroutine` from a different thread
839
840Coroutine_Err_ACoroutineIsAlreadyRunning
841: Trying `Coroutine_RunCoroutine` a `Coroutine`
842
843Coroutine_Err_ExitWithRunningCoroutines
844: All `Coroutine`s must be complete
845
846Coroutine_Err_StackOverrun
847: Stack overrun detected
848
849Coroutine_Err_InternalInsistency
850: Something didn't match inside the system
851
852Coroutine_Err_CouldNotInitialiseSystem
853: Something went wrong initialising (eg couldn't create a lock)
854
855Coroutine_Err_WrongState
856: It's in the wrong statem, eg trying to `Coroutine_Continue` a completed `Coroutine`
857
858Coroutine_Err_Canceled
859: It's canceled
860
861##### Coroutine_SetStackLimit(void *limit)
862
863limit
864: The location (low address) of the stack's end.
865
866Set the limit of the stack. This is used to determine more accurately whether `Coroutine_CanStartCoroutine()`
867
868##### Coroutine_Report Coroutine_GetReport()
869
870(returns)
871: A report from this run of the Coroutine system.
872
873 #!C
874 typedef struct Coroutine_Report {
875 unsigned coroutines_created;
876 unsigned coroutines_pool_size;
877 unsigned lowest_headroom;
878 } Coroutine_Report;
879
880coroutines_created
881: How many coroutines were created
882
883coroutines_pool_size
884: 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.
885
886lowest_headroom
887: The lowest headroom (unused
888
889largest_stack
890: The largest stack requested for any `Coroutine`.
891
892##### Coroutine_CheckIntegrity()
893
894(returns)
895: `Coroutine_Err` for any problem
896
897Check the integrity of the coroutine system, and `printf()` any problems.
898
899##### Coroutine_Start
900
901 #!C
902 void *(*)(void *param)
903
904The 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()`.
905
906##### Coroutine_SystemStart
907
908 #!C
909 Coroutine_Err (*)(void *)
910
911The entry function for `Coroutine_RunSystem`.
912
913##### Coroutine_Err Coroutine_RunSystem(Coroutine_SystemStart start, void *value)
914
915(returns)
916: `Coroutine_OK` or an error. If the system starts, this will be the value returned by `start`.
917
918start
919: The function to call with the `Coroutine` system started. It is expected that this routine will
920start a `Coroutine`.
921
922value
923: The value to pass to `start`.
924
925##### Coroutine *Coroutine_New(size_t size, Coroutine_Start start)
926
927(returns)
928A new Coroutine, or `NULL` if there was a failure, such as insufficient stack for the new Coroutine.
929
930size
931: The stack size given to this Coroutine.
932
933start
934: The routine called to start the Coroutine.
935
936Create 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.
937
938##### Coroutine_Err Coroutine_Run_Coroutine(Coroutine *cor, void *value)
939
940(returns)
941: any problem, or `Coroutine_OK`
942
943cor
944: The Coroutine to run.
945
946value
947: The value to pass to the Coroutine's `start` routine.
948
949Run 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.
950
951##### Coroutine_Err Coroutine_Run(size_t size, Coroutine_Start start, void *value, void **result)
952
953(returns)
954: `Coroutine_OK` or any problem
955
956size
957: The stack size to give to the Corotuine.
958
959start
960: The routine to start the Coroutine.
961
962value
963: The value to pass to `start()`.
964
965result
966: Where to store the return value from `start(value)`. This may be `NULL`.
967
968`start(value)` is called from within a coroutine and its value returned in `*result`.
969If this completes without any failure, `false` is returned, otherwise, typically
970because `Coroutine_New()` returned `NULL`, `true` is returned. `result` may be `NULL` if you don't
971need the resturn value from `start()`.
972When the coroutine system is active - you are already running in a coroutine - `start(value)`
973is simply called and its result returned in `*result`. When the Coroutine system is not running,
974`Coroutine_Run()` starts it, creates a `Coroutine` and runs that Coroutine to call `start(calue)`
975and return value is returned in `*result`, then stops the Coroutine system. If you need to force
976a new Coroutine to be created, with a particular stack size to call `start(value)`, then use
977`Coroutine_Chain()` instead.
978
979The total stack allowed for all coroutines running on any thread is the size of the call stack on that thread.
980
981##### void Coroutine_Delete(Coroutine *cor)
982
983cor
984: The Coroutine to delete.
985
986Use `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.
987
988##### Coroutine_Err Coroutine_Continue(Coroutine *cor, void *value, bool early)
989
990(returns)
991: `Coroutine_OK` or any error.
992
993cor
994: The Coroutine to continue.
995
996value
997: The value to return from `cor`'s yield function.
998
999early
1000: Whether to continue `cor` early (`true`), or late (`false`). Early means before other Coroutines which are waiting
1001to be called, whereas late means after them.
1002
1003Continue 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.
1004
1005##### void *Coroutine_Yield(void *value, Coroutine_YieldCallback on_yield, void *this)
1006
1007value
1008: The value to yield fropm the coroutine.
1009
1010on_yield
1011: A callback to be called once this Coroutine has yielded, but before another one has been continued.
1012
1013this
1014: The parameter to pass to `on_yield`.
1015
1016Yield `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()`.
1017
1018##### void *Coroutine_GetValue(Coroutine *cor)
1019
1020(returns)
1021: The Coroutine's value - the last yielded or returned value.
1022
1023cor
1024: The Coroutine to query.
1025
1026Return the `Coroutine`'s value - the value last yielded, or returned by its `start` routine.
1027
1028##### Coroutine *Coroutine_GetActive()
1029
1030(returns)
1031: The currently active Coroutine.
1032
1033Return whihc coroutine is currently running, ie the caller's `Coroutine`.
1034
1035##### bool Coroutine_IsRunning(Coroutine *cor)
1036
1037(returns)
1038: Whether `cor` is running - it's the active coroutine or waiting to be continued.
1039
1040cor
1041: The Coroutine to query.
1042
1043Return 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.
1044
1045##### bool Coroutine_IsComplete(Coroutine *cor)
1046
1047(returns)
1048: Whether `cor` is complete, ie has returned from `start()`./
1049
1050cor
1051: The Coroutine to query.
1052
1053Return whether the given coroutine is complete - is has returned from its `start` function.
1054
1055##### intptr_t Coroutine_GetStackHeadroom()
1056
1057(returns)
1058: The amount of stack headroom.
1059
1060Return 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.
1061
1062##### bool Coroutine_CanStartCoroutine(size_t size)
1063
1064(returns)
1065: Whether a Coroutine with the given amount of stack could be created.
1066
1067size
1068: The amount of stack in the Coroutine we might want to create.
1069
1070Return whether the coroutine system can start a new coroutine. This check can only be done with the coroutine system active (currently running
1071a 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
1072stack use `Coroutine_SetStackLimit()`
1073
1074##### void *Coroutine_GetStackHWM(void)
1075
1076(returns)
1077: The lowest address where the active Coroutine's stack has grown to ever.
1078
1079Find 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:
1080
1081 #!C
1082 Coroutine_ClearStackForHWM();
1083 char *before = (char *)Coroutine_GetStackHWM();
1084 // do the thing you want to measure here
1085 char *after = (char *)Coroutine_GetStackHWM();
1086 intptr_t amount_used = before - after;
1087
1088##### void Coroutine_ClearStackForHWM(void)
1089
1090Fill 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:
1091
1092 #!C
1093 Coroutine_ClearStackForHWM();
1094 char *before = (char *)Coroutine_GetStackHWM();
1095 // do the thing you want to measure here
1096 char *after = (char *)Coroutine_GetStackHWM();
1097 intptr_t amount_used = before - after;
1098
1099##### void *Coroutine_GetCStackTop()
1100
1101(returns)
1102: Where the Coroutine system has reached in the C stack.
1103
1104Return an address which is near to the top of used C stack.
1105
1106##### Coroutine_Err Coroutine_Chain(size_t size, Coroutine_Start start, void *value, void **result)
1107
1108(returns)
1109: Whether there was a problem. `Coroutine_OK` - `start(value)` was run; an error - there was a problem.
1110
1111size
1112: The amount of stack to give the chained Coroutine.
1113
1114start
1115: The entry point ot the chained Coroutine.
1116
1117value
1118: The value to pass to `start()`
1119
1120result
1121: Where to store the return value from `start(value)`. This may be `NULL`.
1122
1123Run `start` with `value` on a new coroutine, and return its return value in `*result`. `result`
1124may be NULL. `Coroutine_Run()` returns `false` if nothing fails, and `true` if something went wrong,
1125usually when `Coroutine_New()` ran out of stack. `stack_size` is the amount of stack made available
1126to the chained Coroutine.
1127It is expected that `Coroutine_Chain()` will be used when your coroutine is running short
1128of stack - it is not an alternative to `Coroutine_Run()`.
1129
1130##### void Coroutine_Dump_()
1131
1132*Do not use this function in production code*
1133
1134This prints the current state of the Coroutine system. It is used for development, and is not part of the official interface.
1135