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