Improve detection of the bindings
[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 #include "systemd.h"
37
38 /** Description of handled event loops */
39 struct evmgr
40 {
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 */
45 };
46
47 #define EVLOOP_STATE_WAIT           1U
48 #define EVLOOP_STATE_RUN            2U
49
50 /**
51  * prepare the evmgr to run
52  */
53 void evmgr_prepare_run(struct evmgr *evmgr)
54 {
55         evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
56 }
57
58 /**
59  * Run the event loop is set.
60  */
61 void evmgr_run(struct evmgr *evmgr)
62 {
63         int rc;
64         struct sd_event *se;
65
66         evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
67         se = evmgr->sdev;
68         rc = sd_event_prepare(se);
69         if (rc < 0) {
70                 errno = -rc;
71                 CRITICAL("sd_event_prepare returned an error (state: %d): %m", sd_event_get_state(se));
72                 abort();
73         } else {
74                 if (rc == 0) {
75                         rc = sd_event_wait(se, (uint64_t)(int64_t)-1);
76                         if (rc < 0) {
77                                 errno = -rc;
78                                 ERROR("sd_event_wait returned an error (state: %d): %m", sd_event_get_state(se));
79                         }
80                 }
81                 evmgr->state = EVLOOP_STATE_RUN;
82                 if (rc > 0) {
83                         rc = sd_event_dispatch(se);
84                         if (rc < 0) {
85                                 errno = -rc;
86                                 ERROR("sd_event_dispatch returned an error (state: %d): %m", sd_event_get_state(se));
87                         }
88                 }
89         }
90         evmgr->state = 0;
91 }
92
93 void evmgr_job_run(int signum, struct evmgr *evmgr)
94 {
95         if (signum)
96                 evmgr->state = 0;
97         else
98                 evmgr_run(evmgr);
99 }
100
101 int evmgr_can_run(struct evmgr *evmgr)
102 {
103         return !evmgr->state;
104 }
105
106 /**
107  * Internal callback for evmgr management.
108  * The effect of this function is hidden: it exits
109  * the waiting poll if any.
110  */
111 static void evmgr_on_efd_event(struct evmgr *evmgr)
112 {
113         uint64_t x;
114         read(evmgr->efd, &x, sizeof x);
115 }
116
117 /**
118  * wakeup the event loop if needed by sending
119  * an event.
120  */
121 void evmgr_wakeup(struct evmgr *evmgr)
122 {
123         uint64_t x;
124
125         if (evmgr->state & EVLOOP_STATE_WAIT) {
126                 x = 1;
127                 write(evmgr->efd, &x, sizeof x);
128         }
129 }
130
131 /**
132  */
133 void *evmgr_holder(struct evmgr *evmgr)
134 {
135         return evmgr->holder;
136 }
137
138 /**
139  */
140 int evmgr_release_if(struct evmgr *evmgr, void *holder)
141 {
142         if (evmgr->holder != holder)
143                 return 0;
144         evmgr->holder = 0;
145         return 1;
146 }
147
148 /**
149  */
150 int evmgr_try_hold(struct evmgr *evmgr, void *holder)
151 {
152         if (!evmgr->holder)
153                 evmgr->holder = holder;
154         return evmgr->holder == holder;
155 }
156
157 /******************************************************************************/
158 /******************************************************************************/
159 /******  SYSTEM D                                                        ******/
160 /******************************************************************************/
161 /******************************************************************************/
162
163 /**
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.
168  */
169 static int on_evmgr_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
170 {
171         struct evmgr *evmgr = userdata;
172         evmgr_on_efd_event(evmgr);
173         return 1;
174 }
175
176 /**
177  * Gets a sd_event item for the current thread.
178  * @return a sd_event or NULL in case of error
179  */
180 int evmgr_create(struct evmgr **result)
181 {
182         int rc;
183         struct evmgr *evmgr;
184
185         /* creates the evmgr on need */
186         evmgr = malloc(sizeof *evmgr);
187         if (!evmgr) {
188                 ERROR("out of memory");
189                 rc = -ENOMEM;
190                 goto error;
191         }
192
193         /* creates the eventfd for waking up polls */
194         evmgr->efd = eventfd(0, EFD_CLOEXEC|EFD_SEMAPHORE);
195         if (evmgr->efd < 0) {
196                 rc = -errno;
197                 ERROR("can't make eventfd for events");
198                 goto error1;
199         }
200         /* create the systemd event loop */
201         evmgr->sdev = systemd_get_event_loop();
202         if (!evmgr->sdev) {
203                 rc = -errno;
204                 ERROR("can't make new event loop");
205                 goto error2;
206         }
207         /* put the eventfd in the event loop */
208         rc = sd_event_add_io(evmgr->sdev, NULL, evmgr->efd, EPOLLIN, on_evmgr_efd, evmgr);
209         if (rc < 0) {
210                 ERROR("can't register eventfd");
211                 goto error2;
212         }
213
214         /* start the creation */
215         evmgr->state = 0;
216         evmgr->holder = 0;
217         *result = evmgr;
218         return 0;
219
220
221 error2:
222         close(evmgr->efd);
223 error1:
224         free(evmgr);
225 error:
226         *result = 0;
227         return rc;
228 }
229