Add support for L4Re Virtio Sockets
[src/app-framework-binder.git] / src / evmgr.c
1 /*
2  * Copyright (C) 2016-2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <time.h>
26 #include <sys/syscall.h>
27 #include <pthread.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <sys/eventfd.h>
31
32 #include <systemd/sd-event.h>
33
34 #include "evmgr.h"
35 #include "verbose.h"
36
37 #if WITH_SYSTEMD
38 #include "systemd.h"
39 #else
40 #include "fdev-epoll.h"
41 #include "fdev.h"
42 #endif
43
44 /** Description of handled event loops */
45 struct evmgr
46 {
47         int efd;               /**< event notification */
48         unsigned state;        /**< encoded state */
49         void *holder;          /**< holder of the evmgr */
50 #if WITH_SYSTEMD
51         struct sd_event *sdev; /**< the systemd event loop */
52 #endif
53 #if WITH_FDEV_EPOLL
54         struct fdev_epoll *fdev_epoll;
55         struct fdev *fdev;
56 #endif
57 };
58
59 #define EVLOOP_STATE_WAIT           1U
60 #define EVLOOP_STATE_RUN            2U
61
62
63 /**
64  * Internal callback for evmgr management.
65  * The effect of this function is hidden: it exits
66  * the waiting poll if any.
67  */
68 static void evmgr_on_efd_event(struct evmgr *evmgr)
69 {
70         uint64_t x;
71         read(evmgr->efd, &x, sizeof x);
72 }
73
74 /**
75  * wakeup the event loop if needed by sending
76  * an event.
77  */
78 void evmgr_wakeup(struct evmgr *evmgr)
79 {
80         uint64_t x;
81
82         if (evmgr->state & EVLOOP_STATE_WAIT) {
83                 x = 1;
84                 write(evmgr->efd, &x, sizeof x);
85         }
86 }
87
88 /**
89  */
90 void *evmgr_holder(struct evmgr *evmgr)
91 {
92         return evmgr->holder;
93 }
94
95 /**
96  */
97 int evmgr_release_if(struct evmgr *evmgr, void *holder)
98 {
99         if (evmgr->holder != holder)
100                 return 0;
101         evmgr->holder = 0;
102         return 1;
103 }
104
105 /**
106  */
107 int evmgr_try_hold(struct evmgr *evmgr, void *holder)
108 {
109         if (!evmgr->holder)
110                 evmgr->holder = holder;
111         return evmgr->holder == holder;
112 }
113
114 /******************************************************************************/
115 /******************************************************************************/
116 /******  SYSTEM D                                                        ******/
117 /******************************************************************************/
118 /******************************************************************************/
119
120 #if WITH_SYSTEMD
121
122 /**
123  * Run the event loop is set.
124  */
125 void evmgr_run(struct evmgr *evmgr)
126 {
127         int rc;
128         struct sd_event *se;
129
130         evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
131         se = evmgr->sdev;
132         rc = sd_event_prepare(se);
133         if (rc < 0) {
134                 errno = -rc;
135                 CRITICAL("sd_event_prepare returned an error (state: %d): %m", sd_event_get_state(se));
136                 abort();
137         } else {
138                 if (rc == 0) {
139                         rc = sd_event_wait(se, (uint64_t)(int64_t)-1);
140                         if (rc < 0) {
141                                 errno = -rc;
142                                 ERROR("sd_event_wait returned an error (state: %d): %m", sd_event_get_state(se));
143                         }
144                 }
145                 evmgr->state = EVLOOP_STATE_RUN;
146                 if (rc > 0) {
147                         rc = sd_event_dispatch(se);
148                         if (rc < 0) {
149                                 errno = -rc;
150                                 ERROR("sd_event_dispatch returned an error (state: %d): %m", sd_event_get_state(se));
151                         }
152                 }
153         }
154         evmgr->state = 0;
155 }
156
157 void evmgr_job_run(int signum, struct evmgr *evmgr)
158 {
159         if (signum)
160                 evmgr->state = 0;
161         else
162                 evmgr_run(evmgr);
163 }
164
165 int evmgr_can_run(struct evmgr *evmgr)
166 {
167         return !evmgr->state;
168 }
169
170 /**
171  * Internal callback for evmgr management.
172  * The effect of this function is hidden: it exits
173  * the waiting poll if any. Then it wakes up a thread
174  * awaiting the evmgr using signal.
175  */
176 static int on_evmgr_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
177 {
178         struct evmgr *evmgr = userdata;
179         evmgr_on_efd_event(evmgr);
180         return 1;
181 }
182
183 /**
184  * Gets a sd_event item for the current thread.
185  * @return a sd_event or NULL in case of error
186  */
187 int evmgr_create(struct evmgr **result)
188 {
189         int rc;
190         struct evmgr *evmgr;
191
192         /* creates the evmgr on need */
193         evmgr = malloc(sizeof *evmgr);
194         if (!evmgr) {
195                 ERROR("out of memory");
196                 rc = -ENOMEM;
197                 goto error;
198         }
199
200         /* creates the eventfd for waking up polls */
201         evmgr->efd = eventfd(0, EFD_CLOEXEC|EFD_SEMAPHORE);
202         if (evmgr->efd < 0) {
203                 ERROR("can't make eventfd for events");
204                 rc = -errno;
205                 goto error1;
206         }
207         /* create the systemd event loop */
208         evmgr->sdev = systemd_get_event_loop();
209         if (!evmgr->sdev) {
210                 ERROR("can't make new event loop");
211                 goto error2;
212         }
213         /* put the eventfd in the event loop */
214         rc = sd_event_add_io(evmgr->sdev, NULL, evmgr->efd, EPOLLIN, on_evmgr_efd, evmgr);
215         if (rc < 0) {
216                 ERROR("can't register eventfd");
217                 goto error2;
218         }
219
220         /* start the creation */
221         evmgr->state = 0;
222         evmgr->holder = 0;
223         *result = evmgr;
224         return 0;
225
226
227 error2:
228         close(evmgr->efd);
229 error1:
230         free(evmgr);
231 error:
232         *result = 0;
233         return rc;
234 }
235
236 #endif
237 #if WITH_FDEV_EPOLL
238
239 /**
240  * Run the event loop is set.
241  */
242 void evmgr_run(struct evmgr *evmgr)
243 {
244         int rc __attribute__((unused));
245
246         evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
247         rc = fdev_epoll_wait_and_dispatch(evmgr->fdev_epoll, -1);
248         evmgr->state = 0;
249 }
250
251 void evmgr_job_run(int signum, struct evmgr *evmgr)
252 {
253         if (signum)
254                 evmgr->state = 0;
255         else
256                 evmgr_run(evmgr);
257 }
258
259 int evmgr_can_run(struct evmgr *evmgr)
260 {
261         return !evmgr->state;
262 }
263
264 struct fdev_epoll *evmgr_get_fdev_epoll(struct evmgr *evmgr)
265 {
266         return evmgr->fdev_epoll;
267 }
268
269 /**
270  * Internal callback for evmgr management.
271  * The effect of this function is hidden: it exits
272  * the waiting poll if any. Then it wakes up a thread
273  * awaiting the evmgr using signal.
274  */
275 static void on_evmgr_efd(void *closure, uint32_t event, struct fdev *fdev)
276 {
277         struct evmgr *evmgr = closure;
278         evmgr_on_efd_event(evmgr);
279 }
280
281 /**
282  * Gets a sd_event item for the current thread.
283  * @return a sd_event or NULL in case of error
284  */
285 int evmgr_create(struct evmgr **result)
286 {
287         struct evmgr *evmgr;
288
289         /* creates the evmgr on need */
290         evmgr = malloc(sizeof *evmgr);
291         if (!evmgr) {
292                 ERROR("out of memory");
293                 errno = ENOMEM;
294                 goto error;
295         }
296
297         /* creates the eventfd for waking up polls */
298         evmgr->efd = eventfd(0, EFD_CLOEXEC|EFD_SEMAPHORE);
299         if (evmgr->efd < 0) {
300                 ERROR("can't make eventfd for events");
301                 goto error1;
302         }
303
304         /* create the systemd event loop */
305         evmgr->fdev_epoll = fdev_epoll_create();
306         if (!evmgr->fdev_epoll) {
307                 ERROR("can't make new event loop");
308                 goto error2;
309         }
310         /* put the eventfd in the event loop */
311         evmgr->fdev = fdev_epoll_add(evmgr->fdev_epoll, evmgr->efd);
312         if (evmgr->fdev == NULL) {
313                 ERROR("can't add eventfd");
314                 goto error3;
315         }
316
317         fdev_set_callback(evmgr->fdev, on_evmgr_efd, evmgr);
318         fdev_set_events(evmgr->fdev, EPOLLIN);
319
320         /* start the creation */
321         evmgr->state = 0;
322         evmgr->holder = 0;
323         *result = evmgr;
324         return 0;
325
326
327 error3:
328         fdev_epoll_destroy(evmgr->fdev_epoll);
329 error2:
330         close(evmgr->efd);
331 error1:
332         free(evmgr);
333 error:
334         *result = 0;
335         return errno ? -errno : -1;
336 }
337
338 #endif