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