libamxrt  0.4.2
Ambiorix Run Time Library
amxrt_el_libevent.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <string.h>
57 #include <signal.h>
58 
59 #include <event2/event.h>
60 
61 #include <amxrt/amxrt.h>
62 #include "amxrt_priv.h"
63 
64 static struct event_base* base = NULL;
65 
66 typedef struct _el_data {
67  struct event* read;
68  struct event* can_write;
69  amxc_llist_it_t it;
71 
72 static void amxrt_el_free_event_source(amxc_llist_it_t* it) {
73  el_data_t* el_data = amxc_container_of(it, el_data_t, it);
74  if(el_data->read != NULL) {
75  event_del(el_data->read);
76  free(el_data->read);
77  }
78  if(el_data->can_write != NULL) {
79  event_del(el_data->can_write);
80  free(el_data->can_write);
81  }
82 
83  free(el_data);
84 }
85 
86 static void amxrt_el_add_event_source(struct event* source, amxp_connection_t* con) {
87  amxrt_t* rt = amxrt_get();
88  el_data_t* el_data = (el_data_t*) calloc(1, sizeof(el_data_t));
89  el_data->read = source;
90  event_add(source, NULL);
91 
92  if(con != NULL) {
93  con->el_data = el_data;
94  }
95 
96  amxc_llist_append(&rt->event_sources, &el_data->it);
97 }
98 
99 static void amxrt_el_signal_cb(UNUSED evutil_socket_t fd,
100  UNUSED short event,
101  UNUSED void* arg) {
102  amxrt_el_stop();
103 }
104 
105 static void amxrt_el_signal_timers(UNUSED evutil_socket_t fd,
106  UNUSED short event,
107  UNUSED void* arg) {
108  amxp_timers_calculate();
109  amxp_timers_check();
110 }
111 
112 static void amxrt_el_connection_read_cb(UNUSED evutil_socket_t fd,
113  UNUSED short flags,
114  void* arg) {
115  amxp_connection_t* con = (amxp_connection_t*) arg;
116  con->reader(fd, con->priv);
117 }
118 
119 static void amxrt_el_connection_can_write_cb(UNUSED evutil_socket_t fd,
120  UNUSED short flags,
121  void* arg) {
122  amxp_connection_t* con = (amxp_connection_t*) arg;
123  el_data_t* el_data = (el_data_t*) con->el_data;
124  amxo_fd_cb_t cb = con->can_write;
125 
126  con->can_write = NULL;
127  event_del(el_data->can_write);
128  free(el_data->can_write);
129  el_data->can_write = NULL;
130 
131  cb(fd, con->priv);
132 }
133 
134 static void amxrt_el_amxp_signal_read_cb(UNUSED evutil_socket_t fd,
135  UNUSED short flags,
136  UNUSED void* arg) {
137  amxp_signal_read();
138 }
139 
140 static void amxrt_el_amxp_syssignal_read_cb(UNUSED evutil_socket_t fd,
141  UNUSED short flags,
142  UNUSED void* arg) {
143  amxp_syssig_read();
144 }
145 
146 static void amxrt_el_slot_add_fd(UNUSED const char* const sig_name,
147  const amxc_var_t* const data,
148  UNUSED void* const priv) {
149  amxp_connection_t* con = NULL;
150  struct event* source = NULL;
151 
152  when_true(amxc_var_type_of(data) != AMXC_VAR_ID_FD, leave);
153 
154  con = amxp_connection_get(amxc_var_constcast(fd_t, data));
155  when_null(con, leave);
156 
157  source = event_new(base, con->fd, EV_READ | EV_PERSIST, amxrt_el_connection_read_cb, con);
158  amxrt_el_add_event_source(source, con);
159 
160 leave:
161  return;
162 }
163 
164 static void amxrt_el_slot_wait_write_fd(UNUSED const char* const sig_name,
165  const amxc_var_t* const data,
166  UNUSED void* const priv) {
167  amxp_connection_t* con = NULL;
168  el_data_t* el_data = NULL;
169 
170  when_true(amxc_var_type_of(data) != AMXC_VAR_ID_FD, leave);
171 
172  con = amxp_connection_get(amxc_var_constcast(fd_t, data));
173  when_null(con, leave);
174 
175  el_data = (el_data_t*) con->el_data;
176  when_null(el_data, leave);
177  if(el_data->can_write != NULL) {
178  event_del(el_data->can_write);
179  free(el_data->can_write);
180  }
181  el_data->can_write = event_new(base,
182  con->fd,
183  EV_WRITE,
185  con);
186  event_add(el_data->can_write, NULL);
187 
188 leave:
189  return;
190 }
191 
192 static void amxrt_el_slot_remove_fd(UNUSED const char* const sig_name,
193  const amxc_var_t* const data,
194  UNUSED void* const priv) {
195  amxc_llist_t* connections = amxp_connection_get_connections();
196  amxp_connection_t* con = NULL;
197 
198  when_true(amxc_var_type_of(data) != AMXC_VAR_ID_FD, leave);
199 
200  con = amxrt_el_get_connection(connections, amxc_var_constcast(fd_t, data));
201  if(con == NULL) {
202  connections = amxp_connection_get_listeners();
203  con = amxrt_el_get_connection(connections, amxc_var_constcast(fd_t, data));
204  }
205  when_null(con, leave);
206 
207  if(con->el_data != NULL) {
208  el_data_t* el_data = (el_data_t*) con->el_data;
209  if(el_data != NULL) {
210  amxc_llist_it_clean(&el_data->it, amxrt_el_free_event_source);
211  }
212  con->el_data = NULL;
213  }
214 
215 leave:
216  return;
217 }
218 
219 static void amxrt_el_add_read_fd(amxc_llist_t* connections) {
220  struct event* source = NULL;
221 
222  amxc_llist_for_each(it, connections) {
223  amxp_connection_t* con = amxc_llist_it_get_data(it, amxp_connection_t, it);
224  source = event_new(base, con->fd, EV_READ | EV_PERSIST, amxrt_el_connection_read_cb, con);
225  amxrt_el_add_event_source(source, con);
226  }
227 }
228 
229 static void amxrt_el_remove_fd(amxc_llist_t* connections) {
230  amxc_llist_for_each(it, connections) {
231  amxp_connection_t* con = amxc_llist_it_get_data(it, amxp_connection_t, it);
232  el_data_t* el_data = (el_data_t*) con->el_data;
233  if(el_data != NULL) {
234  amxc_llist_it_clean(&el_data->it, amxrt_el_free_event_source);
235  }
236  con->el_data = NULL;
237  }
238 }
239 
240 amxp_connection_t* amxrt_el_get_connection(amxc_llist_t* cons, int fd) {
241  amxp_connection_t* con = NULL;
242  amxc_llist_for_each(it, cons) {
243  con = amxc_llist_it_get_data(it, amxp_connection_t, it);
244  if(con->fd == fd) {
245  break;
246  }
247  con = NULL;
248  }
249 
250  return con;
251 }
252 
253 int amxrt_el_create(void) {
254  amxo_parser_t* parser = amxrt_get_parser();
255  int retval = -1;
256  struct event* event_source = NULL;
257 
258  base = event_base_new();
259  when_null(base, leave);
260 
261  event_source = evsignal_new(base, SIGINT, amxrt_el_signal_cb, NULL);
262  amxrt_el_add_event_source(event_source, NULL);
263 
264  event_source = evsignal_new(base, SIGTERM, amxrt_el_signal_cb, NULL);
265  amxrt_el_add_event_source(event_source, NULL);
266 
267  event_source = evsignal_new(base, SIGALRM, amxrt_el_signal_timers, NULL);
268  amxrt_el_add_event_source(event_source, NULL);
269 
270  event_source = event_new(base, amxp_signal_fd(), EV_READ | EV_PERSIST, amxrt_el_amxp_signal_read_cb, NULL);
271  amxrt_el_add_event_source(event_source, NULL);
272 
273  event_source = event_new(base, amxp_syssig_get_fd(), EV_READ | EV_PERSIST, amxrt_el_amxp_syssignal_read_cb, NULL);
274  amxrt_el_add_event_source(event_source, NULL);
275 
276  amxrt_el_add_read_fd(amxp_connection_get_connections());
277  amxrt_el_add_read_fd(amxp_connection_get_listeners());
278 
279  amxp_slot_connect(NULL, "connection-added", NULL, amxrt_el_slot_add_fd, parser);
280  amxp_slot_connect(NULL, "connection-wait-write", NULL, amxrt_el_slot_wait_write_fd, parser);
281  amxp_slot_connect(NULL, "listen-added", NULL, amxrt_el_slot_add_fd, parser);
282  amxp_slot_connect(NULL, "connection-deleted", NULL, amxrt_el_slot_remove_fd, parser);
283  amxp_slot_connect(NULL, "listen-deleted", NULL, amxrt_el_slot_remove_fd, parser);
284 
285  retval = 0;
286 
287 leave:
288  return retval;
289 }
290 
291 int amxrt_el_start(void) {
292  int retval = -1;
293  amxd_dm_t* dm = amxrt_get_dm();
294 
295  if(base != NULL) {
296  retval = event_base_dispatch(base);
297  }
298 
299  amxp_sigmngr_trigger_signal(&dm->sigmngr, "app:stop", NULL);
300  amxp_sigmngr_trigger_signal(NULL, "wait:cancel", NULL);
301 
302  return retval;
303 }
304 
305 int amxrt_el_stop(void) {
306  int retval = -1;
307  if(base != NULL) {
308  retval = event_base_loopbreak(base);
309  }
310  return retval;
311 }
312 
313 int amxrt_el_destroy(void) {
314  amxrt_t* rt = amxrt_get();
315 
316  amxp_slot_disconnect(NULL, "connection-added", amxrt_el_slot_add_fd);
317  amxp_slot_disconnect(NULL, "listen-added", amxrt_el_slot_add_fd);
318  amxp_slot_disconnect(NULL, "connection-deleted", amxrt_el_slot_remove_fd);
319 
320  amxrt_el_remove_fd(amxp_connection_get_connections());
321  amxrt_el_remove_fd(amxp_connection_get_listeners());
322 
323  amxc_llist_clean(&rt->event_sources, amxrt_el_free_event_source);
324 
325  if(base != NULL) {
326  event_base_free(base);
327  base = NULL;
328  }
329 
330  return 0;
331 }
static amxrt_t rt
Definition: amxrt.c:74
static void amxrt_el_free_event_source(amxc_llist_it_t *it)
static void amxrt_el_signal_cb(UNUSED evutil_socket_t fd, UNUSED short event, UNUSED void *arg)
static void amxrt_el_add_read_fd(amxc_llist_t *connections)
static void amxrt_el_connection_read_cb(UNUSED evutil_socket_t fd, UNUSED short flags, void *arg)
static void amxrt_el_connection_can_write_cb(UNUSED evutil_socket_t fd, UNUSED short flags, void *arg)
static void amxrt_el_add_event_source(struct event *source, amxp_connection_t *con)
static void amxrt_el_signal_timers(UNUSED evutil_socket_t fd, UNUSED short event, UNUSED void *arg)
amxp_connection_t * amxrt_el_get_connection(amxc_llist_t *cons, int fd)
static struct event_base * base
static void amxrt_el_slot_wait_write_fd(UNUSED const char *const sig_name, const amxc_var_t *const data, UNUSED void *const priv)
static void amxrt_el_remove_fd(amxc_llist_t *connections)
static void amxrt_el_amxp_signal_read_cb(UNUSED evutil_socket_t fd, UNUSED short flags, UNUSED void *arg)
static void amxrt_el_amxp_syssignal_read_cb(UNUSED evutil_socket_t fd, UNUSED short flags, UNUSED void *arg)
static void amxrt_el_slot_remove_fd(UNUSED const char *const sig_name, const amxc_var_t *const data, UNUSED void *const priv)
struct _el_data el_data_t
static void amxrt_el_slot_add_fd(UNUSED const char *const sig_name, const amxc_var_t *const data, UNUSED void *const priv)
PRIVATE amxrt_t * amxrt_get(void)
Definition: amxrt.c:297
int amxrt_el_destroy(void)
Cleans-up the event loop components.
int amxrt_el_start(void)
Starts the event loop.
int amxrt_el_stop(void)
Stops the event loop.
int amxrt_el_create(void)
Creates and initializes all needed event loop components.
amxd_dm_t * amxrt_get_dm(void)
Gets the runtime data model storage.
Definition: amxrt.c:309
amxo_parser_t * amxrt_get_parser(void)
Gets runtime odl parser.
Definition: amxrt.c:305
struct event * can_write
amxc_llist_it_t it
struct event * read
amxc_llist_t event_sources
Definition: amxrt_priv.h:104