EM-ODP  3.8.0-1
Event Machine on ODP
event_machine_init.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2023, Nokia Solutions and Networks
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /**
32  * @file
33  *
34  * Event Machine initialization and termination.
35  *
36  */
37 
38 #include "em_include.h"
39 
40 /** EM shared memory */
42 
43 /** Core local variables */
45  .current.egrp = EM_EVENT_GROUP_UNDEF,
46  .current.sched_context_type = EM_SCHED_CONTEXT_TYPE_NONE,
47  .local_queues.empty = 1,
48  .do_input_poll = false,
49  .do_output_drain = false,
50  .sync_api.in_progress = false
51  /* other members initialized to 0 or NULL as per C standard */
52 };
53 
55 {
56  if (unlikely(!conf)) {
58  EM_ESCOPE_CONF_INIT, "Conf pointer NULL!");
59  return;
60  }
61  memset(conf, 0, sizeof(em_conf_t));
64 }
65 
67 {
68  em_status_t stat;
69  int ret;
70 
72  "Conf pointer NULL!");
73 
76  "Not initialized: em_conf_init(conf) not called");
77 
78  stat = early_log_init(conf->log.log_fn, conf->log.vlog_fn);
79  RETURN_ERROR_IF(stat != EM_OK, EM_FATAL(stat),
80  EM_ESCOPE_INIT, "User provided log funcs invalid!");
81 
82  /* Sanity check: em_shm should not be set yet */
83  RETURN_ERROR_IF(em_shm != NULL,
85  "EM shared memory ptr set - already initialized?");
86  /* Sanity check: either process- or thread-per-core, but not both */
88  EM_FATAL(EM_ERR_BAD_ARG), EM_ESCOPE_INIT,
89  "Select EITHER process-per-core OR thread-per-core!");
90 
91  /*
92  * Reserve the EM shared memory once at start-up.
93  */
94  uint32_t flags = 0;
95  odp_shm_capability_t shm_capa;
96 
97  ret = odp_shm_capability(&shm_capa);
99  "shm capability error:%d", ret);
100 
101  if (shm_capa.flags & ODP_SHM_SINGLE_VA)
102  flags |= ODP_SHM_SINGLE_VA;
103 
104  odp_shm_t shm = odp_shm_reserve("em_shm", sizeof(em_shm_t),
105  ODP_CACHE_LINE_SIZE, flags);
106 
107  RETURN_ERROR_IF(shm == ODP_SHM_INVALID, EM_ERR_ALLOC_FAILED,
108  EM_ESCOPE_INIT, "Shared memory reservation failed!");
109 
110  em_shm = odp_shm_addr(shm);
111 
113  "Shared memory ptr NULL!");
114 
115  memset(em_shm, 0, sizeof(em_shm_t));
116 
117  /* Store shm handle, can be used in em_term() to free the memory */
118  em_shm->this_shm = shm;
119 
120  /* Store the given EM configuration */
121  em_shm->conf = *conf;
122 
123  if (!EM_API_HOOKS_ENABLE) {
124  memset(&em_shm->conf.api_hooks, 0,
125  sizeof(em_shm->conf.api_hooks));
126  }
127 
128  /* Initialize the log & error handling */
129  log_init();
130  error_init();
131 
132  /* Initialize libconfig */
133  ret = em_libconfig_init_global(&em_shm->libconfig);
135  "libconfig initialization failed:%d", ret);
136 
137  /*
138  * Initialize the physical-core <-> EM-core mapping
139  *
140  * EM-core <-> ODP-thread id mappings cannot be set up yet,
141  * the ODP thread id is assigned only when that thread is initialized.
142  * Set this mapping in core_map_init_local()
143  */
144  stat = core_map_init(&em_shm->core_map, conf->core_count,
145  &conf->phys_mask);
147  "core_map_init() failed:%" PRI_STAT "", stat);
148 
149  /* Initialize the EM event dispatcher */
150  stat = dispatch_init();
152  "dispatch_init() failed:%" PRI_STAT "", stat);
153 
154  /*
155  * Check validity of core masks for input_poll_fn and output_drain_fn.
156  *
157  * Masks must be a subset of logical EM core mask. Zero mask means
158  * that input_poll_fn and output_drain_fn are run on all EM cores.
159  */
160  stat = input_poll_check(&em_shm->core_map.logic_mask, conf);
162  "input_poll_init() failed:%" PRI_STAT "", stat);
163  stat = output_drain_check(&em_shm->core_map.logic_mask, conf);
165  "output_drain_init() failed:%" PRI_STAT "", stat);
166 
167  /*
168  * Initialize Event State Verification (ESV), if enabled at compile time
169  */
170  if (EM_ESV_ENABLE) {
171  stat = esv_init();
173  "esv_init() failed:%" PRI_STAT "", stat);
174  } else {
176  }
177 
178  /* Initialize EM callbacks/hooks */
179  stat = hooks_init(&conf->api_hooks, &conf->idle_hooks);
181  "hooks_init() failed:%" PRI_STAT "", stat);
182 
183  /*
184  * Initialize the EM buffer pools and create the EM_DEFAULT_POOL.
185  * Create also startup pools if configured in the runtime config
186  * file through option 'startup_pools'.
187  */
188  stat = pool_init(&em_shm->mpool_tbl, &em_shm->mpool_pool,
189  &conf->default_pool_cfg);
191  "pool_init() failed:%" PRI_STAT "", stat);
192 
193  stat = event_init();
195  "event_init() failed:%" PRI_STAT "", stat);
196 
197  stat = event_group_init(&em_shm->event_group_tbl,
198  &em_shm->event_group_stash);
200  "event_group_init() failed:%" PRI_STAT "", stat);
201 
202  stat = queue_init(&em_shm->queue_tbl, &em_shm->queue_pool,
203  &em_shm->queue_pool_static);
205  "queue_init() failed:%" PRI_STAT "", stat);
206 
207  stat = queue_group_init(&em_shm->queue_group_tbl,
208  &em_shm->queue_group_pool);
210  "queue_group_init() failed:%" PRI_STAT "", stat);
211 
212  stat = atomic_group_init(&em_shm->atomic_group_tbl,
213  &em_shm->atomic_group_pool);
215  "atomic_group_init() failed:%" PRI_STAT "", stat);
216 
217  stat = eo_init(&em_shm->eo_tbl, &em_shm->eo_pool);
219  "eo_init() failed:%" PRI_STAT "", stat);
220 
221  stat = create_ctrl_queues();
223  "create_ctrl_queues() failed:%" PRI_STAT "", stat);
224 
225  /* Initialize EM Timer */
226  if (conf->event_timer) {
227  stat = timer_init(&em_shm->timers);
228  RETURN_ERROR_IF(stat != EM_OK,
230  "timer_init() failed:%" PRI_STAT "",
231  stat);
232  }
233 
234  /* Initialize basic Event Chaining support */
235  stat = chaining_init(&em_shm->event_chaining);
237  "chaining_init() failed:%" PRI_STAT "", stat);
238 
239  /* Initialize em_cli */
240  stat = emcli_init();
242  "emcli_init() failed:%" PRI_STAT "", stat);
243 
244  /*
245  * Print EM and ODP version information
246  */
247  print_version_info();
248 
249  return EM_OK;
250 }
251 
253 {
254  em_locm_t *const locm = &em_locm;
255  odp_shm_t shm;
256  em_shm_t *shm_addr;
257  em_status_t stat;
258 
259  /* Lookup the EM shared memory on each EM-core */
260  shm = odp_shm_lookup("em_shm");
261  RETURN_ERROR_IF(shm == ODP_SHM_INVALID,
263  "Shared memory lookup failed!");
264 
265  shm_addr = odp_shm_addr(shm);
267  "Shared memory ptr NULL");
268 
269  if (shm_addr->conf.process_per_core && em_shm == NULL)
270  em_shm = shm_addr;
271 
273  "Shared memory init fails: em_shm:%p != shm_addr:%p",
274  em_shm, shm_addr);
275 
276  /* Initialize core mappings not known yet in core_map_init() */
277  stat = core_map_init_local(&em_shm->core_map);
279  "core_map_init_local() failed:%" PRI_STAT "", stat);
280 
281  stat = queue_group_init_local();
283  "queue_group_init_local() failed:%" PRI_STAT "", stat);
284 
285  stat = dispatch_init_local();
287  "dispatch_init_local() failed:%" PRI_STAT "", stat);
288 
289  /* Check if input_poll_fn should be executed on this core */
290  stat = input_poll_init_local();
292  "input_poll_init_local() failed:%" PRI_STAT "", stat);
293 
294  /* Check if output_drain_fn should be executed on this core */
295  stat = output_drain_init_local();
297  "output_drain_init_local() failed:%" PRI_STAT "", stat);
298 
299  stat = queue_init_local();
301  "queue_init_local() failed:%" PRI_STAT "", stat);
302 
303  /*
304  * Initialize EM timer. If global init was not done (config),
305  * this is just a NOP
306  */
307  stat = timer_init_local();
309  "timer_init_local() failed:%" PRI_STAT "", stat);
310 
311  stat = sync_api_init_local();
313  "sync_api_init_local() failed:%" PRI_STAT "", stat);
314 
315  /* Init the EM CLI locally on this core (only if enabled) */
316  stat = emcli_init_local();
318  "emcli_init_local() failed:%" PRI_STAT "", stat);
319 
320  /* This is an EM-core that will participate in EM event dispatching */
321  locm->is_external_thr = false;
322 
323  /* Initialize debug timestamps to 1 if enabled to differentiate from disabled */
325  for (int i = 0; i < EM_DEBUG_TSP_LAST; i++)
326  locm->debug_ts[i] = 1;
327 
328  /* Now OK to call EM APIs */
329 
330  env_sync_mem();
331 
332  return EM_OK;
333 }
334 
335 static void flush_scheduler_events(void)
336 {
337  odp_event_t odp_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
339  em_event_t em_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
340  int num_events;
341 
342  do {
343  num_events = odp_schedule_multi_no_wait(NULL, odp_ev_tbl, EM_SCHED_MULTI_MAX_BURST);
344  /* the check 'num_events > EM_SCHED_MULTI_MAX_BURST' avoids a gcc warning */
345  if (num_events <= 0 || num_events > EM_SCHED_MULTI_MAX_BURST)
346  break;
347  /*
348  * Events might originate from outside of EM and need init.
349  */
350  event_init_odp_multi(odp_ev_tbl, em_ev_tbl/*out*/, ev_hdr_tbl/*out*/,
351  num_events, true/*is_extev*/);
352  em_free_multi(em_ev_tbl, num_events);
353  } while (num_events > 0);
354 }
355 
357 {
358  em_locm_t *const locm = &em_locm;
359  em_status_t stat;
360  int ret;
361 
362  (void)conf;
363 
364  /*
365  * Join all queue groups to be able to flush all events
366  * from the scheduler from this core.
367  */
369 
370  /*
371  * Flush all events in the scheduler.
372  * Run loop twice: first with sched enabled and then paused.
373  */
374  if (locm->is_sched_paused) {
375  locm->is_sched_paused = false;
376  odp_schedule_resume();
377  }
378  for (int i = 0; i < 2; i++) {
379  flush_scheduler_events();
380  locm->is_sched_paused = true;
381  odp_schedule_pause();
382  }
383 
384  stat = delete_ctrl_queues();
386  "delete_ctrl_queues() failed:%" PRI_STAT "", stat);
387 
388  if (em_shm->conf.event_timer)
389  timer_term(&em_shm->timers);
390 
391  stat = emcli_term();
393  "emcli_term() failed:%" PRI_STAT "", stat);
394 
395  stat = chaining_term(&em_shm->event_chaining);
397  "chaining_term() failed:%" PRI_STAT "", stat);
398 
399  ret = em_libconfig_term_global(&em_shm->libconfig);
401  "EM config term failed:%d");
402 
403  stat = pool_term(&em_shm->mpool_tbl);
405  "pool_term() failed:%" PRI_STAT "", stat);
406 
407  env_shared_free(em_shm->queue_tbl.queue_elem);
408 
409  stat = event_group_term();
411  "event_group_term() failed.");
412 
413  /*
414  * Free the EM shared memory
415  */
416  ret = odp_shm_free(em_shm->this_shm);
418  "odp_shm_free() failed:%d", ret);
419  /* Set em_shm = NULL to allow a new call to em_init() */
420  em_shm = NULL;
421 
422  return EM_OK;
423 }
424 
426 {
427  em_status_t stat = EM_OK;
428  em_status_t ret_stat = EM_OK;
429  em_locm_t *const locm = &em_locm;
430 
431  /*
432  * Poll internal unscheduled ctrl queues to complete ctrl actions
433  * and flush them.
434  */
436 
437  /*
438  * Flush the scheduler from locally stashed events.
439  */
440  if (!locm->is_sched_paused) {
441  locm->is_sched_paused = true;
442  odp_schedule_pause();
443  }
444  flush_scheduler_events();
445 
446  /* Stop EM Timer. Just a NOP if timer was not enabled (config) */
447  stat = timer_term_local();
448  if (stat != EM_OK) {
449  ret_stat = stat;
451  "timer_term_local() fails: %" PRI_STAT "", stat);
452  }
453 
454  /* Term the EM CLI locally (if enabled) */
455  stat = emcli_term_local();
456  if (stat != EM_OK) {
457  ret_stat = stat;
459  "emcli_term_local() fails: %" PRI_STAT "", stat);
460  }
461 
462  /* Delete the local queues */
463  stat = queue_term_local();
464  if (stat != EM_OK) {
465  ret_stat = stat;
467  "queue_term_local() fails: %" PRI_STAT "", stat);
468  }
469 
470  stat = core_map_term_local(&em_shm->core_map);
472  "core_map_term_local() failed:%" PRI_STAT "", stat);
473 
474  return ret_stat == EM_OK ? EM_OK : EM_ERR;
475 }
476 
477 uint16_t em_device_id(void)
478 {
479  return em_shm->conf.device_id;
480 }
em_status_t atomic_group_init(atomic_group_tbl_t *const atomic_group_tbl, atomic_group_pool_t *const atomic_group_pool)
em_status_t chaining_init(event_chaining_t *event_chaining)
Definition: em_chaining.c:137
em_status_t chaining_term(const event_chaining_t *event_chaining)
Definition: em_chaining.c:196
void error_init(void)
Definition: em_error.c:339
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition: em_error.h:50
void esv_disabled_warn_config(void)
em_status_t esv_init(void)
em_status_t hooks_init(const em_api_hooks_t *api_hooks, const em_idle_hooks_t *idle_hooks)
Definition: em_hooks.c:46
#define EM_CHECK_INIT_CALLED
Definition: em_include.h:69
em_status_t create_ctrl_queues(void)
Create EM's internal unscheduled control queues at startup.
void poll_unsched_ctrl_queue(void)
Poll EM's internal unscheduled control queues during dispatch.
em_status_t delete_ctrl_queues(void)
Delete EM's internal unscheduled control queues at teardown.
ENV_LOCAL em_locm_t em_locm
em_status_t queue_init(queue_tbl_t *const queue_tbl, queue_pool_t *const queue_pool, queue_pool_t *const queue_pool_static)
Definition: em_queue.c:217
em_status_t queue_term_local(void)
Definition: em_queue.c:367
em_status_t queue_init_local(void)
Definition: em_queue.c:303
void queue_group_join_all(void)
The calling core joins all available queue groups.
em_status_t queue_group_init(queue_group_tbl_t *const queue_group_tbl, queue_group_pool_t *const queue_group_pool)
#define ENV_LOCAL
Definition: environment.h:57
#define EM_DEBUG_TIMESTAMP_ENABLE
#define EM_ESV_ENABLE
#define EM_API_HOOKS_ENABLE
#define EM_SCHED_MULTI_MAX_BURST
#define EM_ESCOPE_TERM_CORE
#define EM_ESCOPE_INIT
@ EM_ERR_NOT_FOUND
@ EM_ERR_OPERATION_FAILED
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_BAD_ARG
@ EM_ERR_BAD_STATE
@ EM_ERR_LIB_FAILED
@ EM_ERR_NOT_INITIALIZED
@ EM_ERR_BAD_POINTER
#define EM_ESCOPE_INIT_CORE
#define EM_ESCOPE_TERM
#define EM_ESCOPE_CONF_INIT
em_shm_t * em_shm
#define EM_OK
#define EM_EVENT_GROUP_UNDEF
uint32_t em_status_t
@ EM_SCHED_CONTEXT_TYPE_NONE
em_status_t emcli_init_local(void)
Initialize the EM CLI locally on an EM core (if enabled)
Definition: em_cli.c:1451
em_status_t emcli_term(void)
Terminate the EM CLI (if enabled)
Definition: em_cli.c:1456
em_status_t emcli_term_local(void)
Terminate the EM CLI locally on an EM core (if enabled)
Definition: em_cli.c:1461
em_status_t emcli_init(void)
Initialize the EM CLI (if enabled)
Definition: em_cli.c:1446
void em_free_multi(em_event_t events[], int num)
void em_pool_cfg_init(em_pool_cfg_t *const pool_cfg)
em_status_t em_term(const em_conf_t *conf)
em_status_t em_term_core(void)
void em_conf_init(em_conf_t *conf)
em_status_t em_init(const em_conf_t *conf)
uint16_t em_device_id(void)
em_status_t em_init_core(void)
em_log_func_t log_fn
em_api_hooks_t api_hooks
em_vlog_func_t vlog_fn
em_pool_cfg_t default_pool_cfg
em_core_mask_t phys_mask
struct em_conf_t::@3 log
uint32_t __internal_check
em_idle_hooks_t idle_hooks
bool is_sched_paused
Definition: em_mem.h:209
uint64_t debug_ts[EM_DEBUG_TSP_LAST]
Definition: em_mem.h:239
bool is_external_thr
Definition: em_mem.h:207
libconfig_t libconfig
Definition: em_mem.h:146
odp_shm_t this_shm
Definition: em_mem.h:55