EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
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#ifndef _GNU_SOURCE
32#define _GNU_SOURCE
33#endif
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <stdbool.h>
40#include <stdint.h>
41
42#include <odp_api.h>
43
44#include <event_machine.h>
45
46#include "em_dispatcher.h"
48#include "em_dispatcher_types.h"
49#include "em_error.h"
50#include "em_hooks.h"
51#include "em_hook_types.h"
52#include "em_mem.h"
53
54static const em_dispatch_opt_t dispatch_opt_default = {
56 .__internal_check = EM_CHECK_INIT_CALLED
57 /* other members initialized to 0 or NULL as per C standard */
58};
59
60uint64_t em_dispatch(uint64_t rounds /* 0 = forever */)
61{
62 uint64_t events;
63
64 em_locm_t *const locm = &em_locm;
65 const em_input_poll_func_t input_poll_fn = locm->input_poll_fn;
66 const em_output_drain_func_t output_drain_fn = locm->output_drain_fn;
67 const bool do_schedule_pause = em_shm->opt.dispatch.sched_pause;
68
69 if (unlikely(EM_CHECK_LEVEL >= 3 && !locm->is_em_core)) {
70 EM_LOG(EM_LOG_ERR, "%s(): Not an EM-core, can not dispatch!", __func__);
71 return 0;
72 }
73
74 if (locm->is_sched_paused) {
75 odp_schedule_resume();
76 locm->is_sched_paused = false;
77 }
78
79 /* Reset local queue event count - updated during the dispatch rounds */
80 locm->local_event_cnt = 0;
81
82 if (input_poll_fn || output_drain_fn)
83 events = dispatch_with_userfn(rounds, input_poll_fn, output_drain_fn);
84 else
85 events = dispatch_no_userfn(rounds);
86
87 if (do_schedule_pause) {
88 /* pause scheduling before exiting the dispatch loop */
89 int round_events;
90
91 odp_schedule_pause();
92 locm->is_sched_paused = true;
93
94 /* empty the locally pre-scheduled events (if any) */
95 do {
96 round_events = dispatch_round(ODP_SCHED_NO_WAIT,
98 events += round_events;
99 } while (round_events > 0);
100 }
101
102 /* add events dispatched from local queues to the dispatch count */
103 return events + locm->local_event_cnt;
104}
105
107{
108 if (unlikely(!opt)) {
109 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_OPT_INIT,
110 "Bad argument, opt=NULL");
111 return;
112 }
113
114 *opt = dispatch_opt_default;
115}
116
117static inline em_status_t
118dispatch_duration(const em_dispatch_duration_t *duration,
119 const em_dispatch_opt_t *opt,
120 em_dispatch_results_t *results /*out, optional*/)
121{
122 em_locm_t *const locm = &em_locm;
123 const em_input_poll_func_t input_poll_fn = locm->input_poll_fn;
124 const em_output_drain_func_t output_drain_fn = locm->output_drain_fn;
125 const bool do_input_poll = input_poll_fn && !opt->skip_input_poll;
126 const bool do_output_drain = output_drain_fn && !opt->skip_output_drain;
127 const bool do_sched_pause = opt->sched_pause;
128 uint64_t events;
129
130 if (unlikely(EM_CHECK_LEVEL >= 3 && !locm->is_em_core)) {
131 EM_LOG(EM_LOG_ERR, "%s(): Not an EM-core, can not dispatch!", __func__);
132 if (results)
133 memset(results, 0, sizeof(*results));
135 }
136
137 if (locm->is_sched_paused) {
138 odp_schedule_resume();
139 locm->is_sched_paused = false;
140 }
141
142 /* Reset local queue event count - updated during the dispatch rounds */
143 locm->local_event_cnt = 0;
144
145 if (do_input_poll || do_output_drain)
146 events = dispatch_duration_with_userfn(duration, opt,
147 input_poll_fn, output_drain_fn,
148 results /*out*/);
149 else
150 events = dispatch_duration_no_userfn(duration, opt, results /*out*/);
151
152 /* pause scheduling before exiting the dispatch loop */
153 if (do_sched_pause) {
154 odp_schedule_pause();
155 locm->is_sched_paused = true;
156
157 int round_events;
158 uint64_t rounds = 0;
159 uint16_t burst_size = opt->burst_size;
160
161 /* empty the locally pre-scheduled events (if any) */
162 do {
163 round_events = dispatch_round(ODP_SCHED_NO_WAIT,
164 burst_size, opt);
165 events += round_events;
166 rounds++;
167 } while (round_events > 0);
168
169 if (results) {
170 results->rounds += rounds;
171 results->events = events;
172 }
173 }
174
175 if (results) {
176 /* add events dispatched from local queues to the result */
177 results->events += locm->local_event_cnt;
178 }
179
180 return EM_OK;
181}
182
184 const em_dispatch_opt_t *opt /* optional */,
185 em_dispatch_results_t *results /*out, optional*/)
186{
187 RETURN_ERROR_IF(!duration, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
188 "Bad argument: duration=NULL");
189
190 if (!opt) {
191 opt = &dispatch_opt_default;
192 } else {
194 EM_ERR_NOT_INITIALIZED, EM_ESCOPE_DISPATCH_DURATION,
195 "Not initialized: em_dispatch_opt_init(opt) not called");
196 }
197
198 if (EM_CHECK_LEVEL > 0) {
200 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
201 "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
203 }
204
205 if (EM_CHECK_LEVEL > 1) {
206 /* _FLAG_LAST is 'pow2 + 1' */
207 const em_dispatch_duration_select_t next_pow2 =
208 (EM_DISPATCH_DURATION_LAST >> 1) << 2;
209
210 RETURN_ERROR_IF(duration->select >= next_pow2,
211 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
212 "Bad option: duration->select=0x%x invalid", duration->select);
214 duration->rounds == 0) ||
215 (duration->select & EM_DISPATCH_DURATION_NS &&
216 duration->ns == 0) ||
217 (duration->select & EM_DISPATCH_DURATION_EVENTS &&
218 duration->events == 0) ||
220 duration->no_events.rounds == 0) ||
222 duration->no_events.ns == 0)),
223 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_DURATION,
224 "Bad option: opt.duration is zero(0).");
225 }
226
227 return dispatch_duration(duration, opt, results);
228}
229
231 const em_dispatch_opt_t *opt,
232 em_dispatch_results_t *results /*out*/)
233{
234 RETURN_ERROR_IF(ns == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_NS,
235 "Bad argument: ns=0");
236
237 if (!opt) {
238 opt = &dispatch_opt_default;
239 } else {
241 EM_ERR_NOT_INITIALIZED, EM_ESCOPE_DISPATCH_NS,
242 "Not initialized: em_dispatch_opt_init(opt) not called");
243 }
244
245 if (EM_CHECK_LEVEL > 0) {
247 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_NS,
248 "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
250 }
251
252 const em_dispatch_duration_t duration = {
254 .ns = ns
255 };
256
257 return dispatch_duration(&duration, opt, results);
258}
259
261 const em_dispatch_opt_t *opt,
262 em_dispatch_results_t *results /*out*/)
263{
264 RETURN_ERROR_IF(events == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_EVENTS,
265 "Bad argument: events=0");
266
267 if (!opt) {
268 opt = &dispatch_opt_default;
269 } else {
271 EM_ERR_NOT_INITIALIZED, EM_ESCOPE_DISPATCH_EVENTS,
272 "Not initialized: em_dispatch_opt_init(opt) not called");
273 }
274
275 if (EM_CHECK_LEVEL > 0) {
277 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_EVENTS,
278 "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
280 }
281
282 const em_dispatch_duration_t duration = {
284 .events = events
285 };
286
287 return dispatch_duration(&duration, opt, results);
288}
289
291 const em_dispatch_opt_t *opt,
292 em_dispatch_results_t *results /*out*/)
293{
294 RETURN_ERROR_IF(rounds == 0, EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_ROUNDS,
295 "Bad argument: rounds=0");
296
297 if (!opt) {
298 opt = &dispatch_opt_default;
299 } else {
301 EM_ERR_NOT_INITIALIZED, EM_ESCOPE_DISPATCH_ROUNDS,
302 "Not initialized: em_dispatch_opt_init(opt) not called");
303 }
304
305 if (EM_CHECK_LEVEL > 0) {
307 EM_ERR_BAD_ARG, EM_ESCOPE_DISPATCH_ROUNDS,
308 "Bad option: 0 < opt.burst_size (%" PRIu64 ") <= %u (max)",
310 }
311
312 const em_dispatch_duration_t duration = {
314 .rounds = rounds
315 };
316
317 return dispatch_duration(&duration, opt, results);
318}
319
322{
323 hook_fn_t hook_fn;
324 em_status_t stat;
325
326 RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
327 EM_ESCOPE_DISPATCH_REGISTER_ENTER_CB,
328 "EM dispatch callbacks disabled");
329
330 hook_fn.disp_enter = func;
331 stat = hook_register(DISPATCH_CALLBACK_ENTER, hook_fn);
332 RETURN_ERROR_IF(stat != EM_OK, stat,
333 EM_ESCOPE_DISPATCH_REGISTER_ENTER_CB,
334 "Dispatch callback register failed");
335
336 return EM_OK;
337}
338
341{
342 hook_fn_t hook_fn;
343 em_status_t stat;
344
345 RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
346 EM_ESCOPE_DISPATCH_UNREGISTER_ENTER_CB,
347 "EM dispatch callbacks disabled");
348
349 hook_fn.disp_enter = func;
350 stat = hook_unregister(DISPATCH_CALLBACK_ENTER, hook_fn);
351 RETURN_ERROR_IF(stat != EM_OK, stat,
352 EM_ESCOPE_DISPATCH_UNREGISTER_ENTER_CB,
353 "Dispatch callback unregister failed");
354
355 return EM_OK;
356}
357
360{
361 hook_fn_t hook_fn;
362 em_status_t stat;
363
364 RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
365 EM_ESCOPE_DISPATCH_REGISTER_EXIT_CB,
366 "EM dispatch callbacks disabled");
367
368 hook_fn.disp_exit = func;
369 stat = hook_register(DISPATCH_CALLBACK_EXIT, hook_fn);
370 RETURN_ERROR_IF(stat != EM_OK, stat,
371 EM_ESCOPE_DISPATCH_REGISTER_EXIT_CB,
372 "Dispatch callback register failed");
373 return EM_OK;
374}
375
378{
379 hook_fn_t hook_fn;
380 em_status_t stat;
381
382 RETURN_ERROR_IF(!EM_DISPATCH_CALLBACKS_ENABLE, EM_ERR_NOT_IMPLEMENTED,
383 EM_ESCOPE_DISPATCH_UNREGISTER_EXIT_CB,
384 "EM dispatch callbacks disabled");
385
386 hook_fn.disp_exit = func;
387 stat = hook_unregister(DISPATCH_CALLBACK_EXIT, hook_fn);
388 RETURN_ERROR_IF(stat != EM_OK, stat,
389 EM_ESCOPE_DISPATCH_UNREGISTER_EXIT_CB,
390 "Dispatch callback unregister failed");
391 return EM_OK;
392}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
#define EM_CHECK_INIT_CALLED
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_SCHED_MULTI_MAX_BURST
#define EM_CHECK_LEVEL
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.
em_status_t em_dispatch_unregister_exit_cb(em_dispatch_exit_func_t func)
em_status_t em_dispatch_register_enter_cb(em_dispatch_enter_func_t func)
uint64_t em_dispatch(uint64_t rounds)
void em_dispatch_opt_init(em_dispatch_opt_t *opt)
Initialize the EM dispatch options.
em_status_t em_dispatch_register_exit_cb(em_dispatch_exit_func_t func)
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).
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.
em_status_t em_dispatch_unregister_enter_cb(em_dispatch_enter_func_t func)
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.
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)
void(* em_dispatch_exit_func_t)(em_eo_t eo)
em_dispatch_duration_select_t
EM dispatch duration selection flags.
@ EM_DISPATCH_DURATION_ROUNDS
@ EM_DISPATCH_DURATION_NO_EVENTS_NS
@ EM_DISPATCH_DURATION_EVENTS
@ EM_DISPATCH_DURATION_NS
@ EM_DISPATCH_DURATION_NO_EVENTS_ROUNDS
#define EM_OK
uint32_t em_status_t
@ EM_ERR_BAD_ARG
@ EM_ERR_NOT_IMPLEMENTED
@ EM_ERR_NOT_SUPPORTED
@ EM_ERR_NOT_INITIALIZED
int(* em_input_poll_func_t)(void)
int(* em_output_drain_func_t)(void)
em_dispatch_duration_select_t select
bool is_em_core
Definition em_mem.h:254
bool is_sched_paused
Definition em_mem.h:252
em_output_drain_func_t output_drain_fn
Definition em_mem.h:247
uint64_t local_event_cnt
Definition em_mem.h:243
em_input_poll_func_t input_poll_fn
Definition em_mem.h:245
em_cfgfile_opts_t opt
Definition em_mem.h:99