EM-ODP  3.7.0
Event Machine on ODP
event_machine_event_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 #include "em_include.h"
32 
33 /* per core (thread) state for em_event_group_get_next() */
34 static ENV_LOCAL unsigned int _egrp_tbl_iter_idx;
35 
36 em_event_group_t
38 {
39  em_event_group_t egrp;
40  event_group_elem_t *egrp_elem;
41 
42  egrp = event_group_alloc();
43  if (unlikely(egrp == EM_EVENT_GROUP_UNDEF)) {
44  INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_EVENT_GROUP_CREATE,
45  "Event group alloc failed!");
46  return EM_EVENT_GROUP_UNDEF;
47  }
48 
49  egrp_elem = event_group_elem_get(egrp);
50 
51  /* Alloc succeeded, return event group handle */
52  egrp_elem->ready = true; /* Set group ready for 'apply' */
53  return egrp;
54 }
55 
57 em_event_group_delete(em_event_group_t event_group)
58 {
59  em_status_t status;
60  event_group_elem_t *const egrp_elem =
61  event_group_elem_get(event_group);
62  egrp_counter_t egrp_count;
63  uint64_t count;
64 
65  RETURN_ERROR_IF(egrp_elem == NULL || !event_group_allocated(egrp_elem),
66  EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_DELETE,
67  "Invalid event group: %" PRI_EGRP "", event_group);
68 
69  egrp_count.all = EM_ATOMIC_GET(&egrp_elem->post.atomic);
70 
72  count = egrp_count.count;
73  else
74  count = egrp_count.all;
75 
77  EM_ESCOPE_EVENT_GROUP_DELETE,
78  "Event group:%" PRI_EGRP " count not zero!",
79  event_group);
80 
81  /* set num_notif = 0, ready = 0/false */
82  egrp_elem->all = 0;
83 
84  status = event_group_free(event_group);
85  RETURN_ERROR_IF(status != EM_OK,
86  status, EM_ESCOPE_EVENT_GROUP_DELETE,
87  "Event Group delete failed!");
88 
89  return EM_OK;
90 }
91 
93 em_event_group_apply(em_event_group_t event_group, int count,
94  int num_notif, const em_notif_t notif_tbl[])
95 {
96  uint64_t egrp_count;
97  em_status_t ret;
98 
99  event_group_elem_t *const egrp_elem =
100  event_group_elem_get(event_group);
101 
102  if (EM_CHECK_LEVEL > 0)
103  RETURN_ERROR_IF(egrp_elem == NULL || count <= 0,
104  EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_APPLY,
105  "Invalid args: event group:%" PRI_EGRP ", count:%d",
106  event_group, count);
107  if (EM_CHECK_LEVEL >= 2)
108  RETURN_ERROR_IF(!event_group_allocated(egrp_elem),
109  EM_ERR_NOT_CREATED, EM_ESCOPE_EVENT_GROUP_APPLY,
110  "Event group:%" PRI_EGRP " not created!", event_group);
111 
112  ret = check_notif_tbl(num_notif, notif_tbl);
113  RETURN_ERROR_IF(ret != EM_OK, ret, EM_ESCOPE_EVENT_GROUP_APPLY,
114  "Invalid notif cfg given!");
115 
117  egrp_count = egrp_elem->post.count;
118  else
119  egrp_count = egrp_elem->post.all;
120 
121  RETURN_ERROR_IF(egrp_count != 0 || !egrp_elem->ready,
122  EM_ERR_BAD_STATE, EM_ESCOPE_EVENT_GROUP_APPLY,
123  "Event group %" PRI_EGRP " currently in use! count: %i",
124  event_group, egrp_count);
125 
127  egrp_elem->post.count = count;
128  /* Event group generation increments when _apply() is called */
129  egrp_elem->post.gen++;
130  egrp_elem->pre.all = egrp_elem->post.all;
131  } else {
132  egrp_elem->post.all = count;
133  }
134 
135  egrp_elem->ready = false;
136  egrp_elem->num_notif = num_notif;
137 
138  for (int i = 0; i < num_notif; i++) {
139  egrp_elem->notif_tbl[i].event = notif_tbl[i].event;
140  egrp_elem->notif_tbl[i].queue = notif_tbl[i].queue;
141  egrp_elem->notif_tbl[i].egroup = notif_tbl[i].egroup;
142  }
143 
144  /* Sync mem */
145  env_sync_mem();
146 
147  return EM_OK;
148 }
149 
152 {
153  const em_locm_t *const locm = &em_locm;
154  em_event_group_t const egrp = em_event_group_current();
155  event_group_elem_t *egrp_elem = NULL;
156 
157  if (egrp != EM_EVENT_GROUP_UNDEF)
158  egrp_elem = locm->current.egrp_elem;
159 
160  RETURN_ERROR_IF(egrp_elem == NULL || egrp_elem->ready,
161  EM_ERR_BAD_ID, EM_ESCOPE_EVENT_GROUP_INCREMENT,
162  "No current event group (%" PRI_EGRP ") or not applied",
163  egrp);
164 
165  if (EM_CHECK_LEVEL >= 2)
166  RETURN_ERROR_IF(!event_group_allocated(egrp_elem),
167  EM_ERR_BAD_STATE, EM_ESCOPE_EVENT_GROUP_INCREMENT,
168  "Current event group in a bad state (%" PRI_EGRP ")",
169  egrp);
170 
172  EM_ATOMIC_ADD(&egrp_elem->post.atomic, count);
173  return EM_OK;
174  }
175 
176  egrp_counter_t current_count;
177  egrp_counter_t new_count;
178  /* Add to post counter before count is zero or generation mismatch */
179  do {
180  current_count.all = EM_ATOMIC_GET(&egrp_elem->post.atomic);
181 
182  RETURN_ERROR_IF(current_count.count <= 0 ||
183  current_count.gen != locm->current.egrp_gen,
185  EM_ESCOPE_EVENT_GROUP_INCREMENT,
186  "Expired event group (%" PRI_EGRP ")",
187  egrp);
188 
189  new_count = current_count;
190  new_count.count += count;
191  } while (!EM_ATOMIC_CMPSET(&egrp_elem->post.atomic,
192  current_count.all, new_count.all));
193 
194  /* Add to pre counter if generation matches */
195  do {
196  current_count.all = EM_ATOMIC_GET(&egrp_elem->pre.atomic);
197 
198  RETURN_ERROR_IF(current_count.gen != locm->current.egrp_gen,
200  EM_ESCOPE_EVENT_GROUP_INCREMENT,
201  "Expired event group (%" PRI_EGRP ")",
202  egrp);
203 
204  new_count = current_count;
205  new_count.count += count;
206  } while (!EM_ATOMIC_CMPSET(&egrp_elem->pre.atomic,
207  current_count.all, new_count.all));
208 
209  return EM_OK;
210 }
211 
212 int em_event_group_is_ready(em_event_group_t event_group)
213 {
214  const event_group_elem_t *egrp_elem =
215  event_group_elem_get(event_group);
216 
217  if (unlikely(EM_CHECK_LEVEL > 0 && egrp_elem == NULL)) {
218  INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_IS_READY,
219  "Invalid event group: %" PRI_EGRP "",
220  event_group);
221  return EM_FALSE;
222  }
223 
224  if (unlikely(EM_CHECK_LEVEL >= 2 && !event_group_allocated(egrp_elem))) {
225  INTERNAL_ERROR(EM_ERR_NOT_CREATED, EM_ESCOPE_EVENT_GROUP_IS_READY,
226  "Event group: %" PRI_EGRP " not created",
227  event_group);
228  return EM_FALSE;
229  }
230 
231  uint64_t count;
232 
234  count = egrp_elem->post.count;
235  else
236  count = egrp_elem->post.all;
237 
238  if (count == 0 && egrp_elem->ready)
239  return EM_TRUE;
240  else
241  return EM_FALSE;
242 }
243 
244 em_event_group_t
246 {
247  em_locm_t *const locm = &em_locm;
248 
250  return locm->current.egrp;
251 
252  if (locm->current.egrp == EM_EVENT_GROUP_UNDEF)
253  return EM_EVENT_GROUP_UNDEF;
254 
255  const event_group_elem_t *egrp_elem = locm->current.egrp_elem;
256  egrp_counter_t current;
257 
258  if (egrp_elem == NULL)
259  return EM_EVENT_GROUP_UNDEF;
260 
261  current.all = EM_ATOMIC_GET(&egrp_elem->post.atomic);
262 
263  if (locm->current.egrp_gen != current.gen || current.count <= 0)
265 
266  return locm->current.egrp;
267 }
268 
269 /**
270  * Helper to em_send_group().
271  * Send out of EM via event-chaining and a user-provided function
272  * 'event_send_device()' to another device
273  */
274 static inline em_status_t
275 send_external_egrp(em_event_t event, event_hdr_t *const ev_hdr,
276  em_queue_t queue, em_event_group_t event_group,
277  const event_group_elem_t *egrp_elem)
278 {
280  call_api_hooks_send(&event, 1, queue, event_group);
281 
282  em_status_t stat = send_chaining_egrp(event, ev_hdr, queue, egrp_elem);
283 
284  if (EM_CHECK_LEVEL == 0)
285  return stat;
286 
287  RETURN_ERROR_IF(stat != EM_OK, stat, EM_ESCOPE_SEND_GROUP,
288  "send_chaining_egrp: Q:%" PRI_QUEUE "", queue);
289  return EM_OK;
290 }
291 
292 /**
293  * Helper to em_send_multi().
294  * Send out of EM via event-chaining and a user-provided function
295  * 'event_send_device()' to another device
296  */
297 static inline int
298 send_external_egrp_multi(const em_event_t events[], event_hdr_t *ev_hdrs[], int num,
299  em_queue_t queue, em_event_group_t event_group,
300  const event_group_elem_t *egrp_elem)
301 {
303  call_api_hooks_send(events, num, queue, event_group);
304 
305  int num_sent = send_chaining_egrp_multi(events, ev_hdrs, num,
306  queue, egrp_elem);
307  if (EM_CHECK_LEVEL > 0 && unlikely(num_sent != num)) {
308  INTERNAL_ERROR(EM_ERR_OPERATION_FAILED, EM_ESCOPE_SEND_GROUP_MULTI,
309  "send_chaining_egrp_multi: req:%d, sent:%d",
310  num, num_sent);
311  }
312 
313  return num_sent;
314 }
315 
316 /**
317  * Helper to em_send_group().
318  * Send to an EM internal queue.
319  */
320 static inline em_status_t
321 send_internal_egrp(em_event_t event, event_hdr_t *ev_hdr, em_queue_t queue,
322  em_event_group_t event_group)
323 {
324  const queue_elem_t *q_elem = queue_elem_get(queue);
325  em_status_t stat;
326 
327  RETURN_ERROR_IF(EM_CHECK_LEVEL > 0 && !q_elem,
328  EM_ERR_BAD_ARG, EM_ESCOPE_SEND_GROUP,
329  "Invalid queue:%" PRI_QUEUE "", queue);
330  RETURN_ERROR_IF(EM_CHECK_LEVEL >= 2 && !queue_allocated(q_elem),
331  EM_ERR_BAD_STATE, EM_ESCOPE_SEND_GROUP,
332  "Invalid queue:%" PRI_QUEUE "", queue);
333 
334  /* Buffer events sent from EO-start to scheduled queues */
335  if (unlikely(em_locm.start_eo_elem && q_elem->flags.scheduled)) {
336  /*
337  * em_send_group() called from within an EO-start function:
338  * all events sent to scheduled queues will be buffered
339  * and sent when the EO-start operation completes.
340  */
341  if (esv_enabled())
342  evstate_usr2em(event, ev_hdr, EVSTATE__SEND_EGRP);
343 
344  int num_sent = eo_start_buffer_events(&event, 1, queue);
345 
346  if (unlikely(num_sent != 1)) {
348  goto error_return;
349  }
350 
351  return EM_OK; /* Success */
352  }
353 
355  call_api_hooks_send(&event, 1, queue, event_group);
356 
357  /*
358  * Normal send to a queue on this device
359  */
360  if (esv_enabled())
361  evstate_usr2em(event, ev_hdr, EVSTATE__SEND_EGRP);
362 
363  switch (q_elem->type) {
367  stat = send_event(event, q_elem);
368  break;
370  stat = queue_unsched_enqueue(event, q_elem);
371  break;
372  case EM_QUEUE_TYPE_LOCAL:
373  stat = send_local(event, q_elem);
374  break;
375  default:
376  stat = EM_ERR_NOT_FOUND;
377  break;
378  }
379 
380  if (likely(stat == EM_OK))
381  return EM_OK; /* Success */
382 
383 error_return:
384  if (esv_enabled())
385  evstate_usr2em_revert(event, ev_hdr, EVSTATE__SEND_EGRP__FAIL);
386 
387  if (EM_CHECK_LEVEL == 0)
388  return stat;
389  stat = INTERNAL_ERROR(stat, EM_ESCOPE_SEND_GROUP,
390  "send egrp: Q:%" PRI_QUEUE " type:%" PRI_QTYPE "",
391  queue, q_elem->type);
392  return stat;
393 }
394 
395 /**
396  * Helper to em_send_multi().
397  * Send to an EM internal queue.
398  */
399 static inline int
400 send_internal_egrp_multi(const em_event_t events[], event_hdr_t *ev_hdrs[],
401  int num, em_queue_t queue, em_event_group_t event_group)
402 {
403  const queue_elem_t *q_elem = queue_elem_get(queue);
404  int num_sent;
405 
406  if (EM_CHECK_LEVEL > 0 && unlikely(!q_elem)) {
407  INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_SEND_GROUP_MULTI,
408  "Invalid queue:%" PRI_QUEUE "", queue);
409  return 0;
410  }
411  if (EM_CHECK_LEVEL >= 2 && unlikely(!queue_allocated(q_elem))) {
412  INTERNAL_ERROR(EM_ERR_BAD_STATE, EM_ESCOPE_SEND_GROUP_MULTI,
413  "Invalid queue:%" PRI_QUEUE "", queue);
414  return 0;
415  }
416 
417  /* Buffer events sent from EO-start to scheduled queues */
418  if (unlikely(em_locm.start_eo_elem && q_elem->flags.scheduled)) {
419  /*
420  * em_send_group_multi() called from within an EO-start
421  * function: all events sent to scheduled queues will be
422  * buffered and sent when the EO-start operation completes.
423  */
424  if (esv_enabled())
425  evstate_usr2em_multi(events, ev_hdrs, num,
426  EVSTATE__SEND_EGRP_MULTI);
427  num_sent = eo_start_buffer_events(events, num, queue);
428 
429  if (unlikely(num_sent != num))
430  goto error_return;
431 
432  return num_sent; /* Success */
433  }
434 
436  call_api_hooks_send(events, num, queue, event_group);
437 
438  /*
439  * Normal send to a queue on this device
440  */
441  if (esv_enabled())
442  evstate_usr2em_multi(events, ev_hdrs, num, EVSTATE__SEND_EGRP_MULTI);
443 
444  switch (q_elem->type) {
448  num_sent = send_event_multi(events, num, q_elem);
449  break;
450  case EM_QUEUE_TYPE_LOCAL:
451  num_sent = send_local_multi(events, num, q_elem);
452  break;
453  default:
454  num_sent = 0;
455  break;
456  }
457 
458  if (likely(num_sent == num))
459  return num_sent; /* Success */
460 
461 error_return:
462  if (esv_enabled())
463  evstate_usr2em_revert_multi(&events[num_sent],
464  &ev_hdrs[num_sent],
465  num - num_sent,
466  EVSTATE__SEND_EGRP_MULTI__FAIL);
467  if (EM_CHECK_LEVEL > 0)
468  INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_SEND_GROUP_MULTI,
469  "send-egrp-multi failed: req:%d, sent:%d",
470  num, num_sent);
471  return num_sent;
472 }
473 
474 em_status_t em_send_group(em_event_t event, em_queue_t queue,
475  em_event_group_t event_group)
476 {
477  const event_group_elem_t *egrp_elem = event_group_elem_get(event_group);
478  const bool is_external = queue_external(queue);
479 
481  EM_ERR_BAD_ARG, EM_ESCOPE_SEND_GROUP, "Invalid event");
483  event_group != EM_EVENT_GROUP_UNDEF && !egrp_elem,
484  EM_ERR_NOT_FOUND, EM_ESCOPE_SEND_GROUP,
485  "Invalid event group:%" PRI_EGRP "", event_group);
486  RETURN_ERROR_IF(EM_CHECK_LEVEL >= 2 && event_group != EM_EVENT_GROUP_UNDEF &&
487  !event_group_allocated(egrp_elem),
488  EM_ERR_NOT_CREATED, EM_ESCOPE_SEND_GROUP,
489  "Event group:%" PRI_EGRP " not created", event_group);
490  /*
491  * Verify that event references are not used with event groups.
492  * Cannot save the event group into an event header shared between
493  * all the references.
494  */
496  event_group != EM_EVENT_GROUP_UNDEF && event_has_ref(event),
497  EM_ERR_BAD_CONTEXT, EM_ESCOPE_SEND_GROUP,
498  "Event has references: can't use references with event groups");
499 
500  event_hdr_t *ev_hdr = event_to_hdr(event);
501 
503  EM_ERR_BAD_ARG, EM_ESCOPE_SEND_GROUP, "Timer-ring event can't be sent");
504 
505  /* Store the event group information in the event header */
506  if (egrp_elem) {
507  ev_hdr->egrp = egrp_elem->event_group;
509  ev_hdr->egrp_gen = event_group_gen_get(egrp_elem);
510  } else {
511  ev_hdr->egrp = EM_EVENT_GROUP_UNDEF;
512  }
513 
514  /*
515  * External queue belongs to another EM instance, send out via EMC/BIP
516  */
517  if (is_external)
518  return send_external_egrp(event, ev_hdr, queue,
519  event_group, egrp_elem);
520  /*
521  * Queue belongs to this EM instance
522  */
523  return send_internal_egrp(event, ev_hdr, queue, event_group);
524 }
525 
526 /*
527  * em_send_group_multi() helper: check function arguments
528  */
529 static inline em_status_t
530 send_grpmulti_check(const em_event_t events[], int num,
531  em_event_group_t event_group,
532  const event_group_elem_t *egrp_elem)
533 {
534  if (EM_CHECK_LEVEL > 0 &&
535  unlikely(!events || num <= 0 ||
536  (event_group != EM_EVENT_GROUP_UNDEF && !egrp_elem)))
537  return EM_ERR_BAD_ARG;
538 
539  if (EM_CHECK_LEVEL >= 2 &&
540  unlikely(event_group != EM_EVENT_GROUP_UNDEF &&
541  !event_group_allocated(egrp_elem)))
542  return EM_ERR_NOT_CREATED;
543 
544  if (EM_CHECK_LEVEL >= 3) {
545  int i;
546 
547  for (i = 0; i < num && events[i] != EM_EVENT_UNDEF; i++)
548  ;
549  if (unlikely(i != num))
550  return EM_ERR_BAD_POINTER;
551  }
552 
553  return EM_OK;
554 }
555 
556 int em_send_group_multi(const em_event_t events[], int num, em_queue_t queue,
557  em_event_group_t event_group)
558 {
559  const event_group_elem_t *egrp_elem = event_group_elem_get(event_group);
560  const bool is_external = queue_external(queue);
561  event_hdr_t *ev_hdrs[num];
562 
563  em_status_t err = send_grpmulti_check(events, num,
564  event_group, egrp_elem);
565  if (unlikely(err != EM_OK)) {
566  INTERNAL_ERROR(err, EM_ESCOPE_SEND_GROUP_MULTI,
567  "Invalid args: events:%p num:%d event_group:%" PRI_EGRP "",
568  events, num, queue, event_group);
569  return 0;
570  }
571 
572  /*
573  * Verify that event references are not used with event groups.
574  * Cannot save the event group into an event header shared between
575  * all the references
576  */
577  if (unlikely(EM_CHECK_LEVEL >= 3 && event_group != EM_EVENT_GROUP_UNDEF)) {
578  for (int i = 0; i < num; i++) {
579  if (likely(!event_has_ref(events[i])))
580  continue;
581 
582  INTERNAL_ERROR(EM_ERR_BAD_CONTEXT, EM_ESCOPE_SEND_GROUP_MULTI,
583  "event[%d] has references: can't use with event groups", i);
584  return 0;
585  }
586  }
587 
588  event_to_hdr_multi(events, ev_hdrs, num);
589 
590  /* check for invalid TIMER events */
591  if (EM_CHECK_LEVEL > 0) {
592  for (int i = 0; i < num; i++) {
593  if (unlikely(ev_hdrs[i]->event_type == EM_EVENT_TYPE_TIMER_IND)) {
594  INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_SEND_GROUP_MULTI,
595  "Timer-ring event[%d] can't be sent", i);
596  return 0;
597  }
598  }
599  }
600 
601  /* Store the event group information in the event header */
602  for (int i = 0; i < num; i++)
603  ev_hdrs[i]->egrp = event_group; /* can be EM_EVENT_GROUP_UNDEF*/
604 
605  if (EM_EVENT_GROUP_SAFE_MODE && egrp_elem) {
606  uint64_t egrp_gen = event_group_gen_get(egrp_elem);
607 
608  for (int i = 0; i < num; i++)
609  ev_hdrs[i]->egrp_gen = egrp_gen;
610  }
611 
612  /*
613  * External queue belongs to another EM instance, send out via EMC/BIP
614  */
615  if (is_external)
616  return send_external_egrp_multi(events, ev_hdrs, num, queue,
617  event_group, egrp_elem);
618  /*
619  * Queue belongs to this EM instance
620  */
621  return send_internal_egrp_multi(events, ev_hdrs, num, queue, event_group);
622 }
623 
624 void
626 {
627  em_locm_t *const locm = &em_locm;
628  const em_event_group_t event_group = em_event_group_current();
629 
630  if (unlikely(invalid_egrp(event_group)))
631  return;
632 
633  /*
634  * Atomically decrement the event group count.
635  * If new count is zero, send notification events.
636  */
637  event_group_count_decrement(locm->current.rcv_multi_cnt);
638 
640  locm->current.egrp_elem = NULL;
641 }
642 
644 em_event_group_assign(em_event_group_t event_group)
645 {
646  em_locm_t *const locm = &em_locm;
647  event_group_elem_t *const egrp_elem =
648  event_group_elem_get(event_group);
649 
650  if (EM_CHECK_LEVEL > 0)
651  RETURN_ERROR_IF(egrp_elem == NULL,
652  EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_ASSIGN,
653  "Invalid event group: %" PRI_EGRP "", event_group);
654 
655  if (EM_CHECK_LEVEL >= 2)
656  RETURN_ERROR_IF(!event_group_allocated(egrp_elem),
657  EM_ERR_NOT_CREATED, EM_ESCOPE_EVENT_GROUP_ASSIGN,
658  "Invalid event group: %" PRI_EGRP "", event_group);
659 
661  EM_ERR_BAD_CONTEXT, EM_ESCOPE_EVENT_GROUP_ASSIGN,
662  "Cannot assign event group %" PRI_EGRP ",\n"
663  "event already belongs to event group %" PRI_EGRP "",
664  event_group, locm->current.egrp);
665 
666  RETURN_ERROR_IF(egrp_elem->ready,
667  EM_ERR_BAD_STATE, EM_ESCOPE_EVENT_GROUP_ASSIGN,
668  "Cannot assign event group %" PRI_EGRP ".\n"
669  "Event group has not been applied", event_group);
670 
671  locm->current.egrp = event_group;
672  locm->current.egrp_elem = egrp_elem;
673 
675  locm->current.egrp_gen = egrp_elem->post.gen;
676 
677  return EM_OK;
678 }
679 
680 /*
681  * Abort is successful if generation can be incremented before post_count
682  * reaches zero.
683  */
685 em_event_group_abort(em_event_group_t event_group)
686 {
687  event_group_elem_t *const egrp_elem =
688  event_group_elem_get(event_group);
689 
690  if (EM_CHECK_LEVEL > 0)
691  RETURN_ERROR_IF(egrp_elem == NULL,
692  EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_ABORT,
693  "Invalid event group: %" PRI_EGRP "", event_group);
694 
695  if (EM_CHECK_LEVEL >= 2)
696  RETURN_ERROR_IF(!event_group_allocated(egrp_elem),
697  EM_ERR_NOT_CREATED, EM_ESCOPE_EVENT_GROUP_ABORT,
698  "Event group: %" PRI_EGRP " not created", event_group);
699 
701  RETURN_ERROR_IF(egrp_elem->post.all <= 0,
702  EM_ERR_BAD_STATE, EM_ESCOPE_EVENT_GROUP_ABORT,
703  "Event group abort too late, notifs already sent");
704  egrp_elem->post.all = 0;
705  /* mark group ready for new apply and stop notifs */
706  egrp_elem->ready = true;
707  return EM_OK;
708  }
709 
710  egrp_counter_t current_count;
711  egrp_counter_t new_count;
712 
713  /* Attempt to set count to zero before count reaches zero */
714  do {
715  current_count.all = EM_ATOMIC_GET(&egrp_elem->post.atomic);
716 
717  RETURN_ERROR_IF(current_count.count <= 0,
718  EM_ERR_BAD_STATE, EM_ESCOPE_EVENT_GROUP_ABORT,
719  "Event group abort late, notifs already sent");
720  new_count = current_count;
721  new_count.count = 0;
722  } while (!EM_ATOMIC_CMPSET(&egrp_elem->post.atomic,
723  current_count.all, new_count.all));
724  /*
725  * Change pre_count also to prevent expired event group events
726  * from reaching receive function.
727  */
728  EM_ATOMIC_SET(&egrp_elem->pre.atomic, new_count.all);
729  /* Ready for new apply */
730  egrp_elem->ready = true;
731 
732  return EM_OK;
733 }
734 
735 int em_event_group_get_notif(em_event_group_t event_group,
736  int max_notif, em_notif_t notif_tbl[])
737 {
738  const event_group_elem_t *egrp_elem =
739  event_group_elem_get(event_group);
740  int num_notif = 0; /* return value */
741 
742  if (EM_CHECK_LEVEL > 0 &&
743  unlikely(egrp_elem == NULL || max_notif < 0)) {
744  INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_EVENT_GROUP_GET_NOTIF,
745  "Invalid args: evgrp:%" PRI_EGRP ", notifs:%d",
746  event_group, max_notif);
747  return 0;
748  }
749 
750  if (unlikely(EM_CHECK_LEVEL >= 2 && !event_group_allocated(egrp_elem))) {
751  INTERNAL_ERROR(EM_ERR_NOT_CREATED, EM_ESCOPE_EVENT_GROUP_GET_NOTIF,
752  "Event group:%" PRI_EGRP " not created",
753  event_group, max_notif);
754  return 0;
755  }
756 
757  if (unlikely(max_notif == 0))
758  return 0;
759 
760  if (unlikely(notif_tbl == NULL)) {
762  EM_ESCOPE_EVENT_GROUP_GET_NOTIF,
763  "Invalid notif_tbl[] given");
764  return 0;
765  }
766 
767  if (!egrp_elem->ready) {
768  num_notif = max_notif < egrp_elem->num_notif ?
769  max_notif : egrp_elem->num_notif;
770 
771  for (int i = 0; i < num_notif; i++) {
772  notif_tbl[i].event = egrp_elem->notif_tbl[i].event;
773  notif_tbl[i].queue = egrp_elem->notif_tbl[i].queue;
774  notif_tbl[i].egroup = egrp_elem->notif_tbl[i].egroup;
775  }
776  }
777 
778  return num_notif;
779 }
780 
781 em_event_group_t
782 em_event_group_get_first(unsigned int *num)
783 {
784  const event_group_elem_t *const egrp_elem_tbl =
785  em_shm->event_group_tbl.egrp_elem;
786  const event_group_elem_t *egrp_elem = &egrp_elem_tbl[0];
787  const unsigned int egrp_count = event_group_count();
788 
789  _egrp_tbl_iter_idx = 0; /* reset iteration */
790 
791  if (num)
792  *num = egrp_count;
793 
794  if (egrp_count == 0) {
795  _egrp_tbl_iter_idx = EM_MAX_EVENT_GROUPS; /* UNDEF=_get_next()*/
796  return EM_EVENT_GROUP_UNDEF;
797  }
798 
799  /* find first */
800  while (!event_group_allocated(egrp_elem)) {
801  _egrp_tbl_iter_idx++;
802  if (_egrp_tbl_iter_idx >= EM_MAX_EVENT_GROUPS)
803  return EM_EVENT_GROUP_UNDEF;
804  egrp_elem = &egrp_elem_tbl[_egrp_tbl_iter_idx];
805  }
806 
807  return egrp_idx2hdl(_egrp_tbl_iter_idx);
808 }
809 
810 em_event_group_t
812 {
813  if (_egrp_tbl_iter_idx >= EM_MAX_EVENT_GROUPS - 1)
814  return EM_EVENT_GROUP_UNDEF;
815 
816  _egrp_tbl_iter_idx++;
817 
818  const event_group_elem_t *const egrp_elem_tbl =
819  em_shm->event_group_tbl.egrp_elem;
820  const event_group_elem_t *egrp_elem =
821  &egrp_elem_tbl[_egrp_tbl_iter_idx];
822 
823  /* find next */
824  while (!event_group_allocated(egrp_elem)) {
825  _egrp_tbl_iter_idx++;
826  if (_egrp_tbl_iter_idx >= EM_MAX_EVENT_GROUPS)
827  return EM_EVENT_GROUP_UNDEF;
828  egrp_elem = &egrp_elem_tbl[_egrp_tbl_iter_idx];
829  }
830 
831  return egrp_idx2hdl(_egrp_tbl_iter_idx);
832 }
833 
834 uint64_t em_event_group_to_u64(em_event_group_t event_group)
835 {
836  return (uint64_t)event_group;
837 }
em_event_group_get_notif
int em_event_group_get_notif(em_event_group_t event_group, int max_notif, em_notif_t notif_tbl[])
Definition: event_machine_event_group.c:735
EM_OK
#define EM_OK
Definition: event_machine_types.h:329
em_notif_t::queue
em_queue_t queue
Definition: event_machine_types.h:270
EM_ERR_NOT_CREATED
@ EM_ERR_NOT_CREATED
Definition: event_machine_hw_types.h:274
event_group_elem_t::event_group
em_event_group_t event_group
Definition: em_event_group_types.h:92
EM_EVENT_UNDEF
#define EM_EVENT_UNDEF
Definition: event_machine_types.h:62
event_hdr::egrp_gen
int32_t egrp_gen
Definition: em_event_types.h:260
EM_API_HOOKS_ENABLE
#define EM_API_HOOKS_ENABLE
Definition: event_machine_config.h:182
EM_QUEUE_TYPE_PARALLEL
@ EM_QUEUE_TYPE_PARALLEL
Definition: event_machine_hw_types.h:117
em_event_group_delete
em_status_t em_event_group_delete(em_event_group_t event_group)
Definition: event_machine_event_group.c:57
evstate_usr2em_revert_multi
void evstate_usr2em_revert_multi(const em_event_t ev_tbl[], event_hdr_t *const ev_hdr_tbl[], const int num, const uint16_t api_op)
Definition: em_event_state.c:1018
event_hdr::event_type
em_event_type_t event_type
Definition: em_event_types.h:241
queue_elem_t::type
uint8_t type
Definition: em_queue_types.h:216
em_locm
ENV_LOCAL em_locm_t em_locm
evstate_usr2em_revert
void evstate_usr2em_revert(em_event_t event, event_hdr_t *const ev_hdr, const uint16_t api_op)
Definition: em_event_state.c:999
em_locm_t::current
em_locm_current_t current
Definition: em_mem.h:190
EM_ERR_ALLOC_FAILED
@ EM_ERR_ALLOC_FAILED
Definition: event_machine_hw_types.h:287
EM_ERR_LIB_FAILED
@ EM_ERR_LIB_FAILED
Definition: event_machine_hw_types.h:291
EM_EVENT_GROUP_SAFE_MODE
#define EM_EVENT_GROUP_SAFE_MODE
Definition: event_machine_config.h:303
EM_QUEUE_TYPE_ATOMIC
@ EM_QUEUE_TYPE_ATOMIC
Definition: event_machine_hw_types.h:112
eo_start_buffer_events
int eo_start_buffer_events(const em_event_t events[], int num, em_queue_t queue)
Definition: em_eo.c:412
em_send_group_multi
int em_send_group_multi(const em_event_t events[], int num, em_queue_t queue, em_event_group_t event_group)
Definition: event_machine_event_group.c:556
check_notif_tbl
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.
Definition: em_internal_event.c:477
em_send_group
em_status_t em_send_group(em_event_t event, em_queue_t queue, em_event_group_t event_group)
Definition: event_machine_event_group.c:474
ODP_PACKED::egrp_elem
event_group_elem_t * egrp_elem
Definition: em_mem.h:180
em_event_group_is_ready
int em_event_group_is_ready(em_event_group_t event_group)
Definition: event_machine_event_group.c:212
EM_QUEUE_TYPE_UNSCHEDULED
@ EM_QUEUE_TYPE_UNSCHEDULED
Definition: event_machine_hw_types.h:127
event_hdr
Definition: em_event_types.h:184
EM_MAX_EVENT_GROUPS
#define EM_MAX_EVENT_GROUPS
Definition: event_machine_config.h:161
EM_TRUE
#define EM_TRUE
Definition: event_machine_types.h:53
EM_ERR_BAD_CONTEXT
@ EM_ERR_BAD_CONTEXT
Definition: event_machine_hw_types.h:269
em_event_group_create
em_event_group_t em_event_group_create(void)
Definition: event_machine_event_group.c:37
event_group_elem_t::num_notif
int num_notif
Definition: em_event_group_types.h:83
em_event_group_get_first
em_event_group_t em_event_group_get_first(unsigned int *num)
Definition: event_machine_event_group.c:782
em_event_group_apply
em_status_t em_event_group_apply(em_event_group_t event_group, int count, int num_notif, const em_notif_t notif_tbl[])
Definition: event_machine_event_group.c:93
em_event_group_processing_end
void em_event_group_processing_end(void)
Definition: event_machine_event_group.c:625
RETURN_ERROR_IF
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition: em_error.h:50
egrp_counter_t::gen
int32_t gen
Definition: em_event_group_types.h:52
EM_ERR_BAD_ID
@ EM_ERR_BAD_ID
Definition: event_machine_hw_types.h:265
ODP_PACKED::egrp
em_event_group_t egrp
Definition: em_mem.h:178
INTERNAL_ERROR
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
em_event_group_to_u64
uint64_t em_event_group_to_u64(em_event_group_t event_group)
Definition: event_machine_event_group.c:834
EM_FALSE
#define EM_FALSE
Definition: event_machine_types.h:54
em_event_group_current
em_event_group_t em_event_group_current(void)
Definition: event_machine_event_group.c:245
queue_elem_t::scheduled
uint8_t scheduled
Definition: em_queue_types.h:199
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
EM_QUEUE_TYPE_LOCAL
@ EM_QUEUE_TYPE_LOCAL
Definition: event_machine_hw_types.h:131
PRI_QUEUE
#define PRI_QUEUE
Definition: event_machine_types.h:109
EM_CHECK_LEVEL
#define EM_CHECK_LEVEL
Definition: event_machine_config.h:253
EM_ERR_OPERATION_FAILED
@ EM_ERR_OPERATION_FAILED
Definition: event_machine_hw_types.h:289
event_hdr::egrp
em_event_group_t egrp
Definition: em_event_types.h:265
event_group_elem_t::all
uint64_t all
Definition: em_event_group_types.h:88
em_shm
em_shm_t * em_shm
Definition: event_machine_init.c:41
em_event_group_increment
em_status_t em_event_group_increment(int count)
Definition: event_machine_event_group.c:151
evstate_usr2em_multi
void evstate_usr2em_multi(const em_event_t ev_tbl[], event_hdr_t *const ev_hdr_tbl[], const int num, const uint16_t api_op)
Definition: em_event_state.c:1008
EM_EVENT_TYPE_TIMER_IND
@ EM_EVENT_TYPE_TIMER_IND
Definition: event_machine_hw_types.h:91
em_include.h
EM_QUEUE_TYPE_PARALLEL_ORDERED
@ EM_QUEUE_TYPE_PARALLEL_ORDERED
Definition: event_machine_hw_types.h:122
ODP_PACKED::egrp_gen
int32_t egrp_gen
Definition: em_mem.h:182
egrp_counter_t
Definition: em_event_group_types.h:47
event_group_elem_t::ready
bool ready
Definition: em_event_group_types.h:85
EM_ERR_NOT_FOUND
@ EM_ERR_NOT_FOUND
Definition: event_machine_hw_types.h:278
EM_ERR_BAD_POINTER
@ EM_ERR_BAD_POINTER
Definition: event_machine_hw_types.h:271
em_notif_t
Definition: event_machine_types.h:268
EM_ERR_BAD_ARG
@ EM_ERR_BAD_ARG
Definition: event_machine_hw_types.h:261
event_group_elem_t
Definition: em_event_group_types.h:64
em_locm_t
Definition: em_mem.h:188
em_event_group_assign
em_status_t em_event_group_assign(em_event_group_t event_group)
Definition: event_machine_event_group.c:644
evstate_usr2em
void evstate_usr2em(em_event_t event, event_hdr_t *const ev_hdr, const uint16_t api_op)
Definition: em_event_state.c:990
ENV_LOCAL
#define ENV_LOCAL
Definition: environment.h:57
EM_ERR_BAD_STATE
@ EM_ERR_BAD_STATE
Definition: event_machine_hw_types.h:263
em_event_group_abort
em_status_t em_event_group_abort(em_event_group_t event_group)
Definition: event_machine_event_group.c:685
em_event_group_get_next
em_event_group_t em_event_group_get_next(void)
Definition: event_machine_event_group.c:811
EM_EVENT_GROUP_UNDEF
#define EM_EVENT_GROUP_UNDEF
Definition: event_machine_types.h:141
em_notif_t::egroup
em_event_group_t egroup
Definition: event_machine_types.h:271
em_notif_t::event
em_event_t event
Definition: event_machine_types.h:269
queue_elem_t
Definition: em_queue_types.h:180
em_locm_t::start_eo_elem
eo_elem_t * start_eo_elem
Definition: em_mem.h:225
PRI_EGRP
#define PRI_EGRP
Definition: event_machine_types.h:143
egrp_counter_t::count
int32_t count
Definition: em_event_group_types.h:50
ODP_PACKED::rcv_multi_cnt
int rcv_multi_cnt
Definition: em_mem.h:172