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