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