-
Notifications
You must be signed in to change notification settings - Fork 2
/
carrow.h
225 lines (175 loc) · 5.83 KB
/
carrow.h
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Copyright 2023 Vahid Mardani
/*
* This file is part of Carrow.
* Carrow is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Carrow is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Carrow. If not, see <https://www.gnu.org/licenses/>.
*
* Author: Vahid Mardani <vahid.mardani@gmail.com>
*/
#ifndef CARROW_H_
#define CARROW_H_
#include <stdbool.h>
#include <errno.h>
#include <sys/epoll.h>
/* Coroutine */
#define CORO_START \
if (self->events == 0) goto carrow_finally; \
switch (self->line) { \
case 0:
#define CORO_REJECT(...) \
ERROR(__VA_ARGS__); \
goto carrow_finally
#define CORO_WAIT(f, e) \
do { \
self->line = __LINE__; \
self->fd = f; \
self->events = e | CONCE; \
return; \
case __LINE__:; \
} while (0)
#define CORO_SLEEP(sec) \
do { \
if (carrow_sleep((struct carrow_generic_coro*)self, sec, __LINE__)) \
goto carrow_finally;\
return; \
case __LINE__: \
carrow_evloop_unregister(self->fd); \
close(self->fd); \
self->fd = -1; \
} while (0)
#define CORO_FINALLY \
} \
carrow_finally: \
self->run = NULL
#define CORO_NEXT(f) \
do { \
self->run = f; \
self->fd = -1; \
self->line = 0; \
} while (0)
#define CORO_CLEANUP \
if (self->fd != -1) { \
carrow_evloop_unregister(self->fd); \
close(self->fd); \
} \
self->run = NULL
/* Generic stuff */
#define CARROW_NAME_PASTER(x, y) x ## _ ## y
#define CARROW_NAME_EVALUATOR(x, y) CARROW_NAME_PASTER(x, y)
#define CARROW_NAME(n) CARROW_NAME_EVALUATOR(CARROW_ENTITY, n)
#define __FILENAME__ \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define CMUSTWAIT() ((errno == EAGAIN) || (errno == EWOULDBLOCK) \
|| (errno == EINPROGRESS))
#define CIN EPOLLIN // 1
#define COUT EPOLLOUT // 4
#define CET EPOLLET // -2147483648
#define CONCE EPOLLONESHOT // 1073741824
#define CRDHUP EPOLLRDHUP // 8192
#define CPRI EPOLLPRI // 2
#define CERR EPOLLERR // 8
#define CHUP EPOLLHUP // 16
#define CWAKEUP EPOLLWAKEUP // 536870912
/**
* @brief A struct representing a coroutine state.
* It contains the file descriptor, the event mask, and the line number
* where the coroutine was last suspended.
*/
struct carrow_generic_coro {
void *run;
int line;
int fd;
int events; // events bitflags
};
/**
* @brief A function pointer type representing a coroutine handler function.
*/
typedef void (*carrow_generic_corofunc) (void *coro, void *state);
/**
* @brief A function that initializes the event loop with the given maximum
* number of file descriptors.
*/
int
carrow_init(unsigned int openmax);
/**
* @brief A function that frees the memory allocated for the _evbags array.
*/
void
carrow_deinit();
/**
* @brief A function that registers a coroutine with the event loop for a
* given file descriptor and event mask. It sets the evbag for the
* given file descriptor with the provided coroutine state and handler
* function, and adds the file descriptor to the epoll instance.
*/
int
carrow_evloop_register(void *coro, void *state, int fd, int events,
carrow_generic_corofunc handler);
/**
* @brief A function that modifies the coroutine state and handler function
* for a given file descriptor in the event loop.
*/
int
carrow_evloop_modify(void *c, void *state, int fd, int events,
carrow_generic_corofunc handler);
/**
* @brief A function that modifies the coroutine state and handler function
* for a given file descriptor in the event loop if it exists, or
* registers a new coroutine with the provided state and handler
* function if it does not.
*/
int
carrow_evloop_modify_or_register(void *coro, void *state, int fd, int events,
carrow_generic_corofunc handler);
/**
* @brief A function that unregisters a coroutine for a given file descriptor
* from the event loop and deletes its evbag.
*/
int
carrow_evloop_unregister(int fd);
/**
* @brief A function that runs the event loop until the _evbagscount is zero
* or the status is set to a value less than or equal to EXIT_FAILURE.
* It waits for events on the epoll instance and triggers the
* corresponding coroutines when events occur.
*/
int
carrow_evloop(volatile int *status);
/**
* @brief A function that set the coroutine state and coroutine handler for
* the given file descriptor.
*/
int
carrow_evbag_unpack(int fd, struct carrow_generic_coro *coro, void **state,
carrow_generic_corofunc *handler);
/**
* @brief A function that installs a signal handler for SIGINT that sets the
* _carrow_status variable to EXIT_SUCCESS.
*/
int
carrow_handleinterrupts();
/**
* @brief A function that creates a timer file descriptor and sets it to
* expire after the given number of seconds. It sets the coroutine
* state to wait on the timer file descriptor and returns the line
* number where the coroutine was suspended.
*/
int
carrow_sleep(struct carrow_generic_coro *self, unsigned int seconds,
int line);
/** @brief A function that triggers the coroutine associated with the given
* file descriptor with the provided event mask.
*/
int
carrow_trigger(int fd, int events);
#endif // CARROW_H_