EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
event_machine_eo.c
1/*
2 * Copyright (c) 2015-2025, 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#include <stdio.h>
42#include <string.h>
43
44#include <odp_api.h>
45
46#include <event_machine.h>
48
49#include "em_eo.h"
50#include "em_eo_types.h"
51#include "em_error.h"
52#include "em_event.h"
53#include "em_event_inline.h"
54#include "em_internal_event.h"
56#include "em_mem.h"
57#include "em_queue.h"
58#include "em_queue_inline.h"
59#include "em_queue_types.h"
60#include "misc/list.h"
61#include "misc/objpool.h"
62
63/* Per core (thread) state of em_eo_next() */
64static ENV_LOCAL unsigned int _eo_tbl_iter_idx;
65/* Per core (thread) state of em_eo_queue_next() */
66static ENV_LOCAL unsigned int _eo_q_iter_idx;
67static ENV_LOCAL em_eo_t _eo_q_iter_eo;
68
69static em_status_t check_eo_create_params(const em_eo_param_t *param,
70 em_escope_t escope)
71{
74 "Invalid param ptr: Use em_eo_param_init() before create");
75
76 RETURN_ERROR_IF(!param->start || !param->stop || !param->receive,
77 EM_ERR_BAD_POINTER, escope,
78 "Mandatory EO function pointer(s) NULL!");
79
83 EM_ERR_BAD_STATE, escope,
84 "Invalid local_start_mode:%d", param->local_start_mode);
85
89 EM_ERR_BAD_STATE, escope,
90 "Invalid local_stop_mode:%d", param->local_stop_mode);
91
92 return EM_OK;
93}
94
95static em_eo_t eo_create(const char *name, const em_eo_param_t *param,
96 em_escope_t escope)
97{
98 em_eo_t eo;
99 eo_elem_t *eo_elem;
100 em_status_t status;
101
102 status = check_eo_create_params(param, escope);
103 if (unlikely(status != EM_OK)) {
104 /* Error reported by check_eo_create_params(), just return */
105 return EM_EO_UNDEF;
106 }
107
108 eo = eo_alloc();
109 if (unlikely(eo == EM_EO_UNDEF)) {
110 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, escope, "EO alloc failed!");
111 return EM_EO_UNDEF;
112 }
113
114 eo_elem = eo_elem_get(eo);
115 if (unlikely(!eo_elem)) {
116 /* Fatal since eo_alloc() returned 'ok', should never happen */
118 "Invalid EO:%" PRI_EO "", eo);
119 return EM_EO_UNDEF;
120 }
121
122 odp_ticketlock_lock(&eo_elem->lock);
123
124 /* Store the name */
125 if (name != NULL) {
126 strncpy(eo_elem->name, name, sizeof(eo_elem->name) - 1);
127 eo_elem->name[sizeof(eo_elem->name) - 1] = '\0';
128 } else {
129 eo_elem->name[0] = '\0';
130 }
131
132 /* EO's queue list init */
133 list_init(&eo_elem->queue_list);
134 /* EO start: event buffering init */
135 eo_elem->stash = ODP_STASH_INVALID;
136
137 eo_elem->state = EM_EO_STATE_CREATED;
138 eo_elem->start_func = param->start;
139 eo_elem->start_local_func = param->local_start;
140 eo_elem->start_local_mode = param->local_start_mode;
141
142 eo_elem->stop_func = param->stop;
143 eo_elem->stop_local_func = param->local_stop;
144 eo_elem->stop_local_mode = param->local_stop_mode;
145
146 eo_elem->use_multi_rcv = EM_FALSE;
147 eo_elem->max_events = 1;
148 eo_elem->receive_func = param->receive;
149 eo_elem->receive_multi_func = NULL;
150
151 eo_elem->error_handler_func = NULL;
152 eo_elem->eo_ctx = (void *)(uintptr_t)param->eo_ctx;
153 eo_elem->eo = eo;
154 odp_atomic_init_u32(&eo_elem->num_queues, 0);
155
156 odp_ticketlock_unlock(&eo_elem->lock);
157
158 return eo;
159}
160
162{
163 if (unlikely(!param)) {
165 EM_ESCOPE_EO_PARAM_INIT,
166 "Param pointer NULL!");
167 return;
168 }
169 memset(param, 0, sizeof(em_eo_param_t));
171}
172
173em_eo_t em_eo_create(const char *name,
174 em_start_func_t start, em_start_local_func_t local_start,
175 em_stop_func_t stop, em_stop_local_func_t local_stop,
176 em_receive_func_t receive, const void *eo_ctx)
177{
178 em_eo_param_t param;
179
180 if (unlikely(start == NULL || stop == NULL || receive == NULL)) {
181 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_CREATE,
182 "Mandatory EO function pointer(s) NULL!");
183 return EM_EO_UNDEF;
184 }
185
186 em_eo_param_init(&param);
187 param.start = start;
188 param.local_start = local_start;
189 param.stop = stop;
190 param.local_stop = local_stop;
191 param.receive = receive;
192 param.eo_ctx = eo_ctx;
193
194 return eo_create(name, &param, EM_ESCOPE_EO_CREATE);
195}
196
197em_eo_t em_eo_create_param(const char *name, const em_eo_param_t *param)
198{
199 return eo_create(name, param, EM_ESCOPE_EO_CREATE_PARAM);
200}
201
203{
204 if (unlikely(!param)) {
206 EM_ESCOPE_EO_MULTIRCV_PARAM_INIT,
207 "Param pointer NULL!");
208 return;
209 }
210 memset(param, 0, sizeof(em_eo_multircv_param_t));
213}
214
215em_eo_t
216em_eo_create_multircv(const char *name, const em_eo_multircv_param_t *param)
217{
218 em_eo_t eo;
219 eo_elem_t *eo_elem;
220 int max_events;
221
222 if (unlikely(!param ||
224 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_EO_CREATE_MULTIRCV,
225 "Invalid param ptr:\n"
226 "Use em_eo_multircv_param_init() before create");
227 return EM_EO_UNDEF;
228 }
229
230 if (unlikely(!param->start || !param->stop || !param->receive_multi)) {
231 INTERNAL_ERROR(EM_ERR_BAD_POINTER, EM_ESCOPE_EO_CREATE_MULTIRCV,
232 "Mandatory EO function pointer(s) NULL!");
233 return EM_EO_UNDEF;
234 }
235
236 if (unlikely(param->max_events < 0)) {
237 INTERNAL_ERROR(EM_ERR_TOO_SMALL, EM_ESCOPE_EO_CREATE_MULTIRCV,
238 "Max number of events too small:%d",
239 param->max_events);
240 return EM_EO_UNDEF;
241 }
242 max_events = param->max_events;
243 if (max_events == 0) /* user requests default value */
244 max_events = EM_EO_MULTIRCV_MAX_EVENTS;
245
246 eo = eo_alloc();
247 if (unlikely(eo == EM_EO_UNDEF)) {
248 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_EO_CREATE_MULTIRCV,
249 "EO alloc failed!");
250 return EM_EO_UNDEF;
251 }
252
253 eo_elem = eo_elem_get(eo);
254 if (unlikely(eo_elem == NULL)) {
255 /* Fatal since eo_alloc() returned 'ok', should never happen */
257 EM_ESCOPE_EO_CREATE_MULTIRCV,
258 "Invalid EO:%" PRI_EO "", eo);
259 return EM_EO_UNDEF;
260 }
261
262 odp_ticketlock_lock(&eo_elem->lock);
263
264 /* Store the name */
265 if (name) {
266 strncpy(eo_elem->name, name, sizeof(eo_elem->name) - 1);
267 eo_elem->name[sizeof(eo_elem->name) - 1] = '\0';
268 } else {
269 eo_elem->name[0] = '\0';
270 }
271
272 /* EO's queue list init */
273 list_init(&eo_elem->queue_list);
274 /* EO start: event buffering init */
275 eo_elem->stash = ODP_STASH_INVALID;
276
277 eo_elem->state = EM_EO_STATE_CREATED;
278 eo_elem->start_func = param->start;
279 eo_elem->start_local_func = param->local_start;
280 eo_elem->start_local_mode = param->local_start_mode;
281
282 eo_elem->stop_func = param->stop;
283 eo_elem->stop_local_func = param->local_stop;
284 eo_elem->stop_local_mode = param->local_stop_mode;
285
286 eo_elem->use_multi_rcv = EM_TRUE;
287 eo_elem->max_events = max_events;
288 eo_elem->receive_func = NULL;
289 eo_elem->receive_multi_func = param->receive_multi;
290
291 eo_elem->error_handler_func = NULL;
292 eo_elem->eo_ctx = (void *)(uintptr_t)param->eo_ctx;
293 eo_elem->eo = eo;
294 odp_atomic_init_u32(&eo_elem->num_queues, 0);
295
296 odp_ticketlock_unlock(&eo_elem->lock);
297
298 return eo;
299}
300
302{
303 eo_elem_t *const eo_elem = eo_elem_get(eo);
304 em_status_t status;
305
306 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG, EM_ESCOPE_EO_DELETE,
307 "Invalid EO:%" PRI_EO "!", eo);
308
309 RETURN_ERROR_IF(!eo_allocated(eo_elem),
310 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_DELETE,
311 "EO not allocated:%" PRI_EO "", eo);
312
314 eo_elem->state != EM_EO_STATE_ERROR,
315 EM_ERR_BAD_STATE, EM_ESCOPE_EO_DELETE,
316 "EO invalid state, cannot delete:%d", eo_elem->state);
317
318 status = eo_delete_queue_all(eo_elem);
319
320 RETURN_ERROR_IF(status != EM_OK, status, EM_ESCOPE_EO_DELETE,
321 "EO delete: delete queues failed!");
322
323 /* Free EO back into the eo-pool and mark state=EO_STATE_UNDEF */
324 status = eo_free(eo);
325 RETURN_ERROR_IF(status != EM_OK, status, EM_ESCOPE_EO_DELETE,
326 "EO delete failed!");
327
328 return status;
329}
330
331size_t em_eo_name(em_eo_t eo, char *name, size_t maxlen)
332{
333 const eo_elem_t *eo_elem = eo_elem_get(eo);
334
335 if (name == NULL || maxlen == 0) {
336 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_NAME,
337 "Invalid ptr or maxlen (name=0x%" PRIx64 ", maxlen=%zu)",
338 name, maxlen);
339 return 0;
340 }
341
342 name[0] = '\0';
343
344 if (unlikely(eo_elem == NULL)) {
345 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_NAME,
346 "Invalid EO%" PRI_EO "", eo);
347 return 0;
348 }
349
350 if (unlikely(!eo_allocated(eo_elem))) {
351 INTERNAL_ERROR(EM_ERR_NOT_CREATED, EM_ESCOPE_EO_NAME,
352 "EO not created:%" PRI_EO "", eo);
353 return 0;
354 }
355
356 return eo_name(eo_elem, name, maxlen);
357}
358
359em_eo_t em_eo_find(const char *name)
360{
361 if (name && *name) {
362 for (int i = 0; i < EM_MAX_EOS; i++) {
363 const eo_elem_t *eo_elem = &em_shm->eo_tbl.eo_elem[i];
364
365 if (eo_elem->state != EM_EO_STATE_UNDEF &&
366 !strncmp(name, eo_elem->name, EM_EO_NAME_LEN - 1))
367 return eo_elem->eo;
368 }
369 }
370 return EM_EO_UNDEF;
371}
372
373/**
374 * @brief Helper for em_eo_add_queue/_sync()
375 */
376static em_status_t
377eo_add_queue_escope(em_eo_t eo, em_queue_t queue,
378 int num_notif, const em_notif_t notif_tbl[],
379 em_escope_t escope)
380{ eo_elem_t *const eo_elem = eo_elem_get(eo);
381 queue_elem_t *const q_elem = queue_elem_get(queue);
382 em_queue_type_t q_type;
383 em_status_t err;
384 int valid;
385
386 RETURN_ERROR_IF(eo_elem == NULL || q_elem == NULL,
387 EM_ERR_BAD_ARG, escope,
388 "Invalid args: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
389 eo, queue);
390 RETURN_ERROR_IF(!eo_allocated(eo_elem) || !queue_allocated(q_elem),
391 EM_ERR_NOT_CREATED, escope,
392 "Not created: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
393 eo, queue);
394
395 q_type = em_queue_type(queue);
396 valid = q_type == EM_QUEUE_TYPE_ATOMIC ||
397 q_type == EM_QUEUE_TYPE_PARALLEL ||
398 q_type == EM_QUEUE_TYPE_ORDERED ||
399 q_type == EM_QUEUE_TYPE_LOCAL;
400 RETURN_ERROR_IF(!valid, EM_ERR_BAD_TYPE, escope,
401 "Invalid queue type: %" PRI_QTYPE "", q_type);
402
403 if (num_notif > 0) {
404 err = check_notif_tbl(num_notif, notif_tbl);
405 RETURN_ERROR_IF(err != EM_OK, err, escope,
406 "Invalid notif cfg given!");
407 }
408
409 err = eo_add_queue(eo_elem, q_elem);
410 RETURN_ERROR_IF(err != EM_OK, err, escope,
411 "eo_add_queue(Q:%" PRI_QUEUE ") fails", queue);
412
413 if (eo_elem->state == EM_EO_STATE_RUNNING) {
414 err = queue_enable(q_elem); /* otherwise enabled in eo-start */
415 RETURN_ERROR_IF(err != EM_OK, err, escope,
416 "queue_enable(Q:%" PRI_QUEUE ") fails", queue);
417 }
418
419 if (num_notif > 0) {
420 /* Send notifications if requested */
421 err = send_notifs(num_notif, notif_tbl);
422 RETURN_ERROR_IF(err != EM_OK, err, escope,
423 "EO:%" PRI_EO " send notif fails", eo);
424 }
425
426 return EM_OK;
427}
428
430em_eo_add_queue(em_eo_t eo, em_queue_t queue,
431 int num_notif, const em_notif_t notif_tbl[])
432{
433 return eo_add_queue_escope(eo, queue, num_notif, notif_tbl,
434 EM_ESCOPE_EO_ADD_QUEUE);
435}
436
438em_eo_add_queue_sync(em_eo_t eo, em_queue_t queue)
439{
440 /* No sync blocking needed when adding a queue to an EO */
441 return eo_add_queue_escope(eo, queue, 0, NULL,
442 EM_ESCOPE_EO_ADD_QUEUE_SYNC);
443}
444
446em_eo_remove_queue(em_eo_t eo, em_queue_t queue,
447 int num_notif, const em_notif_t notif_tbl[])
448{
449 eo_elem_t *const eo_elem = eo_elem_get(eo);
450 queue_elem_t *const q_elem = queue_elem_get(queue);
451 em_queue_type_t q_type;
452 em_status_t ret;
453 int valid;
454
455 RETURN_ERROR_IF(eo_elem == NULL || q_elem == NULL,
456 EM_ERR_BAD_ARG, EM_ESCOPE_EO_REMOVE_QUEUE,
457 "Invalid args: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
458 eo, queue);
459 RETURN_ERROR_IF(!eo_allocated(eo_elem) || !queue_allocated(q_elem),
460 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_REMOVE_QUEUE,
461 "Not created: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
462 eo, queue);
463
464 q_type = em_queue_type(queue);
465 valid = q_type == EM_QUEUE_TYPE_ATOMIC ||
466 q_type == EM_QUEUE_TYPE_PARALLEL ||
467 q_type == EM_QUEUE_TYPE_ORDERED ||
468 q_type == EM_QUEUE_TYPE_LOCAL;
469 RETURN_ERROR_IF(!valid, EM_ERR_BAD_TYPE, EM_ESCOPE_EO_REMOVE_QUEUE,
470 "Invalid queue type: %" PRI_QTYPE "", q_type);
471
472 ret = check_notif_tbl(num_notif, notif_tbl);
473 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE,
474 "Invalid notif cfg given!");
475 RETURN_ERROR_IF(eo_elem != q_elem->eo_elem,
476 EM_ERR_BAD_POINTER, EM_ESCOPE_EO_REMOVE_QUEUE,
477 "Can't remove Q:%" PRI_QUEUE ", not added to this EO",
478 queue);
479
480 /*
481 * Disable the queue if not already done, dispatcher will drop any
482 * further events. Need to handle events from the queue being processed
483 * in an EO receive function properly still.
484 */
485 if (q_elem->state == EM_QUEUE_STATE_READY) {
486 ret = queue_disable(q_elem);
487
488 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE,
489 "queue_disable(Q:%" PRI_QUEUE ") fails",
490 queue);
491 }
492
493 /*
494 * Request each core to run locally the eo_remove_queue_local() function
495 * and when all are done call eo_remove_queue_done_callback().
496 * The callback will finally remove the queue from the EO when it's
497 * known that no core is anymore processing events from that EO/queue.
498 */
499 int reqs_sent = eo_remove_queue_local_req(eo_elem, q_elem, num_notif, notif_tbl);
500
501 RETURN_ERROR_IF(reqs_sent < 0, EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_REMOVE_QUEUE,
502 "EO:%" PRI_EO " eo_remove_queue_local_req():%d", eo, reqs_sent);
503
504 if (reqs_sent == 0) {
505 /*
506 * No cores to process the request, e.g. all EM-cores (worker or
507 * control) have been terminated and tear down is done by an
508 * EM external thread/process. Remove the queue from the EO.
509 */
510 ret = eo_rem_queue(eo_elem, q_elem);
511 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE_DONE_CB,
512 "EO:%" PRI_EO " remove Q:%" PRI_QUEUE " failed",
513 eo, queue);
514 }
515
516 return EM_OK;
517}
518
520em_eo_remove_queue_sync(em_eo_t eo, em_queue_t queue)
521{
522 em_locm_t *const locm = &em_locm;
523 eo_elem_t *const eo_elem = eo_elem_get(eo);
524 queue_elem_t *const q_elem = queue_elem_get(queue);
525 em_queue_type_t q_type;
526 em_status_t ret;
527 int valid;
528
529 RETURN_ERROR_IF(eo_elem == NULL || q_elem == NULL,
530 EM_ERR_BAD_ARG, EM_ESCOPE_EO_REMOVE_QUEUE_SYNC,
531 "Invalid args: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
532 eo, queue);
533 RETURN_ERROR_IF(!eo_allocated(eo_elem) || !queue_allocated(q_elem),
534 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_REMOVE_QUEUE_SYNC,
535 "Not created: EO:%" PRI_EO " Q:%" PRI_QUEUE "",
536 eo, queue);
537
538 q_type = em_queue_type(queue);
539 valid = q_type == EM_QUEUE_TYPE_ATOMIC ||
540 q_type == EM_QUEUE_TYPE_PARALLEL ||
541 q_type == EM_QUEUE_TYPE_ORDERED ||
542 q_type == EM_QUEUE_TYPE_LOCAL;
544 EM_ESCOPE_EO_REMOVE_QUEUE_SYNC,
545 "Invalid queue type: %" PRI_QTYPE "", q_type);
546
547 RETURN_ERROR_IF(eo_elem != q_elem->eo_elem,
548 EM_ERR_BAD_POINTER, EM_ESCOPE_EO_REMOVE_QUEUE_SYNC,
549 "Can't remove Q:%" PRI_QUEUE ", not added to this EO",
550 queue);
551
552 /* Mark that a sync-API call is in progress */
553 locm->sync_api.in_progress = true;
554
555 /*
556 * Disable the queue if not already done, dispatcher will drop any
557 * further events. Need to handle events from the queue being processed
558 * in an EO receive function properly still.
559 */
560 if (q_elem->state == EM_QUEUE_STATE_READY) {
561 ret = queue_disable(q_elem);
562
563 if (unlikely(ret != EM_OK)) {
564 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_REMOVE_QUEUE_SYNC,
565 "queue_disable(Q:%" PRI_QUEUE ") failed", queue);
566 goto eo_remove_queue_sync_error;
567 }
568 }
569
570 /*
571 * Request each core to run locally the eo_remove_queue_sync_local() function
572 * and when all are done call eo_remove_queue_sync_done_callback().
573 * The callback will finally remove the queue from the EO when it's
574 * known that no core is anymore processing events from that EO/queue.
575 */
576 int reqs_sent = eo_remove_queue_sync_local_req(eo_elem, q_elem);
577
578 if (unlikely(reqs_sent < 0)) {
579 ret = INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_REMOVE_QUEUE,
580 "EO:%" PRI_EO " eo_remove_queue_sync_local_req():%d",
581 eo, reqs_sent);
582 goto eo_remove_queue_sync_error;
583 }
584
585 if (likely(reqs_sent > 0)) {
586 /*
587 * Poll the core-local unscheduled control-queue for events.
588 * These events request the core to do a core-local operation (or nop).
589 * Poll and handle events until 'locm->sync_api.in_progress == false'
590 * indicating that this sync-API is 'done' on all concerned cores.
591 */
592 while (locm->sync_api.in_progress)
594 } else if (reqs_sent == 0) {
595 /*
596 * No cores to process the request, e.g. all EM-cores (worker or
597 * control) have been terminated and tear down is done by an
598 * EM external thread/process. Remove the queue from the EO.
599 */
600 ret = eo_rem_queue(eo_elem, q_elem);
601
602 if (unlikely(ret != EM_OK)) {
603 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_REMOVE_QUEUE,
604 "EO:%" PRI_EO " Q:%" PRI_QUEUE " eo_rem_queue() fails",
605 eo, queue);
606 goto eo_remove_queue_sync_error;
607 }
608 }
609
610 return EM_OK;
611
612eo_remove_queue_sync_error:
613 locm->sync_api.in_progress = false;
614
615 return ret;
616}
617
619em_eo_remove_queue_all(em_eo_t eo, int delete_queues,
620 int num_notif, const em_notif_t notif_tbl[])
621{
622 eo_elem_t *const eo_elem = eo_elem_get(eo);
623 em_status_t ret;
624
625 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG,
626 EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
627 "Invalid EO:%" PRI_EO "", eo);
628 RETURN_ERROR_IF(!eo_allocated(eo_elem), EM_ERR_NOT_CREATED,
629 EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
630 "EO:%" PRI_EO " not created", eo);
631 ret = check_notif_tbl(num_notif, notif_tbl);
632 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
633 "Invalid notif cfg given!");
634
635 ret = queue_disable_all(eo_elem);
636 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
637 "queue_disable_all() failed!");
638
639 /*
640 * Request each core to run locally the eo_remove_queue_all_local() function
641 * and when all are done call eo_remove_queue_all_done_callback().
642 * The callback will finally remove the queue from the EO when it's
643 * known that no core is anymore processing events from that EO/queue.
644 */
645 int reqs_sent = eo_remove_queue_all_local_req(eo_elem, delete_queues,
646 num_notif, notif_tbl);
648 EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
649 "EO:%" PRI_EO " eo_remove_queue_all_local_req():%d",
650 eo, reqs_sent);
651
652 if (reqs_sent == 0) {
653 /*
654 * No cores to process the request, e.g. all EM-cores (worker or
655 * control) have been terminated and tear down is done by an
656 * EM external thread/process.
657 * Remove or delete all the EO's queues.
658 */
659 if (delete_queues)
660 ret = eo_delete_queue_all(eo_elem);
661 else
662 ret = eo_rem_queue_all(eo_elem);
663
664 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_REMOVE_QUEUE_ALL,
665 "EO:%" PRI_EO " remove all queues failed", eo);
666 }
667
668 return EM_OK;
669}
670
672em_eo_remove_queue_all_sync(em_eo_t eo, int delete_queues)
673{
674 em_locm_t *const locm = &em_locm;
675 eo_elem_t *const eo_elem = eo_elem_get(eo);
676 em_status_t ret;
677
678 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG,
679 EM_ESCOPE_EO_REMOVE_QUEUE_ALL_SYNC,
680 "Invalid EO:%" PRI_EO "", eo);
681 RETURN_ERROR_IF(!eo_allocated(eo_elem), EM_ERR_NOT_CREATED,
682 EM_ESCOPE_EO_REMOVE_QUEUE_ALL_SYNC,
683 "EO:%" PRI_EO " not created", eo);
684
685 /* Mark that a sync-API call is in progress */
686 locm->sync_api.in_progress = true;
687
688 ret = queue_disable_all(eo_elem);
689 if (unlikely(ret != EM_OK)) {
690 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_REMOVE_QUEUE_ALL_SYNC,
691 "queue_disable_all() failed!");
692 goto eo_remove_queue_all_sync_error;
693 }
694
695 /*
696 * Request each core to run locally the eo_remove_queue_all_sync_local() function
697 * and when all are done call eo_remove_queue_all_sync_done_callback().
698 * The callback will finally remove the queue from the EO when it's
699 * known that no core is anymore processing events from that EO/queue.
700 */
701 int reqs_sent = eo_remove_queue_all_sync_local_req(eo_elem, delete_queues);
702
703 if (unlikely(reqs_sent < 0)) {
704 ret = INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_REMOVE_QUEUE_ALL_SYNC,
705 "EO:%" PRI_EO " eo_remove_queue_all_sync_local_req():%d",
706 eo, reqs_sent);
707 goto eo_remove_queue_all_sync_error;
708 }
709
710 if (likely(reqs_sent > 0)) {
711 /*
712 * Poll the core-local unscheduled control-queue for events.
713 * These events request the core to do a core-local operation (or nop).
714 * Poll and handle events until 'locm->sync_api.in_progress == false'
715 * indicating that this sync-API is 'done' on all concerned cores.
716 */
717 while (locm->sync_api.in_progress)
719 } else if (reqs_sent == 0) {
720 /*
721 * No cores to process the request, e.g. all EM-cores (worker or
722 * control) have been terminated and tear down is done by an
723 * EM external thread/process.
724 * Remove or delete all the EO's queues.
725 */
726 if (delete_queues)
727 ret = eo_delete_queue_all(eo_elem);
728 else
729 ret = eo_rem_queue_all(eo_elem);
730
731 if (unlikely(ret != EM_OK)) {
732 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_REMOVE_QUEUE_ALL_SYNC_DONE_CB,
733 "EO:%" PRI_EO " removing all queues failed", eo);
734 goto eo_remove_queue_all_sync_error;
735 }
736 }
737
738 return EM_OK;
739
740eo_remove_queue_all_sync_error:
741 locm->sync_api.in_progress = false;
742
743 return ret;
744}
745
748{
749 eo_elem_t *const eo_elem = eo_elem_get(eo);
750
751 RETURN_ERROR_IF(eo_elem == NULL || handler == NULL,
752 EM_ERR_BAD_ARG, EM_ESCOPE_EO_REGISTER_ERROR_HANDLER,
753 "Invalid args: EO:%" PRI_EO " handler:%p", eo, handler);
754 RETURN_ERROR_IF(!eo_allocated(eo_elem),
755 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_REGISTER_ERROR_HANDLER,
756 "EO:%" PRI_EO " not created", eo);
757
758 odp_ticketlock_lock(&eo_elem->lock);
759 eo_elem->error_handler_func = handler;
760 odp_ticketlock_unlock(&eo_elem->lock);
761
762 return EM_OK;
763}
764
767{
768 eo_elem_t *const eo_elem = eo_elem_get(eo);
769
770 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG,
771 EM_ESCOPE_EO_UNREGISTER_ERROR_HANDLER,
772 "Invalid EO id %" PRI_EO "", eo);
773 RETURN_ERROR_IF(!eo_allocated(eo_elem), EM_ERR_NOT_CREATED,
774 EM_ESCOPE_EO_UNREGISTER_ERROR_HANDLER,
775 "EO not created:%" PRI_EO "", eo);
776
777 odp_ticketlock_lock(&eo_elem->lock);
778 eo_elem->error_handler_func = NULL;
779 odp_ticketlock_unlock(&eo_elem->lock);
780
781 return EM_OK;
782}
783
785em_eo_start(em_eo_t eo, em_status_t *result, const em_eo_conf_t *conf,
786 int num_notif, const em_notif_t notif_tbl[])
787{
788 em_locm_t *const locm = &em_locm;
789 eo_elem_t *const eo_elem = eo_elem_get(eo);
790 queue_elem_t *const save_q_elem = locm->current.q_elem;
791 queue_elem_t tmp_q_elem;
792 em_status_t ret;
793
794 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG, EM_ESCOPE_EO_START,
795 "Invalid EO id %" PRI_EO "", eo);
796 RETURN_ERROR_IF(!eo_allocated(eo_elem),
797 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_START,
798 "EO not created:%" PRI_EO "", eo);
800 EM_ERR_BAD_STATE, EM_ESCOPE_EO_START,
801 "EO invalid state, cannot start:%d", eo_elem->state);
802 ret = check_notif_tbl(num_notif, notif_tbl);
803 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_START,
804 "Invalid notif cfg given!");
805
806 eo_elem->state = EM_EO_STATE_STARTING;
807
808 /* Create a stash to buffer events sent during EO-start */
809 eo_elem->stash = eo_start_stash_create();
810 if (unlikely(eo_elem->stash == ODP_STASH_INVALID)) {
811 ret = INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_EO_START,
812 "EO:%" PRI_EO " start stash creation fails", eo);
813 goto eo_start_error;
814 }
815 /* This core is in the EO start function: buffer all sent events */
816 locm->start_eo_elem = eo_elem;
817 /*
818 * Use a tmp q_elem as the 'current q_elem' to enable calling
819 * em_eo_current() from the EO start functions.
820 * Before returning, restore the original 'current q_elem' from
821 * 'save_q_elem'.
822 */
823 memset(&tmp_q_elem, 0, sizeof(tmp_q_elem));
824 tmp_q_elem.eo = (uint16_t)(uintptr_t)eo;
825
826 locm->current.q_elem = &tmp_q_elem;
827 /* Call the global EO start function */
828 ret = eo_elem->start_func(eo_elem->eo_ctx, eo, conf);
829 /* Restore the original 'current q_elem' */
830 locm->current.q_elem = save_q_elem;
831 locm->start_eo_elem = NULL;
832
833 /* Store the return value of the actual EO global start function */
834 if (result != NULL)
835 *result = ret;
836
837 if (unlikely(ret != EM_OK)) {
838 ret = INTERNAL_ERROR(EM_ERR, EM_ESCOPE_EO_START,
839 "EO:%" PRI_EO " start func failed:%" PRIxSTAT "",
840 eo, ret);
841 /* user error handler might change error from own eo-start */
842 if (ret != EM_OK)
843 goto eo_start_error;
844 }
845
846 if (eo_elem->start_local_func != NULL) {
847 /*
848 * Notifications sent when the local start functions
849 * have completed.
850 */
851 int reqs_sent = eo_start_local_req(eo_elem, num_notif, notif_tbl);
852
853 if (unlikely(reqs_sent < 0)) {
855 INTERNAL_ERROR(ret, EM_ESCOPE_EO_START,
856 "EO:%" PRI_EO " eo_start_local_req():%d",
857 eo, reqs_sent);
858 /* Can't allow user err handler to change error here */
859 goto eo_start_error;
860 }
861
862 /*
863 * Note: Return here, queues will be enabled after the local
864 * start funcs complete.
865 * EO state changed to 'EM_EO_STATE_RUNNING' after successful
866 * completion of EO local starts on all cores.
867 */
868 if (reqs_sent > 0)
869 return EM_OK;
870 /*
871 * If req_sent == 0, then no EM-cores (worker or control) were
872 * yet running, e.g. an EM external thread started the EO.
873 */
874 }
875
876 /*
877 * Enable all the EO's queues.
878 * Note: if local start functions are given then enable can be done only
879 * after they have been run on each core.
880 */
881 ret = queue_enable_all(eo_elem);
882 if (unlikely(ret != EM_OK)) {
883 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_START,
884 "EO:%" PRI_EO " queue_enable_all() failed", eo);
885 goto eo_start_error;
886 }
887
888 eo_elem->state = EM_EO_STATE_RUNNING;
889
890 /* Send events buffered during the EO-start/local-start functions */
891 eo_start_send_buffered_events(eo_elem);
892
893 if (num_notif > 0) {
894 /* Send notifications if requested */
895 ret = send_notifs(num_notif, notif_tbl);
896
897 if (unlikely(ret != EM_OK)) {
898 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_START,
899 "EO:%" PRI_EO " send notif fails", eo);
900 /* user error handler might change error */
901 if (ret != EM_OK)
902 goto eo_start_error;
903 }
904 }
905
906 return EM_OK;
907
908eo_start_error:
909 /* roll back state to allow EO delete */
910 eo_elem->state = EM_EO_STATE_ERROR;
911 return ret;
912}
913
915em_eo_start_sync(em_eo_t eo, em_status_t *result, const em_eo_conf_t *conf)
916{
917 em_locm_t *const locm = &em_locm;
918 eo_elem_t *const eo_elem = eo_elem_get(eo);
919 queue_elem_t *const save_q_elem = locm->current.q_elem;
920 queue_elem_t tmp_q_elem;
921 em_status_t ret;
922
923 RETURN_ERROR_IF(eo_elem == NULL, EM_ERR_BAD_ARG, EM_ESCOPE_EO_START_SYNC,
924 "Invalid EO id %" PRI_EO "", eo);
925 RETURN_ERROR_IF(!eo_allocated(eo_elem),
926 EM_ERR_NOT_CREATED, EM_ESCOPE_EO_START_SYNC,
927 "EO not created:%" PRI_EO "", eo);
929 EM_ERR_BAD_STATE, EM_ESCOPE_EO_START_SYNC,
930 "EO invalid state, cannot start:%d", eo_elem->state);
931
932 eo_elem->state = EM_EO_STATE_STARTING;
933
934 /* Create a stash to buffer events sent during EO-start */
935 eo_elem->stash = eo_start_stash_create();
936 if (unlikely(eo_elem->stash == ODP_STASH_INVALID)) {
937 ret = INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_EO_START_SYNC,
938 "EO:%" PRI_EO " start stash creation fails", eo);
939 /* roll back state to allow EO delete */
940 eo_elem->state = EM_EO_STATE_ERROR;
941 return ret;
942 }
943 /* This core is in the EO start function: buffer all sent events */
944 locm->start_eo_elem = eo_elem;
945 /*
946 * Use a tmp q_elem as the 'current q_elem' to enable calling
947 * em_eo_current() from the EO start functions.
948 * Before returning, restore the original 'current q_elem' from
949 * 'save_q_elem'.
950 */
951 memset(&tmp_q_elem, 0, sizeof(tmp_q_elem));
952 tmp_q_elem.eo = (uint16_t)(uintptr_t)eo;
953 locm->current.q_elem = &tmp_q_elem;
954 /* Call the global EO start function */
955 ret = eo_elem->start_func(eo_elem->eo_ctx, eo, conf);
956 /* Restore the original 'current q_elem' */
957 locm->current.q_elem = save_q_elem;
958 locm->start_eo_elem = NULL;
959
960 /* Store the return value of the actual EO global start function */
961 if (result != NULL)
962 *result = ret;
963
964 if (unlikely(ret != EM_OK)) {
965 ret = INTERNAL_ERROR(EM_ERR, EM_ESCOPE_EO_START_SYNC,
966 "EO:%" PRI_EO " start func failed:%" PRIxSTAT "",
967 eo, ret);
968 /* user error handler might change error from own eo-start */
969 if (ret != EM_OK) {
970 /* roll back state to allow EO delete */
971 eo_elem->state = EM_EO_STATE_ERROR;
972 return ret;
973 }
974 }
975
976 if (eo_elem->start_local_func) {
977 int reqs_sent = eo_start_sync_local_req(eo_elem);
978
979 if (unlikely(reqs_sent < 0)) {
980 ret = INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_START_SYNC,
981 "EO:%" PRI_EO " eo_start_sync_local_req():%d",
982 eo, reqs_sent);
983 /* Can't allow user err handler to change error here */
984 goto eo_start_sync_error;
985 }
986
987 if (reqs_sent > 0) {
988 /* Mark that a sync-API call is in progress */
989 locm->sync_api.in_progress = true;
990 /*
991 * Poll the core-local unscheduled control-queue for events.
992 * These events request the core to do a core-local operation (or nop).
993 * Poll and handle events until 'locm->sync_api.in_progress == false'
994 * indicating that this sync-API is 'done' on all concerned cores.
995 */
996 while (locm->sync_api.in_progress)
998
999 /* Send events buffered during the EO-start/local-start funcs */
1000 eo_start_send_buffered_events(eo_elem);
1001 /*
1002 * EO state changed to 'EO_STATE_RUNNING' after successful
1003 * completion of EO local starts on all cores.
1004 */
1005 return EM_OK;
1006 }
1007 /*
1008 * If req_sent == 0, then no EM-cores (worker or control) were
1009 * yet running, e.g. an EM external thread started the EO.
1010 */
1011 }
1012
1013 /*
1014 * Enable all the EO's queues.
1015 * Note: if local start functions are given then enable can be done only
1016 * after they have been run on each core.
1017 */
1018 ret = queue_enable_all(eo_elem);
1019 if (unlikely(ret != EM_OK)) {
1020 ret = INTERNAL_ERROR(ret, EM_ESCOPE_EO_START_SYNC,
1021 "EO:%" PRI_EO " queue_enable_all() failed", eo);
1022 goto eo_start_sync_error;
1023 }
1024
1025 eo_elem->state = EM_EO_STATE_RUNNING;
1026
1027 /* Send events buffered during the EO-start/local-start functions */
1028 eo_start_send_buffered_events(eo_elem);
1029 return EM_OK;
1030
1031eo_start_sync_error:
1032 locm->sync_api.in_progress = false;
1033 /* roll back state to allow EO delete */
1034 eo_elem->state = EM_EO_STATE_ERROR;
1035 return ret;
1036}
1037
1039em_eo_stop(em_eo_t eo, int num_notif, const em_notif_t notif_tbl[])
1040{
1041 eo_elem_t *const eo_elem = eo_elem_get(eo);
1042 em_status_t ret;
1043
1044 RETURN_ERROR_IF(eo_elem == NULL || !eo_allocated(eo_elem),
1045 EM_ERR_BAD_ARG, EM_ESCOPE_EO_STOP,
1046 "Invalid EO:%" PRI_EO "", eo);
1048 EM_ERR_BAD_STATE, EM_ESCOPE_EO_STOP,
1049 "EO invalid state, cannot stop:%d", eo_elem->state);
1050 ret = check_notif_tbl(num_notif, notif_tbl);
1051 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_STOP,
1052 "Invalid notif cfg given!");
1053
1054 eo_elem->state = EM_EO_STATE_STOPPING;
1055
1056 /*
1057 * Disable all queues.
1058 * It doesn't matter if some of the queues are already disabled.
1059 */
1060 queue_disable_all(eo_elem);
1061
1062 /*
1063 * Notifications sent when the local stop functions
1064 * have completed. EO global stop called when all local stops have
1065 * been completed. EO state changed to 'stopped' only after completing
1066 * the EO global stop function.
1067 */
1068 int reqs_sent = eo_stop_local_req(eo_elem, num_notif, notif_tbl);
1069
1070 if (unlikely(reqs_sent < 0)) {
1071 eo_elem->state = EM_EO_STATE_ERROR;
1072 ret = INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_STOP,
1073 "EO:%" PRI_EO " eo_stop_local_req():%d",
1074 eo, reqs_sent);
1075 /* Can't allow user err handler to change error here */
1076 return ret;
1077 } else if (unlikely(reqs_sent == 0)) {
1078 /*
1079 * If req_sent == 0, then no EM-cores (worker or control) were
1080 * running, e.g. an EM external thread stopped the EO after all EM-cores
1081 * were removed. Run the EO global stop function and change state.
1082 */
1083 ret = eo_stop_done(eo_elem);
1084
1085 /*
1086 * Note: the EO might not be available after this if the EO global stop
1087 * called em_eo_delete()!
1088 */
1089 RETURN_ERROR_IF(ret != EM_OK, EM_ERR, EM_ESCOPE_EO_STOP,
1090 "EO:%" PRI_EO " stop-func failed:%" PRI_STAT "", eo, ret);
1091 }
1092
1093 return EM_OK;
1094}
1095
1098{
1099 em_locm_t *const locm = &em_locm;
1100 eo_elem_t *const eo_elem = eo_elem_get(eo);
1101 em_status_t ret;
1102
1103 RETURN_ERROR_IF(eo_elem == NULL || !eo_allocated(eo_elem),
1104 EM_ERR_BAD_ARG, EM_ESCOPE_EO_STOP_SYNC,
1105 "Invalid EO:%" PRI_EO "", eo);
1107 EM_ERR_BAD_STATE, EM_ESCOPE_EO_STOP_SYNC,
1108 "EO invalid state, cannot stop:%d", eo_elem->state);
1109
1110 /* Mark that a sync-API call is in progress */
1111 locm->sync_api.in_progress = true;
1112
1113 eo_elem->state = EM_EO_STATE_STOPPING;
1114
1115 /*
1116 * Disable all queues.
1117 * It doesn't matter if some of the queues are already disabled.
1118 */
1119 ret = queue_disable_all(eo_elem);
1120 if (unlikely(ret != EM_OK))
1121 goto eo_stop_sync_error;
1122
1123 /*
1124 * Notifications sent when the local stop functions have completed.
1125 * EO global stop called when all local stops have been completed.
1126 * EO state changed to 'stopped' only after completing the EO global
1127 * stop function.
1128 */
1129 int reqs_sent = eo_stop_sync_local_req(eo_elem);
1130
1131 if (unlikely(reqs_sent < 0)) {
1132 eo_elem->state = EM_EO_STATE_ERROR;
1133 ret = INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_EO_STOP_SYNC,
1134 "EO:%" PRI_EO " eo_stop_sync_local_req():%d",
1135 eo, reqs_sent);
1136 /* Can't allow user err handler to change error here */
1137 goto eo_stop_sync_error;
1138 }
1139
1140 if (reqs_sent > 0) {
1141 /*
1142 * Poll the core-local unscheduled control-queue for events.
1143 * These events request the core to do a core-local operation (or nop).
1144 * Poll and handle events until 'locm->sync_api.in_progress == false'
1145 * indicating that this sync-API is 'done' on all concerned cores.
1146 */
1147 while (locm->sync_api.in_progress)
1149 }
1150
1151 /*
1152 * If req_sent == 0, then no EM-cores (worker or control) were
1153 * running, e.g. an EM external thread stopped the EO after all EM-cores
1154 * were removed. Run the EO global stop function and change state.
1155 */
1156 ret = eo_stop_done(eo_elem);
1157
1158 RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EO_STOP_SYNC,
1159 "EO:%" PRI_EO " stop-func failed", eo);
1160 /*
1161 * Note: the EO might not be available after this if the EO global stop
1162 * called em_eo_delete()!
1163 */
1164 return EM_OK;
1165
1166eo_stop_sync_error:
1167 locm->sync_api.in_progress = false;
1168 return INTERNAL_ERROR(ret, EM_ESCOPE_EO_STOP_SYNC,
1169 "Failure: EO:%" PRI_EO "", eo);
1170}
1171
1172em_eo_t em_eo_current(void)
1173{
1174 return eo_current();
1175}
1176
1177void *em_eo_context(em_eo_t eo)
1178{
1179 const eo_elem_t *eo_elem = eo_elem_get(eo);
1180 em_eo_state_t eo_state;
1181
1182 if (unlikely(EM_CHECK_LEVEL > 0 && eo_elem == NULL)) {
1183 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_CONTEXT,
1184 "Invalid EO:%" PRI_EO "", eo);
1185 return NULL;
1186 }
1187
1188 if (unlikely(EM_CHECK_LEVEL >= 2 && !eo_allocated(eo_elem))) {
1189 INTERNAL_ERROR(EM_ERR_NOT_CREATED, EM_ESCOPE_EO_CONTEXT,
1190 "EO:%" PRI_EO " not created!", eo);
1191 return NULL;
1192 }
1193
1194 eo_state = eo_elem->state;
1195 if (unlikely(EM_CHECK_LEVEL > 0 && eo_state < EM_EO_STATE_CREATED)) {
1196 INTERNAL_ERROR(EM_ERR_BAD_STATE, EM_ESCOPE_EO_CONTEXT,
1197 "Invalid EO state: EO:%" PRI_EO " state:%d",
1198 eo, eo_state);
1199 return NULL;
1200 }
1201
1202 return eo_elem->eo_ctx;
1203}
1204
1206{
1207 const eo_elem_t *eo_elem = eo_elem_get(eo);
1208
1209 if (unlikely(EM_CHECK_LEVEL > 0 && eo_elem == NULL)) {
1210 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_STATE,
1211 "Invalid EO:%" PRI_EO "", eo);
1212 return EM_EO_STATE_UNDEF;
1213 }
1214
1215 if (unlikely(EM_CHECK_LEVEL >= 2 && !eo_allocated(eo_elem))) {
1216 INTERNAL_ERROR(EM_ERR_NOT_CREATED, EM_ESCOPE_EO_STATE,
1217 "EO:%" PRI_EO " not created", eo);
1218 return EM_EO_STATE_UNDEF;
1219 }
1220
1221 return eo_elem->state;
1222}
1223
1224em_eo_t em_eo_first(unsigned int *num)
1225{
1226 _eo_tbl_iter_idx = 0; /* reset iteration */
1227 const unsigned int eo_cnt = eo_count();
1228
1229 if (num)
1230 *num = eo_cnt;
1231
1232 if (eo_cnt == 0) {
1233 _eo_tbl_iter_idx = EM_MAX_EOS; /* UNDEF = _next() */
1234 return EM_EO_UNDEF;
1235 }
1236
1237 /* find first */
1238 while (!eo_allocated(&em_shm->eo_tbl.eo_elem[_eo_tbl_iter_idx])) {
1239 _eo_tbl_iter_idx++;
1240 if (_eo_tbl_iter_idx >= EM_MAX_EOS)
1241 return EM_EO_UNDEF;
1242 }
1243
1244 return eo_idx2hdl(_eo_tbl_iter_idx);
1245}
1246
1247em_eo_t em_eo_next(void)
1248{
1249 if (_eo_tbl_iter_idx >= EM_MAX_EOS - 1)
1250 return EM_EO_UNDEF;
1251
1252 _eo_tbl_iter_idx++;
1253
1254 /* find next */
1255 while (!eo_allocated(&em_shm->eo_tbl.eo_elem[_eo_tbl_iter_idx])) {
1256 _eo_tbl_iter_idx++;
1257 if (_eo_tbl_iter_idx >= EM_MAX_EOS)
1258 return EM_EO_UNDEF;
1259 }
1260
1261 return eo_idx2hdl(_eo_tbl_iter_idx);
1262}
1263
1264em_queue_t em_eo_queue_first(unsigned int *num, em_eo_t eo)
1265{
1266 eo_elem_t *eo_elem = eo_elem_get(eo);
1267 const unsigned int max_queues = em_shm->queue_tbl.max_queue_num;
1268
1269 if (unlikely(eo_elem == NULL || !eo_allocated(eo_elem))) {
1270 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EO_QUEUE_FIRST,
1271 "Invalid EO:%" PRI_EO "", eo);
1272 if (num)
1273 *num = 0;
1274 return EM_QUEUE_UNDEF;
1275 }
1276
1277 const unsigned int num_queues = odp_atomic_load_u32(&eo_elem->num_queues);
1278
1279 if (num)
1280 *num = num_queues;
1281
1282 if (num_queues == 0) {
1283 _eo_q_iter_idx = max_queues; /* UNDEF = _next() */
1284 return EM_QUEUE_UNDEF;
1285 }
1286
1287 /*
1288 * An 'eo_elem' contains a linked list with all it's queues. That list
1289 * might be modified while processing this iteration, so instead we just
1290 * go through the whole queue table.
1291 * This is potentially a slow implementation and perhaps worth
1292 * re-thinking?
1293 */
1294 const queue_tbl_t *const queue_tbl = &em_shm->queue_tbl;
1295
1296 _eo_q_iter_idx = 0; /* reset list */
1297 _eo_q_iter_eo = eo;
1298
1299 /* find first */
1300 while (!queue_allocated(&queue_tbl->queue_elem[_eo_q_iter_idx]) ||
1301 queue_tbl->queue_elem[_eo_q_iter_idx].eo != (uint16_t)(uintptr_t)_eo_q_iter_eo) {
1302 _eo_q_iter_idx++;
1303 if (_eo_q_iter_idx >= max_queues)
1304 return EM_QUEUE_UNDEF;
1305 }
1306
1307 return queue_idx2hdl(_eo_q_iter_idx);
1308}
1309
1310em_queue_t em_eo_queue_next(void)
1311{
1312 const unsigned int max_queues = em_shm->queue_tbl.max_queue_num;
1313
1314 if (_eo_q_iter_idx >= max_queues - 1)
1315 return EM_QUEUE_UNDEF;
1316
1317 _eo_q_iter_idx++;
1318
1319 const queue_tbl_t *const queue_tbl = &em_shm->queue_tbl;
1320
1321 /* find next */
1322 while (!queue_allocated(&queue_tbl->queue_elem[_eo_q_iter_idx]) ||
1323 queue_tbl->queue_elem[_eo_q_iter_idx].eo != (uint16_t)(uintptr_t)_eo_q_iter_eo) {
1324 _eo_q_iter_idx++;
1325 if (_eo_q_iter_idx >= max_queues)
1326 return EM_QUEUE_UNDEF;
1327 }
1328
1329 return queue_idx2hdl(_eo_q_iter_idx);
1330}
1331
1332uint64_t em_eo_to_u64(em_eo_t eo)
1333{
1334 return (uint64_t)eo;
1335}
#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
void poll_unsched_ctrl_queue(void)
Poll EM's internal unscheduled control queues during dispatch.
em_status_t check_notif_tbl(const int num_notif, const em_notif_t notif_tbl[])
Check that the usage of a table of notifications is valid.
em_status_t send_notifs(const int num_notif, const em_notif_t notif_tbl[])
Helper func to send notifications events.
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
@ EM_QUEUE_STATE_READY
#define EM_EO_NAME_LEN
#define EM_MAX_EOS
#define EM_CHECK_LEVEL
#define EM_EO_MULTIRCV_MAX_EVENTS
#define PRI_QUEUE
#define PRI_EO
#define EM_TRUE
#define EM_FALSE
#define EM_QUEUE_UNDEF
#define EM_EO_UNDEF
em_status_t em_eo_register_error_handler(em_eo_t eo, em_error_handler_t handler)
em_status_t em_eo_remove_queue_all_sync(em_eo_t eo, int delete_queues)
em_eo_t em_eo_first(unsigned int *num)
em_eo_t em_eo_current(void)
em_eo_t em_eo_create(const char *name, em_start_func_t start, em_start_local_func_t local_start, em_stop_func_t stop, em_stop_local_func_t local_stop, em_receive_func_t receive, const void *eo_ctx)
em_status_t em_eo_remove_queue_all(em_eo_t eo, int delete_queues, int num_notif, const em_notif_t notif_tbl[])
size_t em_eo_name(em_eo_t eo, char *name, size_t maxlen)
em_status_t em_eo_remove_queue(em_eo_t eo, em_queue_t queue, int num_notif, const em_notif_t notif_tbl[])
em_status_t em_eo_start(em_eo_t eo, em_status_t *result, const em_eo_conf_t *conf, int num_notif, const em_notif_t notif_tbl[])
em_status_t em_eo_stop(em_eo_t eo, int num_notif, const em_notif_t notif_tbl[])
em_eo_state_t
em_status_t(* em_start_local_func_t)(void *eo_ctx, em_eo_t eo)
void(* em_receive_func_t)(void *eo_ctx, em_event_t event, em_event_type_t type, em_queue_t queue, void *q_ctx)
em_status_t(* em_stop_func_t)(void *eo_ctx, em_eo_t eo)
em_status_t(* em_stop_local_func_t)(void *eo_ctx, em_eo_t eo)
em_eo_t em_eo_next(void)
em_eo_t em_eo_find(const char *name)
void em_eo_param_init(em_eo_param_t *param)
em_queue_t em_eo_queue_next(void)
em_queue_t em_eo_queue_first(unsigned int *num, em_eo_t eo)
em_status_t em_eo_start_sync(em_eo_t eo, em_status_t *result, const em_eo_conf_t *conf)
void * em_eo_context(em_eo_t eo)
em_status_t em_eo_unregister_error_handler(em_eo_t eo)
em_status_t em_eo_add_queue(em_eo_t eo, em_queue_t queue, int num_notif, const em_notif_t notif_tbl[])
void em_eo_multircv_param_init(em_eo_multircv_param_t *param)
em_status_t em_eo_add_queue_sync(em_eo_t eo, em_queue_t queue)
em_eo_state_t em_eo_state(em_eo_t eo)
em_status_t(* em_start_func_t)(void *eo_ctx, em_eo_t eo, const em_eo_conf_t *conf)
em_status_t em_eo_stop_sync(em_eo_t eo)
uint64_t em_eo_to_u64(em_eo_t eo)
em_status_t em_eo_delete(em_eo_t eo)
em_status_t em_eo_remove_queue_sync(em_eo_t eo, em_queue_t queue)
em_eo_t em_eo_create_multircv(const char *name, const em_eo_multircv_param_t *param)
em_eo_t em_eo_create_param(const char *name, const em_eo_param_t *param)
@ EM_EO_START_LOCAL_MODE_CONFIG_FILE
@ EM_EO_START_LOCAL_MODE_LAST
@ EM_EO_STATE_STOPPING
@ EM_EO_STATE_CREATED
@ EM_EO_STATE_RUNNING
@ EM_EO_STATE_ERROR
@ EM_EO_STATE_UNDEF
@ EM_EO_STATE_STARTING
@ EM_EO_STOP_LOCAL_MODE_CONFIG_FILE
@ EM_EO_STOP_LOCAL_MODE_LAST
#define EM_OK
uint32_t em_escope_t
em_status_t(* em_error_handler_t)(em_eo_t eo, em_status_t error, em_escope_t escope, va_list args)
#define EM_FATAL(error)
uint32_t em_status_t
@ EM_ERR_OPERATION_FAILED
@ EM_ERR_BAD_ID
@ EM_ERR_NOT_CREATED
@ EM_ERR_TOO_SMALL
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_BAD_ARG
@ EM_ERR_BAD_STATE
@ EM_ERR_BAD_TYPE
@ EM_ERR_LIB_FAILED
@ EM_ERR_NOT_INITIALIZED
@ EM_ERR_BAD_POINTER
uint32_t em_queue_type_t
em_queue_type_t em_queue_type(em_queue_t queue)
#define PRI_QTYPE
@ EM_QUEUE_TYPE_ORDERED
@ EM_QUEUE_TYPE_ATOMIC
@ EM_QUEUE_TYPE_PARALLEL
@ EM_QUEUE_TYPE_LOCAL
queue_elem_t * q_elem
Definition em_mem.h:214
em_start_local_func_t local_start
em_eo_start_local_mode_t local_start_mode
em_receive_multi_func_t receive_multi
em_stop_local_func_t local_stop
em_eo_stop_local_mode_t local_stop_mode
em_eo_start_local_mode_t local_start_mode
em_start_func_t start
em_stop_local_func_t local_stop
uint32_t __internal_check
em_eo_stop_local_mode_t local_stop_mode
em_stop_func_t stop
const void * eo_ctx
em_start_local_func_t local_start
em_receive_func_t receive
em_locm_current_t current
Definition em_mem.h:228
eo_elem_t * start_eo_elem
Definition em_mem.h:275
sync_api_t sync_api
Definition em_mem.h:286
em_error_handler_t error_handler_func
Definition em_eo_types.h:82
em_eo_stop_local_mode_t stop_local_mode
Definition em_eo_types.h:71
em_receive_func_t receive_func
Definition em_eo_types.h:77
em_stop_func_t stop_func
Definition em_eo_types.h:65
odp_ticketlock_t lock
Definition em_eo_types.h:86
em_eo_state_t state
Definition em_eo_types.h:59
em_stop_local_func_t stop_local_func
Definition em_eo_types.h:67
int max_events
Definition em_eo_types.h:75
list_node_t queue_list
Definition em_eo_types.h:88
em_receive_multi_func_t receive_multi_func
Definition em_eo_types.h:79
odp_atomic_u32_t num_queues
Definition em_eo_types.h:90
em_eo_start_local_mode_t start_local_mode
Definition em_eo_types.h:69
em_start_func_t start_func
Definition em_eo_types.h:61
odp_stash_t stash
Definition em_eo_types.h:92
em_start_local_func_t start_local_func
Definition em_eo_types.h:63
int use_multi_rcv
Definition em_eo_types.h:73
em_eo_t eo
Definition em_eo_types.h:94
void * eo_ctx
Definition em_eo_types.h:84
queue_state_t state
eo_elem_t * eo_elem