EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_hooks.c
1/*
2 * Copyright (c) 2019, 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 <stdint.h>
40#include <string.h>
41
42#include <event_machine.h>
43
44#include "em_error.h"
45#include "em_hooks.h"
46#include "em_hook_types.h"
47#include "em_mem.h"
48
49static hook_tbl_t **
50get_hook_tbl(const uint8_t hook_type, hook_storage_t **hook_storage /*out*/);
51
52/**
53 * Pack a hook table after removing one item.
54 *
55 * Move pointers following the given index back towards the beginning of the
56 * table so that there are no NULL pointers in the middle.
57 */
58static inline int
59pack_hook_tbl(hook_tbl_t hook_tbl[], unsigned int idx);
60
62hooks_init(const em_api_hooks_t *api_hooks, const em_idle_hooks_t *idle_hooks)
63{
64 hook_fn_t hook_fn;
65 em_status_t stat = EM_OK;
66
67 memset(&em_shm->dispatch_enter_cb_storage, 0, sizeof(hook_storage_t));
68 memset(&em_shm->dispatch_exit_cb_storage, 0, sizeof(hook_storage_t));
69 memset(&em_shm->alloc_hook_storage, 0, sizeof(hook_storage_t));
70 memset(&em_shm->free_hook_storage, 0, sizeof(hook_storage_t));
71 memset(&em_shm->send_hook_storage, 0, sizeof(hook_storage_t));
72
73 memset(&em_shm->to_idle_hook_storage, 0, sizeof(hook_storage_t));
74 memset(&em_shm->to_active_hook_storage, 0, sizeof(hook_storage_t));
75 memset(&em_shm->while_idle_hook_storage, 0, sizeof(hook_storage_t));
76
77 em_shm->dispatch_enter_cb_tbl =
78 &em_shm->dispatch_enter_cb_storage.hook_tbl_storage[0];
80 &em_shm->dispatch_exit_cb_storage.hook_tbl_storage[0];
82 &em_shm->alloc_hook_storage.hook_tbl_storage[0];
84 &em_shm->free_hook_storage.hook_tbl_storage[0];
86 &em_shm->send_hook_storage.hook_tbl_storage[0];
87
94
95 em_shm->dispatch_enter_cb_storage.idx = 0;
96 em_shm->dispatch_exit_cb_storage.idx = 0;
97 em_shm->alloc_hook_storage.idx = 0;
98 em_shm->free_hook_storage.idx = 0;
99 em_shm->send_hook_storage.idx = 0;
100
104
105 odp_ticketlock_init(&em_shm->dispatch_enter_cb_storage.lock);
106 odp_ticketlock_init(&em_shm->dispatch_exit_cb_storage.lock);
107 odp_ticketlock_init(&em_shm->alloc_hook_storage.lock);
108 odp_ticketlock_init(&em_shm->free_hook_storage.lock);
109 odp_ticketlock_init(&em_shm->send_hook_storage.lock);
110
111 odp_ticketlock_init(&em_shm->to_idle_hook_storage.lock);
112 odp_ticketlock_init(&em_shm->to_active_hook_storage.lock);
113 odp_ticketlock_init(&em_shm->while_idle_hook_storage.lock);
114
116 if (api_hooks->alloc_hook) {
117 hook_fn.alloc = api_hooks->alloc_hook;
118 stat = hook_register(ALLOC_HOOK, hook_fn);
119 if (unlikely(stat != EM_OK))
120 return stat;
121 }
122 if (api_hooks->free_hook) {
123 hook_fn.free = api_hooks->free_hook;
124 stat = hook_register(FREE_HOOK, hook_fn);
125 if (unlikely(stat != EM_OK))
126 return stat;
127 }
128 if (api_hooks->send_hook) {
129 hook_fn.send = api_hooks->send_hook;
130 stat = hook_register(SEND_HOOK, hook_fn);
131 if (unlikely(stat != EM_OK))
132 return stat;
133 }
134 }
135
137 if (idle_hooks->to_idle_hook) {
138 hook_fn.to_idle = idle_hooks->to_idle_hook;
139 stat = hook_register(TO_IDLE_HOOK, hook_fn);
140 if (unlikely(stat != EM_OK))
141 return stat;
142 }
143 if (idle_hooks->to_active_hook) {
144 hook_fn.to_active = idle_hooks->to_active_hook;
145 stat = hook_register(TO_ACTIVE_HOOK, hook_fn);
146 if (unlikely(stat != EM_OK))
147 return stat;
148 }
149 if (idle_hooks->while_idle_hook) {
150 hook_fn.while_idle = idle_hooks->while_idle_hook;
151 stat = hook_register(WHILE_IDLE_HOOK, hook_fn);
152 if (unlikely(stat != EM_OK))
153 return stat;
154 }
155 }
156
157 return EM_OK;
158}
159
161hook_register(uint8_t hook_type, hook_fn_t hook_fn)
162{
163 hook_storage_t *hook_storage;
164 const hook_tbl_t *hook_tbl;
165 hook_tbl_t *next_tbl;
166 hook_tbl_t **active_tbl_ptr;
167 int idx;
168 int next_idx;
169 int i;
170
171 /* Get the em_shm hook table and hook storage to update */
172 active_tbl_ptr = get_hook_tbl(hook_type, &hook_storage/*out*/);
173 if (unlikely(active_tbl_ptr == NULL))
174 return EM_ERR_BAD_ID;
175
176 odp_ticketlock_lock(&hook_storage->lock);
177
178 /* TODO: Check that no thread is still using the new memory area */
179
180 idx = hook_storage->idx;
181 next_idx = idx + 1;
182 if (next_idx >= API_HOOKS_MAX_TBL_SIZE)
183 next_idx = 0;
184 hook_tbl = &hook_storage->hook_tbl_storage[idx];
185 next_tbl = &hook_storage->hook_tbl_storage[next_idx];
186
187 /*
188 * Copy old callback functions and find the index
189 * of the new function pointer.
190 */
191 memcpy(next_tbl->tbl, hook_tbl->tbl, sizeof(next_tbl->tbl));
192
193 for (i = 0; i < EM_CALLBACKS_MAX; i++) {
194 if (next_tbl->tbl[i].void_hook == NULL)
195 break;
196 }
197 if (unlikely(i == EM_CALLBACKS_MAX)) {
198 odp_ticketlock_unlock(&hook_storage->lock);
199 return EM_ERR_ALLOC_FAILED;
200 }
201 /* Add new callback */
202 next_tbl->tbl[i] = hook_fn;
203
204 /* move the active hook tbl to the new tbl */
205 *active_tbl_ptr = next_tbl; /* em_shm->..._hook_tbl = next_tbl */
206
207 hook_storage->idx = next_idx;
208
209 odp_ticketlock_unlock(&hook_storage->lock);
210
211 return EM_OK;
212}
213
215hook_unregister(uint8_t hook_type, hook_fn_t hook_fn)
216{
217 hook_storage_t *hook_storage;
218 const hook_tbl_t *hook_tbl;
219 hook_tbl_t *next_tbl;
220 hook_tbl_t **active_tbl_ptr;
221 int idx;
222 int next_idx;
223 int ret;
224 int i;
225
226 active_tbl_ptr = get_hook_tbl(hook_type, &hook_storage/*out*/);
227 if (unlikely(active_tbl_ptr == NULL))
228 return EM_ERR_BAD_ID;
229
230 odp_ticketlock_lock(&hook_storage->lock);
231
232 /* TODO: Check that no thread is still using the new memory area */
233
234 idx = hook_storage->idx;
235 next_idx = idx + 1;
236 if (next_idx >= API_HOOKS_MAX_TBL_SIZE)
237 next_idx = 0;
238 hook_tbl = &hook_storage->hook_tbl_storage[idx];
239 next_tbl = &hook_storage->hook_tbl_storage[next_idx];
240
241 /*
242 * Copy old callback functions and try to find matching
243 * function pointer.
244 */
245 memcpy(next_tbl->tbl, hook_tbl->tbl, sizeof(next_tbl->tbl));
246
247 for (i = 0; i < EM_CALLBACKS_MAX; i++)
248 if (next_tbl->tbl[i].void_hook == hook_fn.void_hook)
249 break;
250 if (unlikely(i == EM_CALLBACKS_MAX)) {
251 odp_ticketlock_unlock(&hook_storage->lock);
252 return EM_ERR_NOT_FOUND;
253 }
254
255 /*
256 * Remove a pointer and move the following array entries backwards
257 * and set callback array pointer to the beginning of the new array.
258 */
259 next_tbl->tbl[i].void_hook = NULL;
260 ret = pack_hook_tbl(next_tbl, i);
261 if (unlikely(ret != 0)) {
262 odp_ticketlock_unlock(&hook_storage->lock);
263 return EM_ERR_BAD_POINTER;
264 }
265
266 /* move the active hook tbl to the new tbl */
267 *active_tbl_ptr = next_tbl; /* em_shm->..._hook_tbl = next_tbl */
268
269 hook_storage->idx = next_idx;
270
271 odp_ticketlock_unlock(&hook_storage->lock);
272
273 return EM_OK;
274}
275
276static hook_tbl_t **
277get_hook_tbl(const uint8_t hook_type, hook_storage_t **hook_storage /*out*/)
278{
279 hook_tbl_t **active_tbl_ptr;
280
281 switch (hook_type) {
282 case ALLOC_HOOK:
283 *hook_storage = &em_shm->alloc_hook_storage;
284 active_tbl_ptr = &em_shm->alloc_hook_tbl;
285 break;
286 case FREE_HOOK:
287 *hook_storage = &em_shm->free_hook_storage;
288 active_tbl_ptr = &em_shm->free_hook_tbl;
289 break;
290 case SEND_HOOK:
291 *hook_storage = &em_shm->send_hook_storage;
292 active_tbl_ptr = &em_shm->send_hook_tbl;
293 break;
294 case DISPATCH_CALLBACK_ENTER:
295 *hook_storage = &em_shm->dispatch_enter_cb_storage;
296 active_tbl_ptr = &em_shm->dispatch_enter_cb_tbl;
297 break;
298 case DISPATCH_CALLBACK_EXIT:
299 *hook_storage = &em_shm->dispatch_exit_cb_storage;
300 active_tbl_ptr = &em_shm->dispatch_exit_cb_tbl;
301 break;
302 case TO_IDLE_HOOK:
303 *hook_storage = &em_shm->to_idle_hook_storage;
304 active_tbl_ptr = &em_shm->to_idle_hook_tbl;
305 break;
306 case TO_ACTIVE_HOOK:
307 *hook_storage = &em_shm->to_active_hook_storage;
308 active_tbl_ptr = &em_shm->to_active_hook_tbl;
309 break;
310 case WHILE_IDLE_HOOK:
311 *hook_storage = &em_shm->while_idle_hook_storage;
312 active_tbl_ptr = &em_shm->while_idle_hook_tbl;
313 break;
314 default:
315 return NULL;
316 }
317
318 return active_tbl_ptr;
319}
320
321static inline int
322pack_hook_tbl(hook_tbl_t *const hook_tbl, unsigned int idx)
323{
324 hook_fn_t *const fn_tbl = hook_tbl->tbl;
325
326 if (unlikely(idx >= EM_CALLBACKS_MAX ||
327 fn_tbl[idx].void_hook != NULL))
328 return -1;
329
330 for (unsigned int i = idx; i < EM_CALLBACKS_MAX - 1; i++) {
331 if (fn_tbl[i + 1].void_hook != NULL) {
332 fn_tbl[i].void_hook = fn_tbl[i + 1].void_hook;
333 fn_tbl[i + 1].void_hook = NULL;
334 } else {
335 break;
336 }
337 }
338
339 return 0;
340}
em_shm_t * em_shm
#define EM_IDLE_HOOKS_ENABLE
#define EM_CALLBACKS_MAX
#define EM_API_HOOKS_ENABLE
#define EM_OK
uint32_t em_status_t
@ EM_ERR_NOT_FOUND
@ EM_ERR_BAD_ID
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_BAD_POINTER
em_api_hook_send_t send_hook
em_api_hook_alloc_t alloc_hook
em_api_hook_free_t free_hook
em_idle_hook_to_idle_t to_idle_hook
em_idle_hook_to_active_t to_active_hook
em_idle_hook_while_idle_t while_idle_hook
hook_tbl_t * alloc_hook_tbl
Definition em_mem.h:140
hook_storage_t while_idle_hook_storage
Definition em_mem.h:167
hook_storage_t to_active_hook_storage
Definition em_mem.h:165
hook_tbl_t * to_idle_hook_tbl
Definition em_mem.h:146
hook_tbl_t * to_active_hook_tbl
Definition em_mem.h:148
hook_storage_t to_idle_hook_storage
Definition em_mem.h:163
hook_tbl_t * while_idle_hook_tbl
Definition em_mem.h:150
hook_tbl_t * free_hook_tbl
Definition em_mem.h:142
hook_tbl_t * dispatch_exit_cb_tbl
Definition em_mem.h:138
hook_tbl_t * send_hook_tbl
Definition em_mem.h:144
odp_ticketlock_t lock
hook_tbl_t hook_tbl_storage[API_HOOKS_MAX_TBL_SIZE]