EM-ODP  3.7.0
Event Machine on ODP
event_machine_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 #ifndef EVENT_MACHINE_EVENT_GROUP_H_
32 #define EVENT_MACHINE_EVENT_GROUP_H_
33 
34 #pragma GCC visibility push(default)
35 
36 /**
37  * @file
38  * @defgroup em_event_group Event group
39  * Event Machine fork-join helper.
40  * @{
41  *
42  * An event group can be used to trigger a join of parallel operations in the
43  * form of notification events. The number of parallel operations needs to be
44  * known in advance by the event group creator, but the separate event handlers
45  * don't necessarily need to know anything about the other related events.
46  * An event group is functionally a shared atomic counter decremented when each
47  * related event has been handled (EO-receive() returns). The notification
48  * events are automatically sent once the count reaches zero.
49  *
50  * There are two separate main usage patterns:
51  *
52  * Sender originated (original):
53  * ----------------------------
54  * 1. an event group is allocated with em_event_group_create().
55  *
56  * 2. the number of parallel events and the notifications are set with
57  * em_event_group_apply().
58  *
59  * 3. the (parallel) events are sent normally but using em_send_group() instead
60  * of em_send(). This tags the event with the given event group.
61  *
62  * 4. once received by a core the tag is used to switch core specific current
63  * event group to the one in the tag. The receiver EO handles the event
64  * normally (does not see any difference).
65  *
66  * 5. as the receive function returns the count of the current event group is
67  * decremented. If the count reaches zero (last event) the related
68  * notification event(s) are sent automatically and can trigger the next
69  * operation for the application.
70  *
71  * 6. the sequence can continue from step 2 for a new set of events if the
72  * event group is to be reused.
73  *
74  * Receiver originated (API 1.2):
75  * -----------------------------
76  * 1. an event group is created with em_event_group_create().
77  *
78  * 2. the number of parallel events and the notifications are set with
79  * em_event_group_apply().
80  *
81  * 3. during the processing of any received event that is not already tagged to
82  * belong to an event group, em_event_group_assign() can be used to set the
83  * current event group (a core local value). The rest is then equivalent to
84  * as if the event was originally sent to an event group.
85  *
86  * 4. as the receive function returns the count of the current event group is
87  * decremented. If the count reaches zero (last event) the related
88  * notification event(s) are sent automatically and can trigger the next
89  * operation for the application.
90  *
91  * 5. the sequence can continue from step 2 for a new set of events if the
92  * event group is to be reused.
93  *
94  * From an application (EO) point of view, an event group can get activated
95  * either by entering the EO receive with an event tagged to an event group or
96  * by explicitly calling em_event_group_assign. The current event group is core
97  * local and only one event group can be active (current) at a time.
98  * Assigning a received event that already is tagged to an event group, e.g.
99  * sent with em_send_group(), is not allowed unless the event group is
100  * deactivated first with em_event_group_processing_end().
101  * The current event group gets deactivated by exiting the EO receive function
102  * or by explicitly calling em_event_group_processing_end(). Deactivation means
103  * the count of the event group is decremented and if the count reaches zero
104  * the notification events are sent.
105  * The current event group is local to a core (dispatcher) and exists only
106  * within the EO receive function.
107  *
108  * Note, that event groups may only work with events that are to be handled by
109  * an EO, i.e. SW events.
110  *
111  * OpenEM implementation should internally use a generation count or other
112  * technique to make sure that em_event_group_abort() can stop a problem
113  * propagation, i.e. after a group is aborted (and applied a new count) any
114  * potential delayed event(s) from the previous cycle will not cause the new
115  * count to be decremented.
116  * The same should be valid for excess group events, i.e. when sending more
117  * than the applied count.
118  * To make it possible for the application to properly handle such problems,
119  * the implementation should pre-check incoming events and call error handler
120  * before giving the event to an EO. This makes it possible for the application
121  * to choose whether to drop those events (at the error handler) or let them be
122  * processed.
123  *
124  * It is not allowed to use event references with event groups since assigning
125  * an event that has references to an event group would assign all the
126  * references to the event group resulting in undefined behaviour. E.g. using
127  * em_send_group()/em_send_group_multi() to send a reference is wrong.
128  */
129 
130 #ifdef __cplusplus
131 extern "C" {
132 #endif
133 
136 
137 /**
138  * Create a new event group for fork-join.
139  *
140  * The amount of simultaneous event groups can be limited.
141  *
142  * @return The new event group or EM_EVENT_GROUP_UNDEF if no event group is
143  * available.
144  *
145  * @see em_event_group_delete(), em_event_group_apply()
146  */
147 em_event_group_t em_event_group_create(void);
148 
149 /**
150  * Delete (unallocate) an event group.
151  *
152  * An event group must not be deleted before it has been completed
153  * (count reached zero) or aborted. A created but never applied event group
154  * can be deleted.
155  *
156  * @param event_group Event group to delete
157  *
158  * @return EM_OK if successful.
159  *
160  * @see em_event_group_create(), em_event_group_abort()
161  */
162 em_status_t em_event_group_delete(em_event_group_t event_group);
163 
164 /**
165  * Apply event group configuration.
166  *
167  * This function sets the event count and notification parameters for the event
168  * group. After it returns, events sent or assigned to the event group are
169  * counted against the current count value. Notification events are sent when
170  * all (counted) events have been processed (count is decremented at EO receive
171  * return or by calling em_event_group_processing_end()). A new apply call is
172  * needed to re-use the event group for another cycle (with a new count and
173  * notifications).
174  *
175  * Notification events can optionally be sent to/tagged with another event
176  * group but not with the same event group that triggered the notifications,
177  * see em_notif_t for more.
178  *
179  * @attention em_event_group_apply() can only be used on a newly created event
180  * group or when the previous cycle is completed or successfully aborted.
181  * Application can use em_event_group_is_ready() to detect whether apply is
182  * allowed but would normally use a notification to setup a new cycle
183  * (implementation must make sure that when any of the notifications is
184  * received the group is ready for new apply).
185  *
186  * Apply should only be called once per group cycle.
187  *
188  * @param event_group Event group
189  * @param count Number of events in the group (positive integer)
190  * @param num_notif Number of notification events to send
191  * @param notif_tbl Table of notifications (events and target queues)
192  *
193  * @return EM_OK if successful.
194  *
195  * @see em_event_group_create(), em_send_group(), em_event_group_is_ready(),
196  * em_notif_t
197  */
198 em_status_t em_event_group_apply(em_event_group_t event_group, int count,
199  int num_notif, const em_notif_t notif_tbl[]);
200 
201 /**
202  * Increment the current event group count.
203  *
204  * Increments the event count of the currently active event group (received or
205  * assigned event). Enables sending new events into the current event group.
206  * The event count cannot be decremented and this will fail if there is no
207  * current event group.
208  *
209  * @param count Number of events to add to the event group (positive integer)
210  *
211  * @return EM_OK if successful.
212  *
213  * @see em_send_group(), em_event_group_apply()
214  */
216 
217 /**
218  * Checks if the event group is ready for 'apply'.
219  *
220  * Returns EM_TRUE (1) if the given event group is ready, i.e. the user can do
221  * em_event_group_apply() again. A better alternative to this is to use a
222  * related notification event to re-use the event group (apply can always be
223  * used when handling a notification event from the event group).
224  *
225  * An event group that has been applied a count but no events sent is not
226  * considered 'ready for apply'. If a change is needed the group has to be
227  * aborted and then re-applied.
228  *
229  * Return value EM_TRUE does not guarantee all notifications are received nor
230  * handled, but the event group count has reached zero and the event group
231  * is ready for a new apply.
232  *
233  * @param event_group Event group
234  *
235  * @return EM_TRUE if the given event group is ready for apply
236  *
237  * @see em_event_group_create(), em_event_group_apply()
238  */
239 int em_event_group_is_ready(em_event_group_t event_group);
240 
241 /**
242  * Return the currently active event group.
243  *
244  * Returns the current event group or EM_EVENT_GROUP_UNDEF if an event group is
245  * not active (i.e. never activated or deactivated using
246  * em_event_group_processing_end()).
247  *
248  * Can only be used within an EO receive function.
249  *
250  * @return Current event group or EM_EVENT_GROUP_UNDEF
251  *
252  * @see em_event_group_create()
253  */
254 em_event_group_t em_event_group_current(void);
255 
256 /**
257  * Send event associated with/tagged to an event group.
258  *
259  * Any valid event and destination queue parameters can be used. The event
260  * group indicates which event group the event is tagged to. The event group
261  * has to first be created and applied a count.
262  * One should always send the correct amount of events to an event group, i.e.
263  * matching the applied count.
264  *
265  * Event group is not supported with unscheduled queues.
266  *
267  * It is not allowed to use event references with event groups since assigning
268  * an event that has references to an event group would assign all the
269  * references to the event group resulting in undefined behaviour. E.g. using
270  * em_send_group() to send a reference is wrong.
271  *
272  * @param event Event to send
273  * @param queue Destination queue
274  * @param event_group Event group
275  *
276  * @return EM_OK if successful.
277  *
278  * @see em_send(), em_event_group_create(), em_event_group_apply(),
279  * em_event_group_increment()
280  */
281 em_status_t em_send_group(em_event_t event, em_queue_t queue,
282  em_event_group_t event_group);
283 
284 /**
285  * Send multiple events associated with/tagged to an event group.
286  *
287  * This is like em_send_group, but multiple events can be sent with one call
288  * for potential performance gain.
289  * The call returns the number of events actually sent. A return value equal to
290  * 'num' means that all events were sent. A value less than 'num' means the
291  * events at the end of the given event list were not sent and must be handled
292  * by the application.
293  * The function will not modify the given list of events.
294  *
295  * Event group is not supported with unscheduled queues.
296  *
297  * It is not allowed to use event references with event groups since assigning
298  * an event that has references to an event group would assign all the
299  * references to the event group resulting in undefined behaviour. E.g. using
300  * em_send_group_multi() to send references is wrong.
301  *
302  * @param events List of events to send (i.e. ptr to array of events)
303  * @param num Number of events
304  * @param queue Destination queue
305  * @param event_group Event group
306  *
307  * @return number of events successfully sent (equal to num if all successful)
308  *
309  * @see em_send_group()
310  */
311 int em_send_group_multi(const em_event_t events[], int num, em_queue_t queue,
312  em_event_group_t event_group);
313 
314 /**
315  * Signal early end of processing of the current event group
316  *
317  * This is an optional call that can be used to move the implicit event group
318  * handling (decrementing the count) from exiting event receive function to the
319  * point of this call - the current event group count is decremented
320  * immediately and if it reaches zero the notifications are also sent. In that
321  * case the group will be ready for a new apply after this returns.
322  *
323  * This impacts the current event group the same way whether it was activated
324  * by receiving a tagged event or EO called em_event_group_assign().
325  *
326  * This call does not change potential atomicity or ordering for the current
327  * event and is a no-operation if called while an event group is not active
328  * (no current group).
329  *
330  * Can only be used within the EO receive function.
331  */
333 
334 /**
335  * Assign core local current event group.
336  *
337  * The assign functionality can be used to set the core local current event
338  * group. The event group handling after the assign call is identical to
339  * the handling of an event group that was originally set by sending an event
340  * tagged to that event group, i.e. the core local current event group
341  * is active and will be operated on in a normal way.
342  * Assign will fail if there already is an active current event group, i.e.
343  * only one event group can be active at a time (per core).
344  *
345  * This needs to be used with care, i.e. match the amount of events applied
346  * and assigned.
347  *
348  * @param event_group An applied event group to assign to
349  *
350  * @return EM_OK if assignment was successful
351  */
352 em_status_t em_event_group_assign(em_event_group_t event_group);
353 
354 /**
355  * Abort the ongoing event group.
356  *
357  * This is a recovery operation to abort an ongoing event group in case it does
358  * not get completed. This will reset the group back to a state ready for
359  * a new apply. Note, that there is a potential race as the group could get
360  * completed on another thread while executing this (e.g. a delayed event is
361  * finally received and processed). Implementation will synchronize internal
362  * state changes, but this call may succeed or fail depending on timing so
363  * abort should be done with care for recovery purpose only.
364  *
365  * Notification events related to the ongoing (to be aborted) cycle can be
366  * managed as follows
367  * 1) save possible related notifications using em_event_group_get_notif()
368  * 2) call em_event_group_abort()
369  * 3) IF em_event_group_abort() returns EM_OK the operation was successfully
370  * completed meaning the earlier notifications will not be sent thus the
371  * saved notifications can be freed or re-used. Otherwise the call was made
372  * too late and the saved notifications must not be touched as they are to
373  * be sent.
374  *
375  * This means the synchronization point is em_event_group_abort(), not
376  * em_event_group_get_notif() which might return notifications that will still
377  * be sent.
378  *
379  * @attention Related notification events will not be automatically freed in
380  * any case and must be handled by the application.
381  *
382  * @param event_group Event group to abort and reset
383  *
384  * @return EM_OK if the call was made early enough to cleanly abort, i.e.
385  * before the last event was processed. EM_OK also means the
386  * notifications will not be sent.
387  */
388 em_status_t em_event_group_abort(em_event_group_t event_group);
389 
390 /**
391  * Return notification events currently related to an applied event group.
392  *
393  * This returns the current notifications or none (0) if they were already sent
394  * (event group completed).
395  *
396  * @attention This is not a synchronization point, which means
397  * em_event_group_get_notif() could return notifications which
398  * are just going to be sent and thus should not be touched.
399  *
400  * @param event_group Event group
401  * @param max_notif Maximum number of notifications to return
402  * @param[out] notif_tbl Table for notifications to fill
403  *
404  * @return Number of returned notifications
405  *
406  * @see em_event_group_apply(), em_event_group_abort()
407  */
408 int em_event_group_get_notif(em_event_group_t event_group,
409  int max_notif, em_notif_t notif_tbl[]);
410 
411 /**
412  * Initialize event group iteration and return the first event group handle.
413  *
414  * Can be used to initialize the iteration to retrieve all created event groups
415  * for debugging or management purposes. Use em_event_group_get_next() after
416  * this call until it returns EM_EVENT_GROUP_UNDEF.
417  * A new call to em_event_group_get_first() resets the iteration, which is
418  * maintained per core (thread). The operation should be completed in one go
419  * before returning from the EO's event receive function (or start/stop).
420  *
421  * The number of event groups (output arg 'num') may not match the amount of
422  * event groups actually returned by iterating using em_event_group_get_next()
423  * if event groups are added or removed in parallel by another core. The order
424  * of the returned event group handles is undefined.
425  *
426  * @code
427  * unsigned int num;
428  * em_event_group_t eg = em_event_group_get_first(&num);
429  * while (eg != EM_EVENT_GROUP_UNDEF) {
430  * eg = em_event_group_get_next();
431  * }
432  * @endcode
433  *
434  * @param[out] num Pointer to an unsigned int to store the amount of
435  * event groups into
436  * @return The first event group handle or EM_EVENT_GROUP_UNDEF if none exist
437  *
438  * @see em_event_group_get_next()
439  **/
440 em_event_group_t
441 em_event_group_get_first(unsigned int *num);
442 
443 /**
444  * Return the next event group handle.
445  *
446  * Continues the event group iteration started by em_event_group_get_first() and
447  * returns the next event group handle.
448  *
449  * @return The next event group handle or EM_EVENT_GROUP_UNDEF if the event
450  * group iteration is completed (i.e. no more event groups available).
451  *
452  * @see em_event_group_get_first()
453  **/
454 em_event_group_t
456 
457 /**
458  * Convert an event group handle to an unsigned integer
459  *
460  * @param event_group Event group handle to be converted
461  * @return uint64_t value that can be used to print/display the handle
462  *
463  * @note This routine is intended to be used for diagnostic purposes
464  * to enable applications to e.g. generate a printable value that represents
465  * an em_event_group_t handle.
466  */
467 uint64_t em_event_group_to_u64(em_event_group_t event_group);
468 
469 /**
470  * @}
471  */
472 #ifdef __cplusplus
473 }
474 #endif
475 
476 #pragma GCC visibility pop
477 #endif /* EVENT_MACHINE_EVENT_GROUP_H_ */
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_event_group_delete
em_status_t em_event_group_delete(em_event_group_t event_group)
Definition: event_machine_event_group.c:57
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
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
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_event_group_create
em_event_group_t em_event_group_create(void)
Definition: event_machine_event_group.c:37
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
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_event_group_current
em_event_group_t em_event_group_current(void)
Definition: event_machine_event_group.c:245
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
event_machine_hw_types.h
em_event_group_increment
em_status_t em_event_group_increment(int count)
Definition: event_machine_event_group.c:151
em_notif_t
Definition: event_machine_types.h:268
event_machine_types.h
em_event_group_assign
em_status_t em_event_group_assign(em_event_group_t event_group)
Definition: event_machine_event_group.c:644
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