2 * Copyright (C) 2016-2019 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <sys/syscall.h>
30 #include <sys/eventfd.h>
32 #include <systemd/sd-event.h>
40 #include "fdev-epoll.h"
44 /** Description of handled event loops */
47 int efd; /**< event notification */
48 unsigned state; /**< encoded state */
49 void *holder; /**< holder of the evmgr */
51 struct sd_event *sdev; /**< the systemd event loop */
54 struct fdev_epoll *fdev_epoll;
59 #define EVLOOP_STATE_WAIT 1U
60 #define EVLOOP_STATE_RUN 2U
64 * Internal callback for evmgr management.
65 * The effect of this function is hidden: it exits
66 * the waiting poll if any.
68 static void evmgr_on_efd_event(struct evmgr *evmgr)
71 read(evmgr->efd, &x, sizeof x);
75 * wakeup the event loop if needed by sending
78 void evmgr_wakeup(struct evmgr *evmgr)
82 if (evmgr->state & EVLOOP_STATE_WAIT) {
84 write(evmgr->efd, &x, sizeof x);
90 void *evmgr_holder(struct evmgr *evmgr)
97 int evmgr_release_if(struct evmgr *evmgr, void *holder)
99 if (evmgr->holder != holder)
107 int evmgr_try_hold(struct evmgr *evmgr, void *holder)
110 evmgr->holder = holder;
111 return evmgr->holder == holder;
114 /******************************************************************************/
115 /******************************************************************************/
116 /****** SYSTEM D ******/
117 /******************************************************************************/
118 /******************************************************************************/
123 * Run the event loop is set.
125 void evmgr_run(struct evmgr *evmgr)
130 evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
132 rc = sd_event_prepare(se);
135 CRITICAL("sd_event_prepare returned an error (state: %d): %m", sd_event_get_state(se));
139 rc = sd_event_wait(se, (uint64_t)(int64_t)-1);
142 ERROR("sd_event_wait returned an error (state: %d): %m", sd_event_get_state(se));
145 evmgr->state = EVLOOP_STATE_RUN;
147 rc = sd_event_dispatch(se);
150 ERROR("sd_event_dispatch returned an error (state: %d): %m", sd_event_get_state(se));
157 void evmgr_job_run(int signum, struct evmgr *evmgr)
165 int evmgr_can_run(struct evmgr *evmgr)
167 return !evmgr->state;
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.
176 static int on_evmgr_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
178 struct evmgr *evmgr = userdata;
179 evmgr_on_efd_event(evmgr);
184 * Gets a sd_event item for the current thread.
185 * @return a sd_event or NULL in case of error
187 int evmgr_create(struct evmgr **result)
192 /* creates the evmgr on need */
193 evmgr = malloc(sizeof *evmgr);
195 ERROR("out of memory");
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");
207 /* create the systemd event loop */
208 evmgr->sdev = systemd_get_event_loop();
210 ERROR("can't make new event loop");
213 /* put the eventfd in the event loop */
214 rc = sd_event_add_io(evmgr->sdev, NULL, evmgr->efd, EPOLLIN, on_evmgr_efd, evmgr);
216 ERROR("can't register eventfd");
220 /* start the creation */
240 * Run the event loop is set.
242 void evmgr_run(struct evmgr *evmgr)
244 int rc __attribute__((unused));
246 evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
247 rc = fdev_epoll_wait_and_dispatch(evmgr->fdev_epoll, -1);
251 void evmgr_job_run(int signum, struct evmgr *evmgr)
259 int evmgr_can_run(struct evmgr *evmgr)
261 return !evmgr->state;
264 struct fdev_epoll *evmgr_get_fdev_epoll(struct evmgr *evmgr)
266 return evmgr->fdev_epoll;
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.
275 static void on_evmgr_efd(void *closure, uint32_t event, struct fdev *fdev)
277 struct evmgr *evmgr = closure;
278 evmgr_on_efd_event(evmgr);
282 * Gets a sd_event item for the current thread.
283 * @return a sd_event or NULL in case of error
285 int evmgr_create(struct evmgr **result)
289 /* creates the evmgr on need */
290 evmgr = malloc(sizeof *evmgr);
292 ERROR("out of memory");
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");
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");
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");
317 fdev_set_callback(evmgr->fdev, on_evmgr_efd, evmgr);
318 fdev_set_events(evmgr->fdev, EPOLLIN);
320 /* start the creation */
328 fdev_epoll_destroy(evmgr->fdev_epoll);
335 return errno ? -errno : -1;