EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
event_machine_queue_group.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#include <string.h>
42
43#include <odp_api.h>
44
45#include <event_machine.h>
46
47#include "em_core.h"
48#include "em_error.h"
49#include "em_internal_event.h"
51#include "em_mem.h"
52#include "em_queue.h"
53#include "em_queue_group.h"
55#include "em_queue_inline.h"
56#include "em_queue_types.h"
57
58/* per core (thread) state for em_queue_group_next() */
59static ENV_LOCAL unsigned int _qgrp_tbl_iter_idx;
60/* Per core (thread) state of em_queue_group_queue_next() */
61static ENV_LOCAL unsigned int _qgrp_q_iter_idx;
62static ENV_LOCAL em_queue_group_t _qgrp_q_iter_qgrp;
63
64em_queue_group_t
65em_queue_group_create(const char *name, const em_core_mask_t *mask,
66 int num_notif, const em_notif_t notif_tbl[])
67{
68 em_queue_group_t queue_group;
69 em_status_t err;
70
71 if (unlikely(!mask)) {
72 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_CREATE,
73 "Core mask NULL");
75 }
76
77 err = check_notif_tbl(num_notif, notif_tbl);
78 if (unlikely(err != EM_OK)) {
79 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_CREATE,
80 "Invalid notif cfg given:%" PRI_STAT "!", err);
82 }
83
84 queue_group = queue_group_create(name, mask, num_notif, notif_tbl,
85 EM_QUEUE_GROUP_UNDEF/*any free qgrp*/);
86 return queue_group;
87}
88
89em_queue_group_t
90em_queue_group_create_sync(const char *name, const em_core_mask_t *mask)
91{
92 em_queue_group_t queue_group;
93
94 if (unlikely(!mask)) {
95 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_CREATE_SYNC,
96 "Core mask NULL");
98 }
99
100 queue_group = queue_group_create_sync(name, mask, EM_QUEUE_GROUP_UNDEF
101 /* any free queue group */);
102 return queue_group;
103}
104
106em_queue_group_delete(em_queue_group_t queue_group,
107 int num_notif, const em_notif_t notif_tbl[])
108{
109 em_core_mask_t zero_mask;
110 em_status_t err;
111
112 queue_group_elem_t *const qgrp_elem = queue_group_elem_get(queue_group);
113
114 RETURN_ERROR_IF(!qgrp_elem || !queue_group_allocated(qgrp_elem),
115 EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_DELETE,
116 "Invalid queue group: %" PRI_QGRP "", queue_group);
117
118 err = check_notif_tbl(num_notif, notif_tbl);
119 RETURN_ERROR_IF(err != EM_OK, EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_DELETE,
120 "Invalid notif cfg given, err=%" PRI_STAT "", err);
121
122 em_core_mask_zero(&zero_mask);
123
124 /* Use modify and the notif mechanism to set the core mask to zero */
125 err = queue_group_modify(qgrp_elem, &zero_mask, num_notif, notif_tbl,
126 true /*is_delete*/);
127
128 RETURN_ERROR_IF(err != EM_OK, err, EM_ESCOPE_QUEUE_GROUP_DELETE,
129 "Queue group:%" PRI_QGRP " modify for delete failed!",
130 queue_group);
131
132 return EM_OK;
133}
134
136em_queue_group_delete_sync(em_queue_group_t queue_group)
137{
138 em_core_mask_t zero_mask;
139 em_status_t err;
140
141 queue_group_elem_t *const qgrp_elem = queue_group_elem_get(queue_group);
142
143 RETURN_ERROR_IF(!qgrp_elem || !queue_group_allocated(qgrp_elem),
144 EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_DELETE_SYNC,
145 "Invalid queue group:%" PRI_QGRP "", queue_group);
146
147 em_core_mask_zero(&zero_mask);
148
149 /* Use modify and the notif mechanism to set the core mask to zero */
150 err = queue_group_modify_sync(qgrp_elem, &zero_mask,
151 true /*is_delete*/);
152
153 RETURN_ERROR_IF(err != EM_OK, err, EM_ESCOPE_QUEUE_GROUP_DELETE_SYNC,
154 "Queue group:%" PRI_QGRP " modify for delete failed!",
155 queue_group);
156
157 return EM_OK;
158}
159
161em_queue_group_modify(em_queue_group_t queue_group,
162 const em_core_mask_t *new_mask,
163 int num_notif, const em_notif_t notif_tbl[])
164{
165 queue_group_elem_t *const qgrp_elem = queue_group_elem_get(queue_group);
166 em_status_t err;
167
168 RETURN_ERROR_IF(!qgrp_elem || !queue_group_allocated(qgrp_elem),
169 EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MODIFY,
170 "Invalid queue group:%" PRI_QGRP "", queue_group);
171
172 RETURN_ERROR_IF(!new_mask, EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MODIFY,
173 "Queue group mask NULL! Queue group:%" PRI_QGRP "",
174 queue_group);
175
176 err = check_notif_tbl(num_notif, notif_tbl);
177 RETURN_ERROR_IF(err != EM_OK, EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MODIFY,
178 "Invalid notif cfg given, err=%" PRI_STAT "", err);
179
180 err = queue_group_modify(qgrp_elem, new_mask, num_notif, notif_tbl,
181 false /*!is_delete*/);
182 RETURN_ERROR_IF(err != EM_OK, err, EM_ESCOPE_QUEUE_GROUP_MODIFY,
183 "Queue group:%" PRI_QGRP " modify failed!",
184 queue_group);
185 return EM_OK;
186}
187
189em_queue_group_modify_sync(em_queue_group_t queue_group,
190 const em_core_mask_t *new_mask)
191{
192 queue_group_elem_t *const qgrp_elem = queue_group_elem_get(queue_group);
193 em_status_t err;
194
195 RETURN_ERROR_IF(!qgrp_elem || !queue_group_allocated(qgrp_elem),
196 EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MODIFY_SYNC,
197 "Invalid queue group: %" PRI_QGRP "", queue_group);
198
199 RETURN_ERROR_IF(!new_mask, EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MODIFY_SYNC,
200 "Queue group mask NULL! Queue group:%" PRI_QGRP "",
201 queue_group);
202
203 err = queue_group_modify_sync(qgrp_elem, new_mask, false/*!is_delete*/);
204
205 RETURN_ERROR_IF(err != EM_OK, err, EM_ESCOPE_QUEUE_GROUP_MODIFY_SYNC,
206 "Queue group:%" PRI_QGRP " modify sync failed!",
207 queue_group);
208 return EM_OK;
209}
210
211em_queue_group_t
212em_queue_group_find(const char *name)
213{
214 odp_schedule_group_t odp_group;
215
216 if (!name || name[0] == '\0')
218
219 odp_group = odp_schedule_group_lookup(name);
220 if (odp_group == ODP_SCHED_GROUP_INVALID)
222
223 for (int i = 0; i < EM_MAX_QUEUE_GROUPS; i++) {
224 const queue_group_elem_t *qgrp_elem =
225 &em_shm->queue_group_tbl.queue_group_elem[i];
226
227 if (qgrp_elem->odp_sched_group == odp_group &&
228 queue_group_allocated(qgrp_elem))
229 return qgrp_idx2hdl(i);
230 }
231
233}
234
235em_status_t em_queue_group_mask(em_queue_group_t queue_group,
236 em_core_mask_t *mask /*out*/)
237{
238 int allocated;
239 bool ongoing_delete;
240 queue_group_elem_t *const qgrp_elem = queue_group_elem_get(queue_group);
241
242 RETURN_ERROR_IF(!qgrp_elem, EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_MASK,
243 "Invalid queue group:%" PRI_QGRP "", queue_group);
244
245 odp_ticketlock_lock(&qgrp_elem->lock);
246
247 allocated = queue_group_allocated(qgrp_elem);
248 ongoing_delete = qgrp_elem->ongoing_delete;
249 em_core_mask_copy(mask, &qgrp_elem->core_mask);
250
251 odp_ticketlock_unlock(&qgrp_elem->lock);
252
253 RETURN_ERROR_IF(!allocated || ongoing_delete,
254 EM_ERR_BAD_STATE, EM_ESCOPE_QUEUE_GROUP_MASK,
255 "Queue group:%" PRI_QGRP " in bad state:\t"
256 "allocated=%s, ongoing_delete=%s",
257 queue_group, allocated ? "true" : "false(!)",
258 ongoing_delete ? "true(!)" : "false");
259
260 return EM_OK;
261}
262
263size_t em_queue_group_name(em_queue_group_t queue_group,
264 char *name, size_t maxlen)
265{
266 const queue_group_elem_t *qgrp_elem = queue_group_elem_get(queue_group);
267 odp_schedule_group_info_t info;
268 size_t len;
269 int ret;
270
271 if (unlikely(!name || maxlen == 0)) {
272 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_NAME,
273 "Invalid name=0x%" PRIx64 " or maxlen=%zu",
274 name, maxlen);
275 return 0;
276 }
277
278 name[0] = '\0';
279
280 if (unlikely(!qgrp_elem || !queue_group_allocated(qgrp_elem))) {
281 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_NAME,
282 "Invalid queue group:%" PRI_QGRP "",
283 queue_group);
284 return 0;
285 }
286
287 ret = odp_schedule_group_info(qgrp_elem->odp_sched_group, &info);
288 if (unlikely(ret != 0)) {
289 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_QUEUE_GROUP_NAME,
290 "Failed to retrieve queue group info");
291 return 0;
292 }
293
294 if (unlikely(!info.name))
295 return 0;
296
297 len = strnlen(info.name, ODP_SCHED_GROUP_NAME_LEN - 1);
298 if (maxlen - 1 < len)
299 len = maxlen - 1;
300
301 memcpy(name, info.name, len);
302 name[len] = '\0';
303
304 return len;
305}
306
307em_queue_group_t em_queue_group_first(unsigned int *num)
308{
309 const queue_group_elem_t *const qgrp_elem_tbl =
310 em_shm->queue_group_tbl.queue_group_elem;
311 const queue_group_elem_t *qgrp_elem = &qgrp_elem_tbl[0];
312 const unsigned int max_qgrps = EM_MAX_QUEUE_GROUPS;
313 const unsigned int qgrp_cnt = queue_group_count();
314
315 _qgrp_tbl_iter_idx = 0; /* reset iteration */
316
317 if (num)
318 *num = qgrp_cnt;
319
320 if (qgrp_cnt == 0) {
321 _qgrp_tbl_iter_idx = max_qgrps; /* UNDEF = _next() */
323 }
324
325 /* find first */
326 while (!queue_group_allocated(qgrp_elem)) {
327 _qgrp_tbl_iter_idx++;
328 if (_qgrp_tbl_iter_idx >= max_qgrps)
330 qgrp_elem = &qgrp_elem_tbl[_qgrp_tbl_iter_idx];
331 }
332
333 return qgrp_idx2hdl(_qgrp_tbl_iter_idx);
334}
335
336em_queue_group_t em_queue_group_next(void)
337{
338 const unsigned int max_qgrps = EM_MAX_QUEUE_GROUPS;
339
340 if (_qgrp_tbl_iter_idx >= max_qgrps - 1)
342
343 _qgrp_tbl_iter_idx++;
344
345 const queue_group_elem_t *const qgrp_elem_tbl =
346 em_shm->queue_group_tbl.queue_group_elem;
347 const queue_group_elem_t *qgrp_elem =
348 &qgrp_elem_tbl[_qgrp_tbl_iter_idx];
349
350 /* find next */
351 while (!queue_group_allocated(qgrp_elem)) {
352 _qgrp_tbl_iter_idx++;
353 if (_qgrp_tbl_iter_idx >= max_qgrps)
355 qgrp_elem = &qgrp_elem_tbl[_qgrp_tbl_iter_idx];
356 }
357
358 return qgrp_idx2hdl(_qgrp_tbl_iter_idx);
359}
360
361em_queue_t em_queue_group_queue_first(unsigned int *num,
362 em_queue_group_t queue_group)
363{
364 queue_group_elem_t *qgrp_elem = queue_group_elem_get(queue_group);
365 const unsigned int max_queues = em_shm->queue_tbl.max_queue_num;
366
367 if (unlikely(!qgrp_elem || !queue_group_allocated(qgrp_elem))) {
368 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_QUEUE_GROUP_QUEUE_FIRST,
369 "Invalid queue group:%" PRI_QGRP "",
370 queue_group);
371 if (num)
372 *num = 0;
373 return EM_QUEUE_UNDEF;
374 }
375
376 const unsigned int num_queues = odp_atomic_load_u32(&qgrp_elem->num_queues);
377
378 if (num)
379 *num = num_queues;
380
381 if (num_queues == 0) {
382 _qgrp_q_iter_idx = max_queues; /* UNDEF = _next() */
383 return EM_QUEUE_UNDEF;
384 }
385
386 /*
387 * A 'qgrp_elem' contains a linked list with all it's queues. That list
388 * might be modified while processing this iteration, so instead we just
389 * go through the whole queue table.
390 * This is potentially a slow implementation and perhaps worth
391 * re-thinking?
392 */
393 const queue_elem_t *const q_elem_tbl = em_shm->queue_tbl.queue_elem;
394 const queue_elem_t *q_elem = &q_elem_tbl[0];
395
396 _qgrp_q_iter_idx = 0; /* reset list */
397 _qgrp_q_iter_qgrp = queue_group;
398
399 /* find first */
400 while (!queue_allocated(q_elem) ||
401 q_elem->queue_group != _qgrp_q_iter_qgrp) {
402 _qgrp_q_iter_idx++;
403 if (_qgrp_q_iter_idx >= max_queues)
404 return EM_QUEUE_UNDEF;
405 q_elem = &q_elem_tbl[_qgrp_q_iter_idx];
406 }
407
408 return queue_idx2hdl(_qgrp_q_iter_idx);
409}
410
412{
413 const unsigned int max_queues = em_shm->queue_tbl.max_queue_num;
414
415 if (_qgrp_q_iter_idx >= max_queues - 1)
416 return EM_QUEUE_UNDEF;
417
418 _qgrp_q_iter_idx++;
419
420 const queue_elem_t *const q_elem_tbl = em_shm->queue_tbl.queue_elem;
421 const queue_elem_t *q_elem = &q_elem_tbl[_qgrp_q_iter_idx];
422
423 /* find next */
424 while (!queue_allocated(q_elem) ||
425 q_elem->queue_group != _qgrp_q_iter_qgrp) {
426 _qgrp_q_iter_idx++;
427 if (_qgrp_q_iter_idx >= max_queues)
428 return EM_QUEUE_UNDEF;
429 q_elem = &q_elem_tbl[_qgrp_q_iter_idx];
430 }
431
432 return queue_idx2hdl(_qgrp_q_iter_idx);
433}
434
435uint64_t em_queue_group_to_u64(em_queue_group_t queue_group)
436{
437 return (uint64_t)queue_group;
438}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
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_shm_t * em_shm
#define EM_MAX_QUEUE_GROUPS
void em_core_mask_copy(em_core_mask_t *dst, const em_core_mask_t *src)
void em_core_mask_zero(em_core_mask_t *mask)
#define EM_QUEUE_GROUP_UNDEF
#define PRI_QGRP
#define EM_QUEUE_UNDEF
#define EM_OK
uint32_t em_status_t
@ EM_ERR_BAD_ARG
@ EM_ERR_BAD_STATE
@ EM_ERR_LIB_FAILED
em_queue_group_t em_queue_group_find(const char *name)
em_queue_group_t em_queue_group_first(unsigned int *num)
size_t em_queue_group_name(em_queue_group_t queue_group, char *name, size_t maxlen)
em_status_t em_queue_group_modify_sync(em_queue_group_t queue_group, const em_core_mask_t *new_mask)
em_queue_group_t em_queue_group_create(const char *name, const em_core_mask_t *mask, int num_notif, const em_notif_t notif_tbl[])
em_status_t em_queue_group_modify(em_queue_group_t queue_group, const em_core_mask_t *new_mask, int num_notif, const em_notif_t notif_tbl[])
em_queue_group_t em_queue_group_create_sync(const char *name, const em_core_mask_t *mask)
em_queue_group_t em_queue_group_next(void)
em_queue_t em_queue_group_queue_first(unsigned int *num, em_queue_group_t queue_group)
em_status_t em_queue_group_delete_sync(em_queue_group_t queue_group)
em_status_t em_queue_group_delete(em_queue_group_t queue_group, int num_notif, const em_notif_t notif_tbl[])
em_queue_t em_queue_group_queue_next(void)
uint64_t em_queue_group_to_u64(em_queue_group_t queue_group)
em_status_t em_queue_group_mask(em_queue_group_t queue_group, em_core_mask_t *mask)
em_queue_group_t queue_group
odp_atomic_u32_t num_queues
odp_schedule_group_t odp_sched_group