123 lines4.4 KB
1#ifndef COROUTINE_H
2#define COROUTINE_H
3
4#include <stdbool.h>
5
6///////////////////////////////////////////////////////////////////////////////
7// Coroutine
8//
9// Coroutines for C, based on setjmp/longjmp.
10// Thread safe - each thread has its own coroutine system
11// Coroutines are cooperatively scheduled
12// Coroutines have their own stack (currently 16K each)
13// A coroutine can be continued, queried, or deleted on a different thread.
14//
15// Usage:
16// Coroutine_StartSystem(); // call once per thread before using coroutines
17// Coroutine *co = Coroutine_New(start_function);
18// void *result = Coroutine_Run(co, initial_value);
19// Coroutine_Delete(co);
20// Coroutine_StopSystem(); // call once per thread when done with coroutines
21//
22// Inside the coroutine function:
23// void *value = Coroutine_Yield(yield_value, on_yield, this);
24// ...
25// return return_value;
26//
27// To create a coroutine:
28// Coroutine *co = Coroutine_New(start_function);
29// To start or continue a coroutine:
30// void *result = Coroutine_Continue(co, value, early);
31// // early=true puts the coroutine at the head of the run queue
32// // early=false puts the coroutine at the tail of the run queue
33// To yield from inside a coroutine:
34// void *value = Coroutine_Yield(yield_value, on_yield, this);
35// // on_yield is called before the next coroutine is run
36// // 'this' is passed to on_yield as its parameter
37// // value is the value passed to Coroutine_Continue
38// To delete a coroutine:
39// Coroutine_Delete(co);
40// To get the value yielded from, or returned by a corotuine:
41// void *value = Coroutine_GetValue(co);
42// To get the currently running coroutine (NULL if none):
43// Coroutine *co = Coroutine_GetActive();
44// To check if a coroutine is currently running:
45// bool running = Coroutine_IsRunning(co);
46//
47// Notes:
48// Coroutine is not expected to be used directly, but as a foundation for
49// higher level constructs such as Generators, Async, etc.
50//
51///////////////////////////////////////////////////////////////////////////////
52
53
54// The stack is used as follows:
55// +------------------+ <- stack top
56// | coroutine header | <- more claimed as needed in Coroutine_New
57// +------------------+ <-
58// | coroutine stack | <-
59// +------------------+ <-
60// | coroutine header |
61// +------------------+
62// | coroutine stack |
63// +------------------+
64// | coroutine header |
65// +------------------+
66// | coroutine stack |
67// +------------------+
68// | coroutine header |
69// +------------------+
70// | coroutine stack |
71// +------------------+
72// | coroutine header |
73// +------------------+
74// | startup space | <- set aside by Coroutine_StartSystem
75// +------------------+
76// | caller | <- This calls Coroutine_StartSystem etc
77// +------------------+
78// | used stack |
79// +------------------+ <- stack bottom
80
81// Each coroutine has this much stack:
82#ifndef COROUTINE_STACK_SIZE
83 #define COROUTINE_STACK_SIZE 65536
84#endif
85
86// When Coroutine is started, an amount of stack is set aside to give
87// the caller of Coroutine_StartSystem a bit of room to work before calling
88// Coroutine_Run(), that is this amount:
89#ifndef COROUTINE_STARTUP_STACK_SIZE
90 #define COROUTINE_STARTUP_STACK_SIZE 4096
91#endif
92
93// Returned by Coroutine_StopSystem(), this summarises the coroutine session
94typedef struct Coroutine_Report {
95 unsigned coroutines_created;
96 unsigned coroutines_pool_size;
97 unsigned lowest_headroom;
98} Coroutine_Report;
99
100typedef struct Coroutine Coroutine;
101
102typedef void (*Coroutine_YieldCallback)(void *me);
103typedef void *(*Coroutine_Start)(void *);
104
105extern void Coroutine_StartSystem(void);
106extern Coroutine_Report Coroutine_StopSystem(void);
107extern Coroutine *Coroutine_New(Coroutine_Start start);
108extern void Coroutine_Run_Coroutine(Coroutine *cor, void *value);
109extern void *Coroutine_Run(Coroutine_Start start, void *value);
110extern void Coroutine_Delete(Coroutine *cor);
111extern void Coroutine_Continue(Coroutine *cor, void *value, bool early);
112extern void *Coroutine_Yield(void *value, Coroutine_YieldCallback on_yield, void *me);
113extern void *Coroutine_GetValue(Coroutine *cor);
114extern Coroutine *Coroutine_GetActive(void);
115extern int Coroutine_GetStackHeadroom(void);
116extern bool Coroutine_HasCoroutinesInFreePool(void);
117extern void *Coroutine_GetCStackTop(void);
118extern void *Coroutine_Chain(Coroutine_Start start, void *value);
119extern bool Coroutine_IsStarted(void);
120extern bool Coroutine_IsRunning(Coroutine *cor);
121
122#endif
123