Lely core libraries 2.3.4
thrd_loop.c
Go to the documentation of this file.
1
24#include "ev.h"
25#include <lely/ev/exec.h>
26#include <lely/ev/task.h>
27#include <lely/ev/thrd_loop.h>
28
29#include <assert.h>
30#include <stdint.h>
31
32static void ev_thrd_loop_exec_on_task_init(ev_exec_t *exec);
33static void ev_thrd_loop_exec_on_task_fini(ev_exec_t *exec);
34static int ev_thrd_loop_exec_dispatch(ev_exec_t *exec, struct ev_task *task);
35static void ev_thrd_loop_exec_defer(ev_exec_t *exec, struct ev_task *task);
36static size_t ev_thrd_loop_exec_abort(ev_exec_t *exec, struct ev_task *task);
37static void ev_thrd_loop_exec_run(ev_exec_t *exec, struct ev_task *task);
38
39// clang-format off
40static const struct ev_exec_vtbl ev_thrd_loop_exec_vtbl = {
41 &ev_thrd_loop_exec_on_task_init,
42 &ev_thrd_loop_exec_on_task_fini,
43 &ev_thrd_loop_exec_dispatch,
44 &ev_thrd_loop_exec_defer,
45 &ev_thrd_loop_exec_defer,
46 &ev_thrd_loop_exec_abort,
47 &ev_thrd_loop_exec_run
48};
49// clang-format on
50
54 struct sllist queue;
61 size_t ntasks;
66};
67
69static struct ev_thrd_loop *ev_thrd_loop(void);
70
71static void ev_thrd_loop_on_task_init(struct ev_thrd_loop *loop);
72static void ev_thrd_loop_on_task_fini(struct ev_thrd_loop *loop);
73
76{
77 static ev_exec_t ev_thrd_loop_exec = &ev_thrd_loop_exec_vtbl;
78
79 return &ev_thrd_loop_exec;
80}
81
82void
84{
85 ev_thrd_loop()->stopped = 1;
86}
87
88int
90{
91 return ev_thrd_loop()->stopped;
92}
93
94void
96{
97 ev_thrd_loop()->stopped = 0;
98}
99
100size_t
102{
103 size_t n = 0;
104 while (ev_thrd_loop_run_one())
105 n += n < SIZE_MAX;
106 return n;
107}
108
109size_t
111{
112 struct ev_thrd_loop *loop = ev_thrd_loop();
113
114 if (loop->stopped)
115 return 0;
116
117 struct ev_task *task =
119 if (!task) {
120 if (!loop->ntasks)
121 loop->stopped = 1;
122 return 0;
123 }
124
125 assert(task->exec);
126 ev_exec_run(task->exec, task);
127
128 ev_thrd_loop_on_task_fini(ev_thrd_loop());
129
130 return 1;
131}
132
133static void
134ev_thrd_loop_exec_on_task_init(ev_exec_t *exec)
135{
136 assert(exec == ev_thrd_loop_get_exec());
137 (void)exec;
138
139 ev_thrd_loop_on_task_init(ev_thrd_loop());
140}
141
142static void
143ev_thrd_loop_exec_on_task_fini(ev_exec_t *exec)
144{
145 assert(exec == ev_thrd_loop_get_exec());
146 (void)exec;
147
148 ev_thrd_loop_on_task_fini(ev_thrd_loop());
149}
150
151static int
152ev_thrd_loop_exec_dispatch(ev_exec_t *exec, struct ev_task *task)
153{
154 assert(exec == ev_thrd_loop_get_exec());
155 assert(task);
156
157 if (!task->exec)
158 task->exec = exec;
159 assert(task->exec == exec);
160
161 struct ev_thrd_loop *loop = ev_thrd_loop();
162 ev_thrd_loop_on_task_init(loop);
163 if (loop->running) {
164 ev_thrd_loop_exec_run(exec, task);
165 ev_thrd_loop_on_task_fini(loop);
166 return 1;
167 } else {
168 sllist_push_back(&loop->queue, &task->_node);
169 return 0;
170 }
171}
172
173static void
174ev_thrd_loop_exec_defer(ev_exec_t *exec, struct ev_task *task)
175{
176 assert(exec == ev_thrd_loop_get_exec());
177 assert(task);
178
179 if (!task->exec)
180 task->exec = exec;
181 assert(task->exec == exec);
182
183 struct ev_thrd_loop *loop = ev_thrd_loop();
184 ev_thrd_loop_on_task_init(loop);
185 sllist_push_back(&loop->queue, &task->_node);
186}
187
188static size_t
189ev_thrd_loop_exec_abort(ev_exec_t *exec, struct ev_task *task)
190{
191 assert(exec == ev_thrd_loop_get_exec());
192 (void)exec;
193
194 struct ev_thrd_loop *loop = ev_thrd_loop();
195
196 size_t n = 0;
197 if (!task) {
198 while (sllist_pop_front(&loop->queue)) {
199 ev_thrd_loop_on_task_fini(loop);
200 n += n < SIZE_MAX;
201 }
202 } else if (sllist_remove(&loop->queue, &task->_node)) {
203 ev_thrd_loop_on_task_fini(loop);
204 n++;
205 }
206 return n;
207}
208
209static void
210ev_thrd_loop_exec_run(ev_exec_t *exec, struct ev_task *task)
211{
212 assert(exec == ev_thrd_loop_get_exec());
213 assert(task);
214
215 if (!task->exec)
216 task->exec = exec;
217 assert(task->exec == exec);
218
219 struct ev_thrd_loop *loop = ev_thrd_loop();
220
221 if (task->func) {
222 int running = loop->running;
223 loop->running = 1;
224
225 task->func(task);
226
227 // cppcheck-suppress redundantAssignment
228 loop->running = running;
229 }
230}
231
232static struct ev_thrd_loop *
234{
235#if LELY_NO_THREADS
236 static struct ev_thrd_loop *loop;
237#else
238 static _Thread_local struct ev_thrd_loop *loop;
239#endif
240 if (!loop) {
241#if LELY_NO_THREADS
242 static struct ev_thrd_loop loop_;
243#else
244 static _Thread_local struct ev_thrd_loop loop_;
245#endif
246 sllist_init(&loop_.queue);
247 loop_.ntasks = 0;
248 loop_.stopped = 0;
249 loop_.running = 0;
250 loop = &loop_;
251 }
252 return loop;
253}
254
255static void
256ev_thrd_loop_on_task_init(struct ev_thrd_loop *loop)
257{
258 assert(loop);
259
260 loop->ntasks++;
261}
262
263static void
264ev_thrd_loop_on_task_fini(struct ev_thrd_loop *loop)
265{
266 assert(loop);
267 assert(loop->ntasks);
268
269 if (!--loop->ntasks)
270 loop->stopped = 1;
271}
This header file is part of the event library; it contains the abstract task executor interface.
void ev_exec_run(ev_exec_t *exec, struct ev_task *task)
Invokes the task function in *task as if the task is being executed by *exec.
Definition exec.h:142
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
Definition features.h:249
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition ev.h:29
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition sllist.h:194
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition sllist.c:46
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition sllist.h:232
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition sllist.h:243
This is the internal header file of the event library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdint....
An executable task.
Definition task.h:41
ev_task_func_t * func
The function to be invoked when the task is run.
Definition task.h:45
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition task.h:43
A thread-local event loop.
Definition thrd_loop.c:52
int stopped
A flag specifying whether the event loop is stopped.
Definition thrd_loop.c:63
size_t ntasks
The number of pending tasks.
Definition thrd_loop.c:61
int running
A flag specifying whether ev_exec_run() is running on this thread.
Definition thrd_loop.c:65
struct sllist queue
The queue of pending tasks.
Definition thrd_loop.c:54
A singly-linked list.
Definition sllist.h:52
This header file is part of the event library; it contains the task declarations.
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
Definition task.c:32
size_t ev_thrd_loop_run(void)
If the thread-local event loop is not stopped, run all available tasks.
Definition thrd_loop.c:101
ev_exec_t * ev_thrd_loop_get_exec(void)
Returns a pointer to the executor corresponding to the thread-local event loop.
Definition thrd_loop.c:75
void ev_thrd_loop_stop(void)
Stops the thread-local event loop.
Definition thrd_loop.c:83
size_t ev_thrd_loop_run_one(void)
If the thread-local event loop is not stopped, executes the first task submitted to it,...
Definition thrd_loop.c:110
void ev_thrd_loop_restart(void)
Restarts a thread-local event loop.
Definition thrd_loop.c:95
int ev_thrd_loop_stopped(void)
Returns 1 if the thread-local event loop is stopped, and 0 if not.
Definition thrd_loop.c:89
This header file is part of the event library; it contains the thread-local event loop declarations.