EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_event_group.c
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#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_error.h"
48#include "em_event.h"
49#include "em_event_group.h"
51#include "em_event_inline.h"
52#include "em_event_state.h"
53#include "em_event_types.h"
54#include "em_internal_event.h"
55#include "em_mem.h"
56#include "em_queue.h"
57#include "em_queue_inline.h"
58#include "em_queue_types.h"
59
60em_status_t event_group_init(event_group_tbl_t *const event_group_tbl,
61 odp_stash_t *const event_group_stash)
62{
63 odp_stash_param_t stash_param;
64 odp_stash_capability_t stash_capa;
65
66 if (odp_stash_capability(&stash_capa, ODP_STASH_TYPE_FIFO) != 0)
67 return EM_ERR_LIB_FAILED;
68
69 if (stash_capa.max_num.u32 < EM_MAX_EVENT_GROUPS) {
70 EM_LOG(EM_LOG_ERR,
71 "Maximum number of event groups(%d) exceeds the maximum\n"
72 "number of object handles(%" PRIu64 ") a stash can hold.\n",
73 EM_MAX_EVENT_GROUPS, stash_capa.max_num.u32);
74 return EM_ERR_TOO_LARGE;
75 }
76
77 memset(event_group_tbl, 0, sizeof(event_group_tbl_t));
78 odp_atomic_init_u32(&em_shm->event_group_count, 0);
79
80 odp_stash_param_init(&stash_param);
81
82 stash_param.type = ODP_STASH_TYPE_FIFO;
83 stash_param.put_mode = ODP_STASH_OP_MT;
84 stash_param.get_mode = ODP_STASH_OP_MT;
85 stash_param.num_obj = EM_MAX_EVENT_GROUPS;
86 stash_param.obj_size = sizeof(uint32_t);
87 /*
88 * The stash holds at most EM_MAX_EVENT_GROUPS handles (= num_obj) and the
89 * egrp_elem->in_stash guard blocks double-puts, so it can never overflow
90 * num_obj: enable strict_size to allow a faster ODP ring implementation.
91 */
92 stash_param.strict_size = true;
93
94 odp_stash_t stash = odp_stash_create("event_grp", &stash_param);
95
96 if (stash == ODP_STASH_INVALID)
97 return EM_ERR_LIB_FAILED;
98
99 event_group_elem_t *egrp_elem;
100 egrp_counter_t init_cnt;
101 uint32_t idx;
102
103 init_cnt.all_u64 = 0;
104
105 for (idx = 0; idx < EM_MAX_EVENT_GROUPS; idx++) {
106 egrp_elem = &em_shm->event_group_tbl.egrp_elem[idx];
107
108 __atomic_store_n(&egrp_elem->counts.atomic_u64, init_cnt.all_u64,
109 __ATOMIC_RELEASE);
110 egrp_elem->event_group = egrp_idx2hdl(idx); /* store handle */
111 egrp_elem->num_notif = 0;
112
113 egrp_elem->in_stash = true;
114 if (odp_stash_put_u32(stash, &idx, 1) != 1) {
115 egrp_elem->in_stash = false;
116 goto error_return;
117 }
118 }
119
120 *event_group_stash = stash;
121 return EM_OK;
122
123error_return:
124 /* Empty the stash before destroying it */
125 for (uint32_t i = 0; i < idx; i++) {
126 uint32_t val = 0;
127
128 odp_stash_get_u32(stash, &val, 1);
129 egrp_elem = &em_shm->event_group_tbl.egrp_elem[i];
130 egrp_elem->event_group = EM_EVENT_GROUP_UNDEF;
131 egrp_elem->in_stash = false;
132 }
133
134 odp_stash_destroy(stash);
135 return EM_ERR_LIB_FAILED;
136}
137
138em_status_t event_group_term(void)
139{
140 odp_stash_t stash = em_shm->event_group_stash;
141
142 while (1) {
143 uint32_t tmp;
144 int32_t num = odp_stash_get_u32(stash, &tmp, 1);
145
146 if (num == 1)
147 continue;
148
149 if (num == 0)
150 break;
151
152 EM_PRINT("Stash get failed: %i\n", num);
153 return EM_ERR_LIB_FAILED;
154 }
155
156 if (odp_stash_destroy(stash))
157 return EM_ERR_LIB_FAILED;
158
159 return EM_OK;
160}
161
162em_event_group_t event_group_alloc(void)
163{
164 uint32_t idx;
165 event_group_elem_t *egrp_elem;
166
167 if (unlikely(odp_stash_get_u32(em_shm->event_group_stash, &idx, 1) != 1))
169
170 if (unlikely(idx >= EM_MAX_EVENT_GROUPS))
172
173 egrp_elem = &em_shm->event_group_tbl.egrp_elem[idx];
174 egrp_elem->in_stash = false;
175
176 odp_atomic_inc_u32(&em_shm->event_group_count);
177
178 return egrp_idx2hdl(idx);
179}
180
181em_status_t event_group_free(em_event_group_t event_group)
182{
183 event_group_elem_t *egrp_elem = event_group_elem_get(event_group);
184 uint32_t idx = (uint32_t)egrp_hdl2idx(event_group);
185
186 if (unlikely(egrp_elem == NULL))
187 return EM_ERR_BAD_ID;
188
189 if (unlikely(egrp_elem->in_stash))
190 return EM_ERR_BAD_STATE;
191
192 egrp_elem->in_stash = true;
193 if (unlikely(odp_stash_put_u32(em_shm->event_group_stash, &idx, 1) != 1)) {
194 egrp_elem->in_stash = false;
195 return EM_ERR_LIB_FAILED;
196 }
197
198 odp_atomic_dec_u32(&em_shm->event_group_count);
199 return EM_OK;
200}
201
202unsigned int event_group_count(void)
203{
204 return odp_atomic_load_u32(&em_shm->event_group_count);
205}
206
207#define EGRP_INFO_HDR_FMT \
208"Number of event groups: %u\n\n" \
209"ID Applied Cnt(pre) Cnt(post) Gen Num-notif\n" \
210"-------------------------------------------------------\n%s\n"
211
212#define EGRP_INFO_LEN 56
213#define EGRP_INFO_FMT "%-10" PRI_EGRP "%-9c%-10u%-11u%-6u%-9d\n" /*56 bytes*/
214
215void event_group_info_print(void)
216{
217 unsigned int egrp_num;
218 em_event_group_t egrp;
219 const event_group_elem_t *egrp_elem;
220 egrp_counter_t egrp_count;
221 int len = 0;
222 int n_print = 0;
223
224 egrp = em_event_group_first(&egrp_num);
225
226 /*
227 * egrp_num may not match the amount of event groups actually returned
228 * by iterating with em_event_group_next() if event groups are added
229 * or removed in parallel by another core. Thus space for 10 extra event
230 * groups is reserved. If more than 10 event groups are added by other
231 * cores in parallel, we print only information of the (egrp_num + 10)
232 * event groups.
233 *
234 * The extra 1 byte is reserved for the terminating null byte.
235 */
236 const int egrp_info_str_len = (egrp_num + 10) * EGRP_INFO_LEN + 1;
237 char egrp_info_str[egrp_info_str_len];
238
239 while (egrp != EM_EVENT_GROUP_UNDEF) {
240 egrp_elem = event_group_elem_get(egrp);
241
242 if (unlikely(egrp_elem == NULL || !event_group_allocated(egrp_elem))) {
243 egrp = em_event_group_next();
244 continue;
245 }
246
247 egrp_count.all_u64 = __atomic_load_n(&egrp_elem->counts.atomic_u64,
248 __ATOMIC_ACQUIRE);
249 n_print = snprintf(egrp_info_str + len,
250 egrp_info_str_len - len,
251 EGRP_INFO_FMT, egrp,
252 egrp_count.applied ? 'Y' : 'N',
253 (uint32_t)egrp_count.pre_cnt, (uint32_t)egrp_count.post_cnt,
254 (uint32_t)egrp_count.gen, egrp_elem->num_notif);
255
256 /* Not enough space to hold more event group info */
257 if (n_print >= egrp_info_str_len - len)
258 break;
259
260 len += n_print;
261 egrp = em_event_group_next();
262 }
263
264 /* No event group */
265 if (len == 0) {
266 EM_PRINT("No event group!\n");
267 return;
268 }
269
270 /*
271 * To prevent printing incomplete information of the last event group
272 * when there is not enough space to hold all event group info.
273 */
274 egrp_info_str[len] = '\0';
275 EM_PRINT(EGRP_INFO_HDR_FMT, egrp_num, egrp_info_str);
276}
em_shm_t * em_shm
#define EM_MAX_EVENT_GROUPS
#define EM_EVENT_GROUP_UNDEF
#define EM_OK
uint32_t em_status_t
@ EM_ERR_TOO_LARGE
@ EM_ERR_BAD_ID
@ EM_ERR_BAD_STATE
@ EM_ERR_LIB_FAILED
em_event_group_t em_event_group_next(void)
em_event_group_t em_event_group_first(unsigned int *num)
odp_atomic_u32_t event_group_count
Definition em_mem.h:179