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