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>
38 /** Description of handled event loops */
41 unsigned state; /**< encoded state */
42 int efd; /**< event notification */
43 void *holder; /**< holder of the evmgr */
44 struct sd_event *sdev; /**< the systemd event loop */
47 #define EVLOOP_STATE_WAIT 1U
48 #define EVLOOP_STATE_RUN 2U
51 * prepare the evmgr to run
53 void evmgr_prepare_run(struct evmgr *evmgr)
55 evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
59 * Run the event loop is set.
61 void evmgr_run(struct evmgr *evmgr)
66 evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
68 rc = sd_event_prepare(se);
71 CRITICAL("sd_event_prepare returned an error (state: %d): %m", sd_event_get_state(se));
75 rc = sd_event_wait(se, (uint64_t)(int64_t)-1);
78 ERROR("sd_event_wait returned an error (state: %d): %m", sd_event_get_state(se));
81 evmgr->state = EVLOOP_STATE_RUN;
83 rc = sd_event_dispatch(se);
86 ERROR("sd_event_dispatch returned an error (state: %d): %m", sd_event_get_state(se));
93 void evmgr_job_run(int signum, struct evmgr *evmgr)
101 int evmgr_can_run(struct evmgr *evmgr)
103 return !evmgr->state;
107 * Internal callback for evmgr management.
108 * The effect of this function is hidden: it exits
109 * the waiting poll if any.
111 static void evmgr_on_efd_event(struct evmgr *evmgr)
114 read(evmgr->efd, &x, sizeof x);
118 * wakeup the event loop if needed by sending
121 void evmgr_wakeup(struct evmgr *evmgr)
125 if (evmgr->state & EVLOOP_STATE_WAIT) {
127 write(evmgr->efd, &x, sizeof x);
133 void *evmgr_holder(struct evmgr *evmgr)
135 return evmgr->holder;
140 int evmgr_release_if(struct evmgr *evmgr, void *holder)
142 if (evmgr->holder != holder)
150 int evmgr_try_hold(struct evmgr *evmgr, void *holder)
153 evmgr->holder = holder;
154 return evmgr->holder == holder;
157 /******************************************************************************/
158 /******************************************************************************/
159 /****** SYSTEM D ******/
160 /******************************************************************************/
161 /******************************************************************************/
164 * Internal callback for evmgr management.
165 * The effect of this function is hidden: it exits
166 * the waiting poll if any. Then it wakes up a thread
167 * awaiting the evmgr using signal.
169 static int on_evmgr_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
171 struct evmgr *evmgr = userdata;
172 evmgr_on_efd_event(evmgr);
177 * Gets a sd_event item for the current thread.
178 * @return a sd_event or NULL in case of error
180 int evmgr_create(struct evmgr **result)
185 /* creates the evmgr on need */
186 evmgr = malloc(sizeof *evmgr);
188 ERROR("out of memory");
193 /* creates the eventfd for waking up polls */
194 evmgr->efd = eventfd(0, EFD_CLOEXEC|EFD_SEMAPHORE);
195 if (evmgr->efd < 0) {
197 ERROR("can't make eventfd for events");
200 /* create the systemd event loop */
201 evmgr->sdev = systemd_get_event_loop();
204 ERROR("can't make new event loop");
207 /* put the eventfd in the event loop */
208 rc = sd_event_add_io(evmgr->sdev, NULL, evmgr->efd, EPOLLIN, on_evmgr_efd, evmgr);
210 ERROR("can't register eventfd");
214 /* start the creation */