EM-ODP  3.8.0-1
Event Machine on ODP
em_event_group.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, 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  *
34  * EM internal event group functions
35  *
36  */
37 
38 #ifndef EM_EVENT_GROUP_H_
39 #define EM_EVENT_GROUP_H_
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 #define invalid_egrp(event_group) \
46  ((unsigned int)egrp_hdl2idx((event_group)) >= EM_MAX_EVENT_GROUPS)
47 
49 event_group_init(event_group_tbl_t *const event_group_tbl, odp_stash_t *const event_group_pool);
50 
51 em_status_t event_group_term(void);
52 
53 em_event_group_t
54 event_group_alloc(void);
55 
57 event_group_free(em_event_group_t event_group);
58 
59 static inline int
60 event_group_allocated(const event_group_elem_t *egrp_elem)
61 {
62  return !egrp_elem->in_stash;
63 }
64 
65 static inline int
66 egrp_hdl2idx(const em_event_group_t event_group)
67 {
68  return (int)((uintptr_t)event_group - 1);
69 }
70 
71 static inline em_event_group_t
72 egrp_idx2hdl(const int event_group_idx)
73 {
74  return (em_event_group_t)(uintptr_t)(event_group_idx + 1);
75 }
76 
77 static inline event_group_elem_t *
78 event_group_elem_get(const em_event_group_t event_group)
79 {
80  const int egrp_idx = egrp_hdl2idx(event_group);
81  event_group_elem_t *egrp_elem;
82 
83  if (unlikely((uint32_t)egrp_idx > EM_MAX_EVENT_GROUPS - 1))
84  return NULL;
85 
86  egrp_elem = &em_shm->event_group_tbl.egrp_elem[egrp_idx];
87 
88  return egrp_elem;
89 }
90 
91 static inline uint64_t
92 event_group_gen_get(const event_group_elem_t *egrp_elem)
93 {
94  egrp_counter_t egrp_count;
95 
96  egrp_count.all = EM_ATOMIC_GET(&egrp_elem->post.atomic);
97 
98  return egrp_count.gen;
99 }
100 
101 /**
102  * Verifies event group state and updates pre count before setting core local
103  * event group. Sets group to undefined for excess and expired group events.
104  */
105 static inline void
106 set_local_safe(const em_event_group_t egrp, const int32_t egrp_gen,
107  const unsigned int decr)
108 {
109  em_locm_t *const locm = &em_locm;
110  uint64_t current_count;
111  egrp_counter_t new_count;
112  event_group_elem_t *const egrp_elem = event_group_elem_get(egrp);
113 
114  do {
115  current_count = EM_ATOMIC_GET(&egrp_elem->pre.atomic);
116  new_count.all = current_count;
117  new_count.count -= decr;
118  /* Check for excess and expired group events */
119  if (unlikely(new_count.count < 0 ||
120  new_count.gen != egrp_gen)) {
123  "Expired event group event received!");
125  return;
126  }
127  } while (!EM_ATOMIC_CMPSET(&egrp_elem->pre.atomic,
128  current_count, new_count.all));
129 
130  locm->current.egrp_gen = egrp_gen;
131  locm->current.egrp = egrp;
132  locm->current.egrp_elem = egrp_elem;
133 }
134 
135 /**
136  * Set core local event group.
137  *
138  * Validates event group if EM_EVENT_GROUP_SAFE_MODE is enabled.
139  *
140  * Only called by the EM-dispatcher before receive function.
141  */
142 static inline void
143 event_group_set_local(const em_event_group_t egrp, const int32_t egrp_gen,
144  const unsigned int decr)
145 {
146  if (egrp == EM_EVENT_GROUP_UNDEF)
147  return;
148 
149  /* event group is set: */
151  /* Group is validated before setting */
152  set_local_safe(egrp, egrp_gen, decr);
153  } else {
154  em_locm_t *const locm = &em_locm;
155 
156  locm->current.egrp_elem = event_group_elem_get(egrp);
157  locm->current.egrp = egrp;
158  }
159 }
160 
161 /**
162  * Updates event group counter safely. Generation and count must be valid.
163  */
164 static inline int64_t
165 count_decrement_safe(event_group_elem_t *const egrp_elem,
166  const unsigned int decr)
167 {
168  uint64_t current_count;
169  egrp_counter_t new_count;
170 
171  do {
172  current_count = EM_ATOMIC_GET(&egrp_elem->post.atomic);
173  new_count.all = current_count;
174  new_count.count -= decr;
175  /* Validate group state and generation before changing count */
176  if (unlikely(new_count.count < 0 ||
177  new_count.gen != em_locm.current.egrp_gen)) {
178  /* Suppress error if group is aborted */
179  if (!egrp_elem->ready)
182  "Expired grp event in post cnt!"
183  );
184  return -1;
185  }
186  } while (!EM_ATOMIC_CMPSET(&egrp_elem->post.atomic, current_count,
187  new_count.all));
188  return new_count.count;
189 }
190 
191 /**
192  * Decrements the event group count and sends notif events when group is done
193  *
194  * Only called by the EM-dispatcher after receive function.
195  */
196 static inline void
197 event_group_count_decrement(const unsigned int decr)
198 {
199  int64_t count;
200  event_group_elem_t *const egrp_elem = em_locm.current.egrp_elem;
201 
203  /* Validates group before updating counters */
204  count = count_decrement_safe(egrp_elem, decr);
205  } else {
206  count = EM_ATOMIC_SUB_RETURN(&egrp_elem->post.atomic, decr);
207 
208  if (unlikely(count < 0)) {
209  if (egrp_elem->ready) {
210  /* Counter should stay zero if aborted */
211  egrp_elem->post.all = 0;
212  return;
213  }
214 
215  INTERNAL_ERROR(EM_FATAL(EM_ERR_BAD_ID),
217  "Group count already 0!");
218  }
219  }
220 
221  if (count == 0) { /* Last event in the group */
222  /* Setting pre_count here does nothing as both counters should
223  * be zero. Only due to incorrect usage pre_count is other than
224  * zero when notif events are about to be sent.
225  */
227  egrp_elem->pre.count = 0;
228 
229  const int num_notif = egrp_elem->num_notif;
230  em_status_t ret;
231 
232  /* Copy notifications to local memory */
234 
235  for (int i = 0; i < num_notif; i++) {
236  notif_tbl[i].event = egrp_elem->notif_tbl[i].event;
237  notif_tbl[i].queue = egrp_elem->notif_tbl[i].queue;
238  notif_tbl[i].egroup = egrp_elem->notif_tbl[i].egroup;
239  }
240 
241  egrp_elem->ready = true; /* ready for 'apply' */
242  ret = send_notifs(num_notif, notif_tbl);
243  if (unlikely(ret != EM_OK))
245  "send notifs failed");
246  }
247 }
248 
249 static inline void
250 save_current_evgrp(em_event_group_t *save_egrp /*out*/,
251  event_group_elem_t **save_egrp_elem /*out*/,
252  int32_t *save_egrp_gen /*out*/)
253 {
254  const em_locm_t *locm = &em_locm;
255 
256  *save_egrp_elem = locm->current.egrp_elem;
257  *save_egrp = locm->current.egrp;
258  *save_egrp_gen = locm->current.egrp_gen;
259 }
260 
261 static inline void
262 restore_current_evgrp(const em_event_group_t saved_egrp,
263  event_group_elem_t *const saved_egrp_elem,
264  const int32_t saved_egrp_gen)
265 {
266  em_locm_t *const locm = &em_locm;
267 
268  locm->current.egrp_elem = saved_egrp_elem;
269  locm->current.egrp = saved_egrp;
270  locm->current.egrp_gen = saved_egrp_gen;
271 }
272 
273 unsigned int
274 event_group_count(void);
275 
276 /** Print information about all event groups */
277 void event_group_info_print(void);
278 
279 #ifdef __cplusplus
280 }
281 #endif
282 
283 #endif /* EM_EVENT_GROUP_H_ */
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
void event_group_info_print(void)
em_status_t send_notifs(const int num_notif, const em_notif_t notif_tbl[])
Helper func to send notifications events.
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_EVENT_GROUP_SAFE_MODE
#define EM_EVENT_GROUP_MAX_NOTIF
#define EM_MAX_EVENT_GROUPS
#define EM_ESCOPE_EVENT_GROUP_UPDATE
#define EM_OK
#define EM_EVENT_GROUP_UNDEF
uint32_t em_status_t
event_group_elem_t * egrp_elem
Definition: em_mem.h:180
int32_t egrp_gen
Definition: em_mem.h:182
em_event_group_t egrp
Definition: em_mem.h:178
em_locm_current_t current
Definition: em_mem.h:190
em_queue_t queue
em_event_group_t egroup
em_event_t event