EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_queue_inline.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015-2026, 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 * EM internal queue functions
34 */
35
36#ifndef EM_QUEUE_INLINE_H_
37#define EM_QUEUE_INLINE_H_
38
39#include <stdbool.h>
40#include <stddef.h>
41#include <stdint.h>
42
43#include <odp_api.h>
44
45#include <event_machine.h>
46
47#include "em_event_inline.h"
48#include "em_event_state.h"
49#include "em_event_types.h"
50#include "em_mem.h"
51#include "em_queue_types.h"
52#include "misc/list.h"
53#include "misc/objpool.h"
54
55#ifdef __cplusplus
56extern "C" {
57#endif
58
59/** Is the queue allocated? */
60static inline int
61queue_allocated(const queue_elem_t *const queue_elem)
62{
63 return !objpool_in_pool(&queue_elem->queue_pool_elem);
64}
65
66/** Convert EM queue handle to queue index */
67static inline int
68queue_hdl2idx(em_queue_t queue)
69{
70 internal_queue_t iq = {.queue = queue};
71 int queue_idx;
72
73 queue_idx = iq.queue_id - EM_QUEUE_RANGE_OFFSET;
74
75 return queue_idx;
76}
77
78/** Convert queue index to EM queue handle */
79static inline em_queue_t
80queue_idx2hdl(int queue_idx)
81{
82 internal_queue_t iq = {.queue = 0};
83
84 iq.queue_id = queue_idx + EM_QUEUE_RANGE_OFFSET;
85 iq.device_id = em_shm->conf.device_id;
86
87 return iq.queue;
88}
89
90/** Convert queue ID (internal_queue_t:queue_id) to queue index */
91static inline int
92queue_id2idx(uint16_t queue_id)
93{
94 return (int)queue_id - EM_QUEUE_RANGE_OFFSET;
95}
96
97/** Convert queue index to queue ID (internal_queue_t:queue_id) */
98static inline uint16_t
99queue_idx2id(int queue_idx)
100{
101 return (uint16_t)queue_idx + EM_QUEUE_RANGE_OFFSET;
102}
103
104/** Convert queue ID (internal_queue_t:queue_id) handle to EM queue handle */
105static inline em_queue_t
106queue_id2hdl(uint16_t queue_id)
107{
108 internal_queue_t iq = {.queue = 0};
109
110 iq.queue_id = queue_id;
111 iq.device_id = em_shm->conf.device_id;
112
113 return iq.queue;
114}
115
116/**
117 * Return 'true' if the EM queue handle belongs to another EM instance.
118 *
119 * Sending to external queues will cause EM to call the user provided
120 * functions 'event_send_device' or 'event_send_device_multi'
121 */
122static inline bool
123queue_external(em_queue_t queue)
124{
125 internal_queue_t iq = {.queue = queue};
126
127 if (unlikely(queue == EM_QUEUE_UNDEF))
128 return 0;
129
130 return iq.device_id != em_shm->conf.device_id ? true : false;
131}
132
133/** Returns queue element associated with queued id 'queue' */
134static inline queue_elem_t *
135queue_elem_get(const em_queue_t queue)
136{
137 int queue_idx;
139 queue_elem_t *queue_elem;
140
141 iq.queue = queue;
142 queue_idx = queue_id2idx(iq.queue_id);
143
144 if (unlikely(iq.device_id != em_shm->conf.device_id ||
145 (uint16_t)queue_idx > em_shm->queue_tbl.max_queue_num - 1))
146 return NULL;
147
148 queue_elem = &em_shm->queue_tbl.queue_elem[queue_idx];
149
150 return queue_elem;
151}
152
153static inline em_queue_t
154queue_current(void)
155{
156 const queue_elem_t *const q_elem = em_locm.current.q_elem;
157
158 if (unlikely(q_elem == NULL))
159 return EM_QUEUE_UNDEF;
160
161 return (em_queue_t)(uintptr_t)q_elem->queue;
162}
163
164/**
165 * Convert an EO queue list node to its containing queue element.
166 *
167 * @param list_node Pointer to the 'eo_queue_node' member of a queue_elem_t
168 *
169 * @return Pointer to the queue element, or NULL if list_node is NULL
170 */
171static inline queue_elem_t *
172eo_queue_node_to_queue_elem(const list_node_t *const list_node)
173{
174 queue_elem_t *const q_elem = (queue_elem_t *)((uintptr_t)list_node
175 - offsetof(queue_elem_t, eo_queue_node));
176
177 return likely(list_node != NULL) ? q_elem : NULL;
178}
179
180static inline int
181prio_em2odp(em_queue_prio_t em_prio, odp_schedule_prio_t *odp_prio /*out*/)
182{
183 if (em_prio < EM_QUEUE_PRIO_NUM) {
184 *odp_prio = em_shm->queue_prio.map[em_prio];
185 return 0;
186 }
187 return -1;
188}
189
190static inline int
191scheduled_queue_type_em2odp(em_queue_type_t em_queue_type,
192 odp_schedule_sync_t *odp_schedule_sync /* out */)
193{
194 switch (em_queue_type) {
196 *odp_schedule_sync = ODP_SCHED_SYNC_ATOMIC;
197 return 0;
199 *odp_schedule_sync = ODP_SCHED_SYNC_PARALLEL;
200 return 0;
202 *odp_schedule_sync = ODP_SCHED_SYNC_ORDERED;
203 return 0;
204 default:
205 return -1;
206 }
207}
208
209static inline int
210scheduled_queue_type_odp2em(odp_schedule_sync_t odp_schedule_sync,
212{
213 switch (odp_schedule_sync) {
214 case ODP_SCHED_SYNC_ATOMIC:
216 return 0;
217 case ODP_SCHED_SYNC_PARALLEL:
219 return 0;
220 case ODP_SCHED_SYNC_ORDERED:
222 return 0;
223 default:
225 return 0;
226 }
227}
228
229static inline em_event_t
230queue_dequeue(const queue_elem_t *q_elem)
231{
232 odp_queue_t odp_queue;
233 odp_event_t odp_event;
234 em_event_t event;
235
236 odp_queue = q_elem->odp_queue;
237 odp_event = odp_queue_deq(odp_queue);
238 if (odp_event == ODP_EVENT_INVALID)
239 return EM_EVENT_UNDEF;
240
241 event = event_odp2em(odp_event);
242
243 /*
244 * Only aggregator parents (flags.has_aggr) can receive aggregation-
245 * produced vectors, which need full vector-header init plus, with ESV,
246 * the inner-event em2usr transition - event_init_odp() applies it. A
247 * plain queue only ever yields scalars or user-built vectors, both of
248 * which need at most the same em2usr as a scalar, so keep them on the
249 * fast path below (no per-event odp_event_type() probe).
250 */
251 if (unlikely(q_elem->flags.has_aggr &&
252 odp_event_type(odp_event) == ODP_EVENT_VECTOR)) {
253 /*
254 * .has_aggr implies the event-vector backend, so a vector here is
255 * always an ODP event vector - init it directly instead of via
256 * event_init_odp(). evhdr_init_evvec() inits the header and, with
257 * ESV, scans the inner table; the per-inner aggr_sent/refs_used
258 * flags pick aggregator-delivered slots needing em2usr and skip
259 * user-built ones.
260 */
261 odp_event_vector_t odp_evvec = odp_event_vector_from_event(odp_event);
262 event_hdr_t *ev_hdr = odp_event_vector_user_area(odp_evvec);
263
264 return evhdr_init_evvec(ev_hdr, event, odp_evvec,
265 true/*is_extev*/, q_elem);
266 }
267
268 if (esv_enabled()) {
269 event_hdr_t *ev_hdr = event_to_hdr(event);
270
271 event = evstate_em2usr(event, ev_hdr, EVSTATE__DEQUEUE);
272 }
273
274 return event;
275}
276
277static inline int
278queue_dequeue_multi(const queue_elem_t *q_elem,
279 em_event_t events[/*out*/], int num)
280{
281 odp_queue_t odp_queue;
282 int ret;
283
284 /* use same output-array for dequeue: odp_events[] = events[] */
285 odp_event_t *const odp_events = (odp_event_t *)events;
286
287 odp_queue = q_elem->odp_queue;
288 ret = odp_queue_deq_multi(odp_queue, odp_events /*out*/, num);
289 if (ret <= 0)
290 return ret;
291
292 /* now events[] = odp_events[], events[].evgen missing, set below: */
293
294 /*
295 * Only aggregator parents (flags.has_aggr) can receive aggregation-
296 * produced vectors that need full init + inner-event em2usr; handle
297 * those per-event. A plain queue never yields such vectors, so use the
298 * batched fast path below - and skip all per-event work when ESV is
299 * disabled.
300 */
301 if (unlikely(q_elem->flags.has_aggr)) {
302 /*
303 * .has_aggr implies the event-vector backend - a vector here is
304 * always an ODP event vector, init directly (see queue_dequeue()).
305 */
306 for (int i = 0; i < ret; i++) {
307 if (odp_event_type(odp_events[i]) == ODP_EVENT_VECTOR) {
308 odp_event_vector_t evvec =
309 odp_event_vector_from_event(odp_events[i]);
310 event_hdr_t *ev_hdr =
311 odp_event_vector_user_area(evvec);
312
313 events[i] = evhdr_init_evvec(ev_hdr,
314 event_odp2em(odp_events[i]),
315 evvec, true/*is_extev*/,
316 q_elem);
317 } else if (esv_enabled()) {
318 event_hdr_t *ev_hdr = event_to_hdr(events[i]);
319
320 events[i] = evstate_em2usr(events[i], ev_hdr,
321 EVSTATE__DEQUEUE_MULTI);
322 }
323 }
324 return ret;
325 }
326
327 if (esv_enabled()) {
328 event_hdr_t *ev_hdrs[ret];
329
330 event_to_hdr_multi(events, ev_hdrs, ret);
331 evstate_em2usr_multi(events, ev_hdrs, ret,
332 EVSTATE__DEQUEUE_MULTI);
333 }
334
335 return ret;
336}
337
338#ifdef __cplusplus
339}
340#endif
341
342#endif /* EM_QUEUE_INLINE_H_ */
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_QUEUE_PRIO_NUM
#define EM_QUEUE_RANGE_OFFSET
#define EM_EVENT_UNDEF
#define EM_QUEUE_UNDEF
uint32_t em_queue_type_t
uint32_t em_queue_prio_t
em_queue_type_t em_queue_type(em_queue_t queue)
@ EM_QUEUE_TYPE_ORDERED
@ EM_QUEUE_TYPE_ATOMIC
@ EM_QUEUE_TYPE_PARALLEL
@ EM_QUEUE_TYPE_UNDEF
queue_elem_t * q_elem
Definition em_mem.h:214
em_locm_current_t current
Definition em_mem.h:228
struct em_shm_t::@53 queue_prio
int map[EM_QUEUE_PRIO_NUM]
Definition em_mem.h:190
em_conf_t conf
Definition em_mem.h:93
odp_queue_t odp_queue
objpool_elem_t queue_pool_elem
queue_elem_flags_t flags