EM-ODP  3.7.0
Event Machine on ODP
event_machine_dispatcher.c
1 /*
2  * Copyright (c) 2015-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 #include "em_include.h"
32 #include "em_dispatcher_inline.h"
33 
34 static const em_dispatch_opt_t dispatch_opt_default = {
36  .__internal_check = EM_CHECK_INIT_CALLED
37  /* other members initialized to 0 or NULL as per C standard */
38 };
39 
40 uint64_t em_dispatch(uint64_t rounds /* 0 = forever */)
41 {
42  uint64_t events;
43 
44  em_locm_t *const locm = &em_locm;
45  const bool do_input_poll = locm->do_input_poll;
46  const bool do_output_drain = locm->do_output_drain;
47  const bool do_schedule_pause = em_shm->opt.dispatch.sched_pause;
48 
49  if (locm->is_sched_paused) {
50  odp_schedule_resume();
51  locm->is_sched_paused = false;
52  }
53 
54  if (do_input_poll || do_output_drain)
55  events = dispatch_with_userfn(rounds, do_input_poll, do_output_drain);
56  else
57  events = dispatch_no_userfn(rounds);
58 
59  if (do_schedule_pause) {
60  /* pause scheduling before exiting the dispatch loop */
61  int round_events;
62 
63  odp_schedule_pause();
64  locm->is_sched_paused = true;
65 
66  /* empty the locally pre-scheduled events (if any) */
67  do {
68  round_events = dispatch_round(ODP_SCHED_NO_WAIT,
70  events += round_events;
71  } while (round_events > 0);
72  }
73 
74  return events;
75 }
76 
78 {
79  if (unlikely(!opt)) {
80  INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_OPT_INIT,
81  "Bad argument, opt=NULL");
82  return;
83  }
84 
85  *opt = dispatch_opt_default;
86 }
87 
88 static inline em_status_t
89 dispatch_duration(const em_dispatch_duration_t *duration,
90  const em_dispatch_opt_t *opt,
91  em_dispatch_results_t *results /*out, optional*/)
92 {
93  em_locm_t *const locm = &em_locm;
94  const bool do_input_poll = locm->do_input_poll && !opt->skip_input_poll;
95  const bool do_output_drain = locm->do_output_drain && !opt->skip_output_drain;
96  const bool do_sched_pause = opt->sched_pause;
97  uint64_t events;
98 
99  if (locm->is_sched_paused) {
100  odp_schedule_resume();
101  locm->is_sched_paused = false;
102  }
103 
104  if (do_input_poll || do_output_drain)
105  events = dispatch_duration_with_userfn(duration, opt, results,
106  do_input_poll, do_output_drain);
107  else
108  events = dispatch_duration_no_userfn(duration, opt, results);
109 
110  /* pause scheduling before exiting the dispatch loop */
111  if (do_sched_pause) {
112  odp_schedule_pause();
113  locm->is_sched_paused = true;
114 
115  int round_events;
116  uint64_t rounds = 0;
117  uint16_t burst_size = opt->burst_size;
118 
119  /* empty the locally pre-scheduled events (if any) */
120  do {
121  round_events = dispatch_round(ODP_SCHED_NO_WAIT,
122  burst_size, opt);
123  events += round_events;
124  rounds++;
125  } while (round_events > 0);
126 
127  if (results) {
128  results->rounds += rounds;
129  results->events = events;
130  }
131  }
132 
133  return EM_OK;
134 }
135 
137  const em_dispatch_opt_t *opt /* optional */,
138  em_dispatch_results_t *results /*out, optional*/)
139 {
140  RETURN_ERROR_IF(!duration, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
141  "Bad argument: duration=NULL");
142 
143  if (!opt) {
144  opt = &dispatch_opt_default;
145  } else {
147  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
148  "Bad argument: em_dispatch_opt_init(opt) not called");
149  }
150 
151  if (EM_CHECK_LEVEL > 0) {
153  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
154  "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
156  }
157 
158  if (EM_CHECK_LEVEL > 1) {
159  /* _FLAG_LAST is 'pow2 + 1' */
160  const em_dispatch_duration_select_t next_pow2 =
161  (EM_DISPATCH_DURATION_LAST >> 1) << 2;
162 
163  RETURN_ERROR_IF(duration->select >= next_pow2,
164  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
165  "Bad option: duration->select=0x%x invalid", duration->select);
167  duration->rounds == 0) ||
168  (duration->select & EM_DISPATCH_DURATION_NS &&
169  duration->ns == 0) ||
170  (duration->select & EM_DISPATCH_DURATION_EVENTS &&
171  duration->events == 0) ||
173  duration->no_events.rounds == 0) ||
175  duration->no_events.ns == 0)),
176  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
177  "Bad option: opt.duration is zero(0).");
178  }
179 
180  return dispatch_duration(duration, opt, results);
181 }
182 
184  const em_dispatch_opt_t *opt,
185  em_dispatch_results_t *results /*out*/)
186 {
187  RETURN_ERROR_IF(ns == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_NS,
188  "Bad argument: ns=0");
189 
190  if (!opt) {
191  opt = &dispatch_opt_default;
192  } else {
194  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_NS,
195  "Bad argument: em_dispatch_opt_init(opt) not called");
196  }
197 
198  if (EM_CHECK_LEVEL > 0) {
200  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_NS,
201  "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
203  }
204 
205  const em_dispatch_duration_t duration = {
207  .ns = ns
208  };
209 
210  return dispatch_duration(&duration, opt, results);
211 }
212 
214  const em_dispatch_opt_t *opt,
215  em_dispatch_results_t *results /*out*/)
216 {
217  RETURN_ERROR_IF(events == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_EVENTS,
218  "Bad argument: events=0");
219 
220  if (!opt) {
221  opt = &dispatch_opt_default;
222  } else {
224  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_EVENTS,
225  "Bad argument: em_dispatch_opt_init(opt) not called");
226  }
227 
228  if (EM_CHECK_LEVEL > 0) {
230  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_EVENTS,
231  "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
233  }
234 
235  const em_dispatch_duration_t duration = {
237  .events = events
238  };
239 
240  return dispatch_duration(&duration, opt, results);
241 }
242 
244  const em_dispatch_opt_t *opt,
245  em_dispatch_results_t *results /*out*/)
246 {
247  RETURN_ERROR_IF(rounds == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_ROUNDS,
248  "Bad argument: rounds=0");
249 
250  if (!opt) {
251  opt = &dispatch_opt_default;
252  } else {
254  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_ROUNDS,
255  "Bad argument: em_dispatch_opt_init(opt) not called");
256  }
257 
258  if (EM_CHECK_LEVEL > 0) {
260  EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_ROUNDS,
261  "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
263  }
264 
265  const em_dispatch_duration_t duration = {
267  .rounds = rounds
268  };
269 
270  return dispatch_duration(&duration, opt, results);
271 }
272 
275 {
276  hook_fn_t hook_fn;
277  em_status_t stat;
278 
279  RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
280  EM_ESCOPE_DISPATCH_REGISTER_ENTER_CB,
281  "EM dispatch callbacks disabled");
282 
283  hook_fn.disp_enter = func;
284  stat = hook_register(DISPATCH_CALLBACK_ENTER, hook_fn);
285  RETURN_ERROR_IF(stat != EM_OK, stat,
286  EM_ESCOPE_DISPATCH_REGISTER_ENTER_CB,
287  "Dispatch callback register failed");
288 
289  return EM_OK;
290 }
291 
294 {
295  hook_fn_t hook_fn;
296  em_status_t stat;
297 
298  RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
299  EM_ESCOPE_DISPATCH_UNREGISTER_ENTER_CB,
300  "EM dispatch callbacks disabled");
301 
302  hook_fn.disp_enter = func;
303  stat = hook_unregister(DISPATCH_CALLBACK_ENTER, hook_fn);
304  RETURN_ERROR_IF(stat != EM_OK, stat,
305  EM_ESCOPE_DISPATCH_UNREGISTER_ENTER_CB,
306  "Dispatch callback unregister failed");
307 
308  return EM_OK;
309 }
310 
313 {
314  hook_fn_t hook_fn;
315  em_status_t stat;
316 
317  RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
318  EM_ESCOPE_DISPATCH_REGISTER_EXIT_CB,
319  "EM dispatch callbacks disabled");
320 
321  hook_fn.disp_exit = func;
322  stat = hook_register(DISPATCH_CALLBACK_EXIT, hook_fn);
323  RETURN_ERROR_IF(stat != EM_OK, stat,
324  EM_ESCOPE_DISPATCH_REGISTER_EXIT_CB,
325  "Dispatch callback register failed");
326  return EM_OK;
327 }
328 
331 {
332  hook_fn_t hook_fn;
333  em_status_t stat;
334 
335  RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
336  EM_ESCOPE_DISPATCH_UNREGISTER_EXIT_CB,
337  "EM dispatch callbacks disabled");
338 
339  hook_fn.disp_exit = func;
340  stat = hook_unregister(DISPATCH_CALLBACK_EXIT, hook_fn);
341  RETURN_ERROR_IF(stat != EM_OK, stat,
342  EM_ESCOPE_DISPATCH_UNREGISTER_EXIT_CB,
343  "Dispatch callback unregister failed");
344  return EM_OK;
345 }
em_dispatch_duration_t::ns
uint64_t ns
Definition: event_machine_dispatcher.h:143
EM_OK
#define EM_OK
Definition: event_machine_types.h:329
em_dispatch_duration_select_t
em_dispatch_duration_select_t
EM dispatch duration selection flags.
Definition: event_machine_dispatcher.h:82
em_locm_t::do_output_drain
bool do_output_drain
Definition: em_mem.h:205
em_dispatch_duration_t::rounds
uint64_t rounds
Definition: event_machine_dispatcher.h:128
hook_register
em_status_t hook_register(uint8_t type, hook_fn_t hook_fn)
Definition: em_hooks.c:140
em_dispatch_exit_func_t
void(* em_dispatch_exit_func_t)(em_eo_t eo)
Definition: event_machine_dispatcher.h:548
em_dispatch_duration_t::select
em_dispatch_duration_select_t select
Definition: event_machine_dispatcher.h:118
em_dispatch_duration_t
Definition: event_machine_dispatcher.h:110
em_dispatch_results_t::rounds
uint64_t rounds
Definition: event_machine_dispatcher.h:266
em_dispatch_opt_t
EM dispatch options.
Definition: event_machine_dispatcher.h:190
em_dispatch_opt_t::skip_input_poll
bool skip_input_poll
Definition: event_machine_dispatcher.h:219
em_locm
ENV_LOCAL em_locm_t em_locm
em_dispatch
uint64_t em_dispatch(uint64_t rounds)
Definition: event_machine_dispatcher.c:40
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_dispatch_opt_t::burst_size
uint16_t burst_size
Definition: event_machine_dispatcher.h:210
em_dispatch_duration_t::events
uint64_t events
Definition: event_machine_dispatcher.h:158
em_dispatch_rounds
em_status_t em_dispatch_rounds(uint64_t rounds, const em_dispatch_opt_t *opt, em_dispatch_results_t *results)
Run the EM dispatcher for a given number of dispatch-rounds.
Definition: event_machine_dispatcher.c:243
EM_DISPATCH_DURATION_NS
@ EM_DISPATCH_DURATION_NS
Definition: event_machine_dispatcher.h:88
em_dispatch_ns
em_status_t em_dispatch_ns(uint64_t ns, const em_dispatch_opt_t *opt, em_dispatch_results_t *results)
Run the EM dispatcher for a given amount of time (in nanoseconds).
Definition: event_machine_dispatcher.c:183
em_dispatch_register_enter_cb
em_status_t em_dispatch_register_enter_cb(em_dispatch_enter_func_t func)
Definition: event_machine_dispatcher.c:274
em_dispatch_opt_t::sched_pause
bool sched_pause
Definition: event_machine_dispatcher.h:244
hook_unregister
em_status_t hook_unregister(uint8_t type, hook_fn_t hook_fn)
Definition: em_hooks.c:194
em_dispatch_opt_t::skip_output_drain
bool skip_output_drain
Definition: event_machine_dispatcher.h:228
em_dispatch_results_t
Dispatch results.
Definition: event_machine_dispatcher.h:262
RETURN_ERROR_IF
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition: em_error.h:50
em_locm_t::do_input_poll
bool do_input_poll
Definition: em_mem.h:203
INTERNAL_ERROR
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
em_dispatch_duration
em_status_t em_dispatch_duration(const em_dispatch_duration_t *duration, const em_dispatch_opt_t *opt, em_dispatch_results_t *results)
Run the EM dispatcher for a certain duration with options.
Definition: event_machine_dispatcher.c:136
em_dispatch_results_t::events
uint64_t events
Definition: event_machine_dispatcher.h:281
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
EM_CHECK_LEVEL
#define EM_CHECK_LEVEL
Definition: event_machine_config.h:253
EM_DISPATCH_DURATION_EVENTS
@ EM_DISPATCH_DURATION_EVENTS
Definition: event_machine_dispatcher.h:90
em_shm
em_shm_t * em_shm
Definition: event_machine_init.c:41
em_include.h
em_dispatch_opt_t::__internal_check
uint32_t __internal_check
Definition: event_machine_dispatcher.h:252
EM_DISPATCH_DURATION_NO_EVENTS_ROUNDS
@ EM_DISPATCH_DURATION_NO_EVENTS_ROUNDS
Definition: event_machine_dispatcher.h:93
EM_CHECK_INIT_CALLED
#define EM_CHECK_INIT_CALLED
Definition: em_include.h:69
em_dispatch_opt_init
void em_dispatch_opt_init(em_dispatch_opt_t *opt)
Initialize the EM dispatch options.
Definition: event_machine_dispatcher.c:77
EM_DISPATCH_DURATION_ROUNDS
@ EM_DISPATCH_DURATION_ROUNDS
Definition: event_machine_dispatcher.h:86
hook_fn_t
Definition: em_hook_types.h:61
em_dispatch_enter_func_t
void(* em_dispatch_enter_func_t)(em_eo_t eo, void **eo_ctx, em_event_t events[], int num, em_queue_t *queue, void **q_ctx)
Definition: event_machine_dispatcher.h:533
em_dispatcher_inline.h
EM_ERR_BAD_ARG
@ EM_ERR_BAD_ARG
Definition: event_machine_hw_types.h:261
EM_ERR_NOT_IMPLEMENTED
@ EM_ERR_NOT_IMPLEMENTED
Definition: event_machine_hw_types.h:282
em_dispatch_unregister_enter_cb
em_status_t em_dispatch_unregister_enter_cb(em_dispatch_enter_func_t func)
Definition: event_machine_dispatcher.c:293
em_locm_t
Definition: em_mem.h:188
em_dispatch_unregister_exit_cb
em_status_t em_dispatch_unregister_exit_cb(em_dispatch_exit_func_t func)
Definition: event_machine_dispatcher.c:330
em_dispatch_events
em_status_t em_dispatch_events(uint64_t events, const em_dispatch_opt_t *opt, em_dispatch_results_t *results)
Run the EM dispatcher until a given number of events have been dispatched.
Definition: event_machine_dispatcher.c:213
em_dispatch_register_exit_cb
em_status_t em_dispatch_register_exit_cb(em_dispatch_exit_func_t func)
Definition: event_machine_dispatcher.c:312
EM_DISPATCH_DURATION_NO_EVENTS_NS
@ EM_DISPATCH_DURATION_NO_EVENTS_NS
Definition: event_machine_dispatcher.h:95