blob: 77cb0a3047f2db4fae135b7a1f6bffa85271813d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
/* coroutine.h - Simple coroutine and request/response implementation
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
*/
#ifndef _COROUTINE_H_
#define _COROUTINE_H_
#include <stddef.h> /* for size_t */
#include <stdbool.h> /* for bool, true, false */
/* typedefs *******************************************************************/
typedef size_t cid_t; /* 0=none; otherwise 1-indexed */
typedef void (*cr_fn_t)(void *stack);
typedef struct {
cr_fn_t fn;
void *stack;
unsigned int state;
bool blocked;
} _cr_entry_t;
/* globals ********************************************************************/
extern _cr_entry_t *_coroutine_table;
extern cid_t _cur_cid;
/* bona-fide functions ********************************************************/
void coroutine_init(void);
cid_t coroutine_add(cr_fn_t fn, void *stack);
void coroutine_task(void);
/* core macros for use in a cr_fn_t() *****************************************/
#define cr_begin() switch(_coroutine_table[_cur_cid].state) { case 0:
#define cr_exit() do { _coroutine_table[_cur_cid] = (cr_entry_t){0}; return; } while (0)
#define cr_yield() _cr_yield(__COUNTER__)
#define _cr_yield(_state) do { _coroutine_table[_cur_cid].state = _state; return; case _state:; } while (0)
#define cr_end() }
/* request/response channels **************************************************/
#define cr_chan_t(req_t, resp_t) struct { \
cid_t requester; \
cid_t responder; \
req_t req; \
resp_t resp; \
}
#define cr_chan_req(ch, _resp_p, _req) do { \
(ch)->requester = _cur_cid; \
(ch)->req = (_req); \
if ((ch)->responder != 0) \
_coroutine_table[(ch)->responder].blocked = false; \
_coroutine_table[_cur_cid].blocked = true; \
cr_yield(); \
if ((typeof(&(ch)->resp))(_resp_p)) \
*((typeof(&(ch)->resp))(_resp_p)) = (ch)->resp; \
} while (0)
#define cr_chan_have_req(ch) ((ch)->requester != 0)
#define cr_chan_recv_req(ch, _req_p) do { \
(ch)->responder = _cur_cid; \
if ((ch)->requester == 0) { \
_coroutine_table[_cur_cid].blocked = true; \
cr_yield(); \
} \
*(_req_p) = (ch)->req; \
} while (0)
#define cr_chan_send_resp(ch, _resp) do { \
(ch)->responder = 0; \
(ch)->requester = 0; \
(ch)->resp = (_resp); \
_coroutine_table[(ch)->requester].blocked = false; \
} while (0)
#endif /* _COROUTINE_H_ */
|