EM-ODP  3.7.0
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));
63 }
64 
66 {
67  em_status_t stat;
68  int ret;
69 
71  "Conf pointer NULL!");
72 
73  stat = early_log_init(conf->log.log_fn, conf->log.vlog_fn);
74  RETURN_ERROR_IF(stat != EM_OK, EM_FATAL(stat),
75  EM_ESCOPE_INIT, "User provided log funcs invalid!");
76 
77  /* Sanity check: em_shm should not be set yet */
78  RETURN_ERROR_IF(em_shm != NULL,
80  "EM shared memory ptr set - already initialized?");
81  /* Sanity check: either process- or thread-per-core, but not both */
83  EM_FATAL(EM_ERR_BAD_ARG), EM_ESCOPE_INIT,
84  "Select EITHER process-per-core OR thread-per-core!");
85 
86  /*
87  * Reserve the EM shared memory once at start-up.
88  */
89  uint32_t flags = 0;
90  odp_shm_capability_t shm_capa;
91 
92  ret = odp_shm_capability(&shm_capa);
94  "shm capability error:%d", ret);
95 
96  if (shm_capa.flags & ODP_SHM_SINGLE_VA)
97  flags |= ODP_SHM_SINGLE_VA;
98 
99  odp_shm_t shm = odp_shm_reserve("em_shm", sizeof(em_shm_t),
100  ODP_CACHE_LINE_SIZE, flags);
101 
102  RETURN_ERROR_IF(shm == ODP_SHM_INVALID, EM_ERR_ALLOC_FAILED,
103  EM_ESCOPE_INIT, "Shared memory reservation failed!");
104 
105  em_shm = odp_shm_addr(shm);
106 
108  "Shared memory ptr NULL!");
109 
110  memset(em_shm, 0, sizeof(em_shm_t));
111 
112  /* Store shm handle, can be used in em_term() to free the memory */
113  em_shm->this_shm = shm;
114 
115  /* Store the given EM configuration */
116  em_shm->conf = *conf;
117 
118  if (!EM_API_HOOKS_ENABLE) {
119  memset(&em_shm->conf.api_hooks, 0,
120  sizeof(em_shm->conf.api_hooks));
121  }
122 
123  /* Initialize the log & error handling */
124  log_init();
125  error_init();
126 
127  /* Initialize libconfig */
128  ret = em_libconfig_init_global(&em_shm->libconfig);
130  "libconfig initialization failed:%d", ret);
131 
132  /*
133  * Initialize the physical-core <-> EM-core mapping
134  *
135  * EM-core <-> ODP-thread id mappings cannot be set up yet,
136  * the ODP thread id is assigned only when that thread is initialized.
137  * Set this mapping in core_map_init_local()
138  */
139  stat = core_map_init(&em_shm->core_map, conf->core_count,
140  &conf->phys_mask);
142  "core_map_init() failed:%" PRI_STAT "", stat);
143 
144  /* Initialize the EM event dispatcher */
145  stat = dispatch_init();
147  "dispatch_init() failed:%" PRI_STAT "", stat);
148 
149  /*
150  * Check validity of core masks for input_poll_fn and output_drain_fn.
151  *
152  * Masks must be a subset of logical EM core mask. Zero mask means
153  * that input_poll_fn and output_drain_fn are run on all EM cores.
154  */
155  stat = input_poll_check(&em_shm->core_map.logic_mask, conf);
157  "input_poll_init() failed:%" PRI_STAT "", stat);
158  stat = output_drain_check(&em_shm->core_map.logic_mask, conf);
160  "output_drain_init() failed:%" PRI_STAT "", stat);
161 
162  /*
163  * Initialize Event State Verification (ESV), if enabled at compile time
164  */
165  if (EM_ESV_ENABLE) {
166  stat = esv_init();
168  "esv_init() failed:%" PRI_STAT "", stat);
169  } else {
171  }
172 
173  /* Initialize EM callbacks/hooks */
174  stat = hooks_init(&conf->api_hooks, &conf->idle_hooks);
176  "hooks_init() failed:%" PRI_STAT "", stat);
177 
178  /*
179  * Initialize the EM buffer pools and create the EM_DEFAULT_POOL.
180  * Create also startup pools if configured in the runtime config
181  * file through option 'startup_pools'.
182  */
183  stat = pool_init(&em_shm->mpool_tbl, &em_shm->mpool_pool,
184  &conf->default_pool_cfg);
186  "pool_init() failed:%" PRI_STAT "", stat);
187 
188  stat = event_init();
190  "event_init() failed:%" PRI_STAT "", stat);
191 
192  stat = event_group_init(&em_shm->event_group_tbl,
193  &em_shm->event_group_pool);
195  "event_group_init() failed:%" PRI_STAT "", stat);
196 
197  stat = queue_init(&em_shm->queue_tbl, &em_shm->queue_pool,
198  &em_shm->queue_pool_static);
200  "queue_init() failed:%" PRI_STAT "", stat);
201 
202  stat = queue_group_init(&em_shm->queue_group_tbl,
203  &em_shm->queue_group_pool);
205  "queue_group_init() failed:%" PRI_STAT "", stat);
206 
207  stat = atomic_group_init(&em_shm->atomic_group_tbl,
208  &em_shm->atomic_group_pool);
210  "atomic_group_init() failed:%" PRI_STAT "", stat);
211 
212  stat = eo_init(&em_shm->eo_tbl, &em_shm->eo_pool);
214  "eo_init() failed:%" PRI_STAT "", stat);
215 
216  stat = create_ctrl_queues();
218  "create_ctrl_queues() failed:%" PRI_STAT "", stat);
219 
220  /* Initialize EM Timer */
221  if (conf->event_timer) {
222  stat = timer_init(&em_shm->timers);
223  RETURN_ERROR_IF(stat != EM_OK,
225  "timer_init() failed:%" PRI_STAT "",
226  stat);
227  }
228 
229  /* Initialize basic Event Chaining support */
230  stat = chaining_init(&em_shm->event_chaining);
232  "chaining_init() failed:%" PRI_STAT "", stat);
233 
234  /* Initialize em_cli */
235  stat = emcli_init();
237  "emcli_init() failed:%" PRI_STAT "", stat);
238 
239  /*
240  * Print EM and ODP version information
241  */
242  print_version_info();
243 
244  return EM_OK;
245 }
246 
248 {
249  em_locm_t *const locm = &em_locm;
250  odp_shm_t shm;
251  em_shm_t *shm_addr;
252  em_status_t stat;
253 
254  /* Lookup the EM shared memory on each EM-core */
255  shm = odp_shm_lookup("em_shm");
256  RETURN_ERROR_IF(shm == ODP_SHM_INVALID,
258  "Shared memory lookup failed!");
259 
260  shm_addr = odp_shm_addr(shm);
262  "Shared memory ptr NULL");
263 
264  if (shm_addr->conf.process_per_core && em_shm == NULL)
265  em_shm = shm_addr;
266 
268  "Shared memory init fails: em_shm:%p != shm_addr:%p",
269  em_shm, shm_addr);
270 
271  /* Initialize core mappings not known yet in core_map_init() */
272  stat = core_map_init_local(&em_shm->core_map);
274  "core_map_init_local() failed:%" PRI_STAT "", stat);
275 
276  stat = queue_group_init_local();
278  "queue_group_init_local() failed:%" PRI_STAT "", stat);
279 
280  stat = dispatch_init_local();
282  "dispatch_init_local() failed:%" PRI_STAT "", stat);
283 
284  /* Check if input_poll_fn should be executed on this core */
285  stat = input_poll_init_local();
287  "input_poll_init_local() failed:%" PRI_STAT "", stat);
288 
289  /* Check if output_drain_fn should be executed on this core */
290  stat = output_drain_init_local();
292  "output_drain_init_local() failed:%" PRI_STAT "", stat);
293 
294  stat = queue_init_local();
296  "queue_init_local() failed:%" PRI_STAT "", stat);
297 
298  /*
299  * Initialize EM timer. If global init was not done (config),
300  * this is just a NOP
301  */
302  stat = timer_init_local();
304  "timer_init_local() failed:%" PRI_STAT "", stat);
305 
306  stat = sync_api_init_local();
308  "sync_api_init_local() failed:%" PRI_STAT "", stat);
309 
310  /* Init the EM CLI locally on this core (only if enabled) */
311  stat = emcli_init_local();
313  "emcli_init_local() failed:%" PRI_STAT "", stat);
314 
315  /* This is an EM-core that will participate in EM event dispatching */
316  locm->is_external_thr = false;
317 
318  /* Initialize debug timestamps to 1 if enabled to differentiate from disabled */
320  for (int i = 0; i < EM_DEBUG_TSP_LAST; i++)
321  locm->debug_ts[i] = 1;
322 
323  /* Now OK to call EM APIs */
324 
325  env_sync_mem();
326 
327  return EM_OK;
328 }
329 
330 static void flush_scheduler_events(void)
331 {
332  odp_event_t odp_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
334  em_event_t em_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
335  int num_events;
336 
337  do {
338  num_events = odp_schedule_multi_no_wait(NULL, odp_ev_tbl, EM_SCHED_MULTI_MAX_BURST);
339  /* the check 'num_events > EM_SCHED_MULTI_MAX_BURST' avoids a gcc warning */
340  if (num_events <= 0 || num_events > EM_SCHED_MULTI_MAX_BURST)
341  break;
342  /*
343  * Events might originate from outside of EM and need init.
344  */
345  event_init_odp_multi(odp_ev_tbl, em_ev_tbl/*out*/, ev_hdr_tbl/*out*/,
346  num_events, true/*is_extev*/);
347  em_free_multi(em_ev_tbl, num_events);
348  } while (num_events > 0);
349 }
350 
352 {
353  em_locm_t *const locm = &em_locm;
354  em_status_t stat;
355  int ret;
356 
357  (void)conf;
358 
359  /*
360  * Join all queue groups to be able to flush all events
361  * from the scheduler from this core.
362  */
364 
365  /*
366  * Flush all events in the scheduler.
367  * Run loop twice: first with sched enabled and then paused.
368  */
369  if (locm->is_sched_paused) {
370  locm->is_sched_paused = false;
371  odp_schedule_resume();
372  }
373  for (int i = 0; i < 2; i++) {
374  flush_scheduler_events();
375  locm->is_sched_paused = true;
376  odp_schedule_pause();
377  }
378 
379  stat = delete_ctrl_queues();
381  "delete_ctrl_queues() failed:%" PRI_STAT "", stat);
382 
383  if (em_shm->conf.event_timer)
384  timer_term(&em_shm->timers);
385 
386  stat = emcli_term();
388  "emcli_term() failed:%" PRI_STAT "", stat);
389 
390  stat = chaining_term(&em_shm->event_chaining);
392  "chaining_term() failed:%" PRI_STAT "", stat);
393 
394  ret = em_libconfig_term_global(&em_shm->libconfig);
396  "EM config term failed:%d");
397 
398  stat = pool_term(&em_shm->mpool_tbl);
400  "pool_term() failed:%" PRI_STAT "", stat);
401 
402  env_shared_free(em_shm->queue_tbl.queue_elem);
403 
404  /*
405  * Free the EM shared memory
406  */
407  ret = odp_shm_free(em_shm->this_shm);
409  "odp_shm_free() failed:%d", ret);
410  /* Set em_shm = NULL to allow a new call to em_init() */
411  em_shm = NULL;
412 
413  return EM_OK;
414 }
415 
417 {
418  em_status_t stat = EM_OK;
419  em_status_t ret_stat = EM_OK;
420  em_locm_t *const locm = &em_locm;
421 
422  /*
423  * Poll internal unscheduled ctrl queues to complete ctrl actions
424  * and flush them.
425  */
427 
428  /*
429  * Flush the scheduler from locally stashed events.
430  */
431  if (!locm->is_sched_paused) {
432  locm->is_sched_paused = true;
433  odp_schedule_pause();
434  }
435  flush_scheduler_events();
436 
437  /* Stop EM Timer. Just a NOP if timer was not enabled (config) */
438  stat = timer_term_local();
439  if (stat != EM_OK) {
440  ret_stat = stat;
442  "timer_term_local() fails: %" PRI_STAT "", stat);
443  }
444 
445  /* Term the EM CLI locally (if enabled) */
446  stat = emcli_term_local();
447  if (stat != EM_OK) {
448  ret_stat = stat;
450  "emcli_term_local() fails: %" PRI_STAT "", stat);
451  }
452 
453  /* Delete the local queues */
454  stat = queue_term_local();
455  if (stat != EM_OK) {
456  ret_stat = stat;
458  "queue_term_local() fails: %" PRI_STAT "", stat);
459  }
460 
461  stat = core_map_term_local(&em_shm->core_map);
463  "core_map_term_local() failed:%" PRI_STAT "", stat);
464 
465  return ret_stat == EM_OK ? EM_OK : EM_ERR;
466 }
467 
468 uint16_t em_device_id(void)
469 {
470  return em_shm->conf.device_id;
471 }
em_device_id
uint16_t em_device_id(void)
Definition: event_machine_init.c:468
em_conf_t::vlog_fn
em_vlog_func_t vlog_fn
Definition: event_machine_init.h:171
delete_ctrl_queues
em_status_t delete_ctrl_queues(void)
Delete EM's internal unscheduled control queues at teardown.
Definition: em_internal_event.c:96
EM_OK
#define EM_OK
Definition: event_machine_types.h:329
emcli_init
em_status_t emcli_init(void)
Initialize the EM CLI (if enabled)
Definition: em_cli.c:1446
EM_ERR
@ EM_ERR
Definition: event_machine_hw_types.h:312
em_conf_t::event_timer
int event_timer
Definition: event_machine_init.h:105
queue_group_join_all
void queue_group_join_all(void)
The calling core joins all available queue groups.
Definition: em_queue_group.c:370
atomic_group_init
em_status_t atomic_group_init(atomic_group_tbl_t *const atomic_group_tbl, atomic_group_pool_t *const atomic_group_pool)
Definition: em_atomic_group.c:38
emcli_init_local
em_status_t emcli_init_local(void)
Initialize the EM CLI locally on an EM core (if enabled)
Definition: em_cli.c:1451
chaining_term
em_status_t chaining_term(const event_chaining_t *event_chaining)
Definition: em_chaining.c:194
queue_group_elem_t
Definition: em_queue_group_types.h:59
em_conf_t::thread_per_core
int thread_per_core
Definition: event_machine_init.h:115
EM_API_HOOKS_ENABLE
#define EM_API_HOOKS_ENABLE
Definition: event_machine_config.h:182
create_ctrl_queues
em_status_t create_ctrl_queues(void)
Create EM's internal unscheduled control queues at startup.
Definition: em_internal_event.c:41
EM_ESCOPE_TERM
#define EM_ESCOPE_TERM
Definition: event_machine_hw_types.h:473
error_init
void error_init(void)
Definition: em_error.c:339
esv_disabled_warn_config
void esv_disabled_warn_config(void)
Definition: em_event_state.c:1210
em_locm
ENV_LOCAL em_locm_t em_locm
EM_SCHED_MULTI_MAX_BURST
#define EM_SCHED_MULTI_MAX_BURST
Definition: event_machine_hw_config.h:226
em_locm_t::is_sched_paused
bool is_sched_paused
Definition: em_mem.h:209
EM_ERR_ALLOC_FAILED
@ EM_ERR_ALLOC_FAILED
Definition: event_machine_hw_types.h:287
EM_ERR_LIB_FAILED
@ EM_ERR_LIB_FAILED
Definition: event_machine_hw_types.h:291
chaining_init
em_status_t chaining_init(event_chaining_t *event_chaining)
Definition: em_chaining.c:135
queue_group_init
em_status_t queue_group_init(queue_group_tbl_t *const queue_group_tbl, queue_group_pool_t *const queue_group_pool)
Definition: em_queue_group.c:122
em_conf_t::default_pool_cfg
em_pool_cfg_t default_pool_cfg
Definition: event_machine_init.h:160
event_hdr
Definition: em_event_types.h:184
em_conf_t::log
struct em_conf_t::@3 log
em_shm_t
Definition: em_mem.h:53
em_shm_t::libconfig
libconfig_t libconfig
Definition: em_mem.h:146
em_conf_t::log_fn
em_log_func_t log_fn
Definition: event_machine_init.h:169
poll_unsched_ctrl_queue
void poll_unsched_ctrl_queue(void)
Poll EM's internal unscheduled control queues during dispatch.
Definition: em_internal_event.c:540
em_term_core
em_status_t em_term_core(void)
Definition: event_machine_init.c:416
RETURN_ERROR_IF
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition: em_error.h:50
em_locm_t::debug_ts
uint64_t debug_ts[EM_DEBUG_TSP_LAST]
Definition: em_mem.h:239
emcli_term
em_status_t emcli_term(void)
Terminate the EM CLI (if enabled)
Definition: em_cli.c:1456
INTERNAL_ERROR
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
em_pool_cfg_init
void em_pool_cfg_init(em_pool_cfg_t *const pool_cfg)
Definition: event_machine_pool.c:43
em_term
em_status_t em_term(const em_conf_t *conf)
Definition: event_machine_init.c:351
em_init
em_status_t em_init(const em_conf_t *conf)
Definition: event_machine_init.c:65
em_conf_t::process_per_core
int process_per_core
Definition: event_machine_init.h:123
emcli_term_local
em_status_t emcli_term_local(void)
Terminate the EM CLI locally on an EM core (if enabled)
Definition: em_cli.c:1461
em_conf_t::idle_hooks
em_idle_hooks_t idle_hooks
Definition: event_machine_init.h:225
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
EM_ERR_OPERATION_FAILED
@ EM_ERR_OPERATION_FAILED
Definition: event_machine_hw_types.h:289
em_conf_init
void em_conf_init(em_conf_t *conf)
Definition: event_machine_init.c:54
em_conf_t::api_hooks
em_api_hooks_t api_hooks
Definition: event_machine_init.h:218
em_include.h
EM_ESV_ENABLE
#define EM_ESV_ENABLE
Definition: event_machine_config.h:275
em_shm
em_shm_t * em_shm
Definition: event_machine_init.c:41
hooks_init
em_status_t hooks_init(const em_api_hooks_t *api_hooks, const em_idle_hooks_t *idle_hooks)
Definition: em_hooks.c:46
EM_SCHED_CONTEXT_TYPE_NONE
@ EM_SCHED_CONTEXT_TYPE_NONE
Definition: event_machine_types.h:281
EM_ESCOPE_CONF_INIT
#define EM_ESCOPE_CONF_INIT
Definition: event_machine_hw_types.h:458
queue_init_local
em_status_t queue_init_local(void)
Definition: em_queue.c:303
EM_ERR_NOT_FOUND
@ EM_ERR_NOT_FOUND
Definition: event_machine_hw_types.h:278
em_shm_t::this_shm
odp_shm_t this_shm
Definition: em_mem.h:55
EM_ESCOPE_INIT
#define EM_ESCOPE_INIT
Definition: event_machine_hw_types.h:463
queue_init
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_ERR_BAD_POINTER
@ EM_ERR_BAD_POINTER
Definition: event_machine_hw_types.h:271
esv_init
em_status_t esv_init(void)
Definition: em_event_state.c:1202
EM_ESCOPE_TERM_CORE
#define EM_ESCOPE_TERM_CORE
Definition: event_machine_hw_types.h:478
queue_term_local
em_status_t queue_term_local(void)
Definition: em_queue.c:367
EM_ERR_BAD_ARG
@ EM_ERR_BAD_ARG
Definition: event_machine_hw_types.h:261
em_conf_t::core_count
int core_count
Definition: event_machine_init.h:132
em_free_multi
void em_free_multi(em_event_t events[], int num)
Definition: event_machine_event.c:370
em_locm_t
Definition: em_mem.h:188
ENV_LOCAL
#define ENV_LOCAL
Definition: environment.h:57
em_conf_t::phys_mask
em_core_mask_t phys_mask
Definition: event_machine_init.h:149
EM_ERR_BAD_STATE
@ EM_ERR_BAD_STATE
Definition: event_machine_hw_types.h:263
em_locm_t::is_external_thr
bool is_external_thr
Definition: em_mem.h:207
EM_ESCOPE_INIT_CORE
#define EM_ESCOPE_INIT_CORE
Definition: event_machine_hw_types.h:468
EM_EVENT_GROUP_UNDEF
#define EM_EVENT_GROUP_UNDEF
Definition: event_machine_types.h:141
EM_DEBUG_TIMESTAMP_ENABLE
#define EM_DEBUG_TIMESTAMP_ENABLE
Definition: event_machine_config.h:325
em_init_core
em_status_t em_init_core(void)
Definition: event_machine_init.c:247
em_conf_t
Definition: event_machine_init.h:93