]> begriffs open source - freertos/blob - event_groups.c
Reduce memory usage of ACL. (#809)
[freertos] / event_groups.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* Standard includes. */
30 #include <stdlib.h>
31
32 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33  * all the API functions to use the MPU wrappers.  That should only be done when
34  * task.h is included from an application file. */
35 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
36
37 /* FreeRTOS includes. */
38 #include "FreeRTOS.h"
39 #include "task.h"
40 #include "timers.h"
41 #include "event_groups.h"
42
43 /* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified
44  * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
45  * for the header files above, but not in this file, in order to generate the
46  * correct privileged Vs unprivileged linkage and placement. */
47 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */
48
49 typedef struct EventGroupDef_t
50 {
51     EventBits_t uxEventBits;
52     List_t xTasksWaitingForBits; /**< List of tasks waiting for a bit to be set. */
53
54     #if ( configUSE_TRACE_FACILITY == 1 )
55         UBaseType_t uxEventGroupNumber;
56     #endif
57
58     #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
59         uint8_t ucStaticallyAllocated; /**< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
60     #endif
61 } EventGroup_t;
62
63 /*-----------------------------------------------------------*/
64
65 /*
66  * Test the bits set in uxCurrentEventBits to see if the wait condition is met.
67  * The wait condition is defined by xWaitForAllBits.  If xWaitForAllBits is
68  * pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
69  * are also set in uxCurrentEventBits.  If xWaitForAllBits is pdFALSE then the
70  * wait condition is met if any of the bits set in uxBitsToWait for are also set
71  * in uxCurrentEventBits.
72  */
73 static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
74                                         const EventBits_t uxBitsToWaitFor,
75                                         const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
76
77 /*-----------------------------------------------------------*/
78
79 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
80
81     EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer )
82     {
83         EventGroup_t * pxEventBits;
84
85         traceENTER_xEventGroupCreateStatic( pxEventGroupBuffer );
86
87         /* A StaticEventGroup_t object must be provided. */
88         configASSERT( pxEventGroupBuffer );
89
90         #if ( configASSERT_DEFINED == 1 )
91         {
92             /* Sanity check that the size of the structure used to declare a
93              * variable of type StaticEventGroup_t equals the size of the real
94              * event group structure. */
95             volatile size_t xSize = sizeof( StaticEventGroup_t );
96             configASSERT( xSize == sizeof( EventGroup_t ) );
97         } /*lint !e529 xSize is referenced if configASSERT() is defined. */
98         #endif /* configASSERT_DEFINED */
99
100         /* The user has provided a statically allocated event group - use it. */
101         pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
102
103         if( pxEventBits != NULL )
104         {
105             pxEventBits->uxEventBits = 0;
106             vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
107
108             #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
109             {
110                 /* Both static and dynamic allocation can be used, so note that
111                  * this event group was created statically in case the event group
112                  * is later deleted. */
113                 pxEventBits->ucStaticallyAllocated = pdTRUE;
114             }
115             #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
116
117             traceEVENT_GROUP_CREATE( pxEventBits );
118         }
119         else
120         {
121             /* xEventGroupCreateStatic should only ever be called with
122              * pxEventGroupBuffer pointing to a pre-allocated (compile time
123              * allocated) StaticEventGroup_t variable. */
124             traceEVENT_GROUP_CREATE_FAILED();
125         }
126
127         traceRETURN_xEventGroupCreateStatic( pxEventBits );
128
129         return pxEventBits;
130     }
131
132 #endif /* configSUPPORT_STATIC_ALLOCATION */
133 /*-----------------------------------------------------------*/
134
135 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
136
137     EventGroupHandle_t xEventGroupCreate( void )
138     {
139         EventGroup_t * pxEventBits;
140
141         traceENTER_xEventGroupCreate();
142
143         /* Allocate the event group.  Justification for MISRA deviation as
144          * follows:  pvPortMalloc() always ensures returned memory blocks are
145          * aligned per the requirements of the MCU stack.  In this case
146          * pvPortMalloc() must return a pointer that is guaranteed to meet the
147          * alignment requirements of the EventGroup_t structure - which (if you
148          * follow it through) is the alignment requirements of the TickType_t type
149          * (EventBits_t being of TickType_t itself).  Therefore, whenever the
150          * stack alignment requirements are greater than or equal to the
151          * TickType_t alignment requirements the cast is safe.  In other cases,
152          * where the natural word size of the architecture is less than
153          * sizeof( TickType_t ), the TickType_t variables will be accessed in two
154          * or more reads operations, and the alignment requirements is only that
155          * of each individual read. */
156         pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
157
158         if( pxEventBits != NULL )
159         {
160             pxEventBits->uxEventBits = 0;
161             vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
162
163             #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
164             {
165                 /* Both static and dynamic allocation can be used, so note this
166                  * event group was allocated statically in case the event group is
167                  * later deleted. */
168                 pxEventBits->ucStaticallyAllocated = pdFALSE;
169             }
170             #endif /* configSUPPORT_STATIC_ALLOCATION */
171
172             traceEVENT_GROUP_CREATE( pxEventBits );
173         }
174         else
175         {
176             traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */
177         }
178
179         traceRETURN_xEventGroupCreate( pxEventBits );
180
181         return pxEventBits;
182     }
183
184 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
185 /*-----------------------------------------------------------*/
186
187 EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
188                              const EventBits_t uxBitsToSet,
189                              const EventBits_t uxBitsToWaitFor,
190                              TickType_t xTicksToWait )
191 {
192     EventBits_t uxOriginalBitValue, uxReturn;
193     EventGroup_t * pxEventBits = xEventGroup;
194     BaseType_t xAlreadyYielded;
195     BaseType_t xTimeoutOccurred = pdFALSE;
196
197     traceENTER_xEventGroupSync( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTicksToWait );
198
199     configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
200     configASSERT( uxBitsToWaitFor != 0 );
201     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
202     {
203         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
204     }
205     #endif
206
207     vTaskSuspendAll();
208     {
209         uxOriginalBitValue = pxEventBits->uxEventBits;
210
211         ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
212
213         if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
214         {
215             /* All the rendezvous bits are now set - no need to block. */
216             uxReturn = ( uxOriginalBitValue | uxBitsToSet );
217
218             /* Rendezvous always clear the bits.  They will have been cleared
219              * already unless this is the only task in the rendezvous. */
220             pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
221
222             xTicksToWait = 0;
223         }
224         else
225         {
226             if( xTicksToWait != ( TickType_t ) 0 )
227             {
228                 traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
229
230                 /* Store the bits that the calling task is waiting for in the
231                  * task's event list item so the kernel knows when a match is
232                  * found.  Then enter the blocked state. */
233                 vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
234
235                 /* This assignment is obsolete as uxReturn will get set after
236                  * the task unblocks, but some compilers mistakenly generate a
237                  * warning about uxReturn being returned without being set if the
238                  * assignment is omitted. */
239                 uxReturn = 0;
240             }
241             else
242             {
243                 /* The rendezvous bits were not set, but no block time was
244                  * specified - just return the current event bit value. */
245                 uxReturn = pxEventBits->uxEventBits;
246                 xTimeoutOccurred = pdTRUE;
247             }
248         }
249     }
250     xAlreadyYielded = xTaskResumeAll();
251
252     if( xTicksToWait != ( TickType_t ) 0 )
253     {
254         if( xAlreadyYielded == pdFALSE )
255         {
256             #if ( configNUMBER_OF_CORES == 1 )
257             {
258                 portYIELD_WITHIN_API();
259             }
260             #else /* #if ( configNUMBER_OF_CORES == 1 ) */
261             {
262                 vTaskYieldWithinAPI();
263             }
264             #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
265         }
266         else
267         {
268             mtCOVERAGE_TEST_MARKER();
269         }
270
271         /* The task blocked to wait for its required bits to be set - at this
272          * point either the required bits were set or the block time expired.  If
273          * the required bits were set they will have been stored in the task's
274          * event list item, and they should now be retrieved then cleared. */
275         uxReturn = uxTaskResetEventItemValue();
276
277         if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
278         {
279             /* The task timed out, just return the current event bit value. */
280             taskENTER_CRITICAL();
281             {
282                 uxReturn = pxEventBits->uxEventBits;
283
284                 /* Although the task got here because it timed out before the
285                  * bits it was waiting for were set, it is possible that since it
286                  * unblocked another task has set the bits.  If this is the case
287                  * then it needs to clear the bits before exiting. */
288                 if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
289                 {
290                     pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
291                 }
292                 else
293                 {
294                     mtCOVERAGE_TEST_MARKER();
295                 }
296             }
297             taskEXIT_CRITICAL();
298
299             xTimeoutOccurred = pdTRUE;
300         }
301         else
302         {
303             /* The task unblocked because the bits were set. */
304         }
305
306         /* Control bits might be set as the task had blocked should not be
307          * returned. */
308         uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
309     }
310
311     traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
312
313     /* Prevent compiler warnings when trace macros are not used. */
314     ( void ) xTimeoutOccurred;
315
316     traceRETURN_xEventGroupSync( uxReturn );
317
318     return uxReturn;
319 }
320 /*-----------------------------------------------------------*/
321
322 EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
323                                  const EventBits_t uxBitsToWaitFor,
324                                  const BaseType_t xClearOnExit,
325                                  const BaseType_t xWaitForAllBits,
326                                  TickType_t xTicksToWait )
327 {
328     EventGroup_t * pxEventBits = xEventGroup;
329     EventBits_t uxReturn, uxControlBits = 0;
330     BaseType_t xWaitConditionMet, xAlreadyYielded;
331     BaseType_t xTimeoutOccurred = pdFALSE;
332
333     traceENTER_xEventGroupWaitBits( xEventGroup, uxBitsToWaitFor, xClearOnExit, xWaitForAllBits, xTicksToWait );
334
335     /* Check the user is not attempting to wait on the bits used by the kernel
336      * itself, and that at least one bit is being requested. */
337     configASSERT( xEventGroup );
338     configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
339     configASSERT( uxBitsToWaitFor != 0 );
340     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
341     {
342         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
343     }
344     #endif
345
346     vTaskSuspendAll();
347     {
348         const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
349
350         /* Check to see if the wait condition is already met or not. */
351         xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
352
353         if( xWaitConditionMet != pdFALSE )
354         {
355             /* The wait condition has already been met so there is no need to
356              * block. */
357             uxReturn = uxCurrentEventBits;
358             xTicksToWait = ( TickType_t ) 0;
359
360             /* Clear the wait bits if requested to do so. */
361             if( xClearOnExit != pdFALSE )
362             {
363                 pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
364             }
365             else
366             {
367                 mtCOVERAGE_TEST_MARKER();
368             }
369         }
370         else if( xTicksToWait == ( TickType_t ) 0 )
371         {
372             /* The wait condition has not been met, but no block time was
373              * specified, so just return the current value. */
374             uxReturn = uxCurrentEventBits;
375             xTimeoutOccurred = pdTRUE;
376         }
377         else
378         {
379             /* The task is going to block to wait for its required bits to be
380              * set.  uxControlBits are used to remember the specified behaviour of
381              * this call to xEventGroupWaitBits() - for use when the event bits
382              * unblock the task. */
383             if( xClearOnExit != pdFALSE )
384             {
385                 uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
386             }
387             else
388             {
389                 mtCOVERAGE_TEST_MARKER();
390             }
391
392             if( xWaitForAllBits != pdFALSE )
393             {
394                 uxControlBits |= eventWAIT_FOR_ALL_BITS;
395             }
396             else
397             {
398                 mtCOVERAGE_TEST_MARKER();
399             }
400
401             /* Store the bits that the calling task is waiting for in the
402              * task's event list item so the kernel knows when a match is
403              * found.  Then enter the blocked state. */
404             vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
405
406             /* This is obsolete as it will get set after the task unblocks, but
407              * some compilers mistakenly generate a warning about the variable
408              * being returned without being set if it is not done. */
409             uxReturn = 0;
410
411             traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
412         }
413     }
414     xAlreadyYielded = xTaskResumeAll();
415
416     if( xTicksToWait != ( TickType_t ) 0 )
417     {
418         if( xAlreadyYielded == pdFALSE )
419         {
420             #if ( configNUMBER_OF_CORES == 1 )
421             {
422                 portYIELD_WITHIN_API();
423             }
424             #else /* #if ( configNUMBER_OF_CORES == 1 ) */
425             {
426                 vTaskYieldWithinAPI();
427             }
428             #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
429         }
430         else
431         {
432             mtCOVERAGE_TEST_MARKER();
433         }
434
435         /* The task blocked to wait for its required bits to be set - at this
436          * point either the required bits were set or the block time expired.  If
437          * the required bits were set they will have been stored in the task's
438          * event list item, and they should now be retrieved then cleared. */
439         uxReturn = uxTaskResetEventItemValue();
440
441         if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
442         {
443             taskENTER_CRITICAL();
444             {
445                 /* The task timed out, just return the current event bit value. */
446                 uxReturn = pxEventBits->uxEventBits;
447
448                 /* It is possible that the event bits were updated between this
449                  * task leaving the Blocked state and running again. */
450                 if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
451                 {
452                     if( xClearOnExit != pdFALSE )
453                     {
454                         pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
455                     }
456                     else
457                     {
458                         mtCOVERAGE_TEST_MARKER();
459                     }
460                 }
461                 else
462                 {
463                     mtCOVERAGE_TEST_MARKER();
464                 }
465
466                 xTimeoutOccurred = pdTRUE;
467             }
468             taskEXIT_CRITICAL();
469         }
470         else
471         {
472             /* The task unblocked because the bits were set. */
473         }
474
475         /* The task blocked so control bits may have been set. */
476         uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
477     }
478
479     traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
480
481     /* Prevent compiler warnings when trace macros are not used. */
482     ( void ) xTimeoutOccurred;
483
484     traceRETURN_xEventGroupWaitBits( uxReturn );
485
486     return uxReturn;
487 }
488 /*-----------------------------------------------------------*/
489
490 EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
491                                   const EventBits_t uxBitsToClear )
492 {
493     EventGroup_t * pxEventBits = xEventGroup;
494     EventBits_t uxReturn;
495
496     traceENTER_xEventGroupClearBits( xEventGroup, uxBitsToClear );
497
498     /* Check the user is not attempting to clear the bits used by the kernel
499      * itself. */
500     configASSERT( xEventGroup );
501     configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
502
503     taskENTER_CRITICAL();
504     {
505         traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
506
507         /* The value returned is the event group value prior to the bits being
508          * cleared. */
509         uxReturn = pxEventBits->uxEventBits;
510
511         /* Clear the bits. */
512         pxEventBits->uxEventBits &= ~uxBitsToClear;
513     }
514     taskEXIT_CRITICAL();
515
516     traceRETURN_xEventGroupClearBits( uxReturn );
517
518     return uxReturn;
519 }
520 /*-----------------------------------------------------------*/
521
522 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
523
524     BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
525                                             const EventBits_t uxBitsToClear )
526     {
527         BaseType_t xReturn;
528
529         traceENTER_xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear );
530
531         traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
532         xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
533
534         traceRETURN_xEventGroupClearBitsFromISR( xReturn );
535
536         return xReturn;
537     }
538
539 #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
540 /*-----------------------------------------------------------*/
541
542 EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
543 {
544     UBaseType_t uxSavedInterruptStatus;
545     EventGroup_t const * const pxEventBits = xEventGroup;
546     EventBits_t uxReturn;
547
548     traceENTER_xEventGroupGetBitsFromISR( xEventGroup );
549
550     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
551     {
552         uxReturn = pxEventBits->uxEventBits;
553     }
554     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
555
556     traceRETURN_xEventGroupGetBitsFromISR( uxReturn );
557
558     return uxReturn;
559 } /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
560 /*-----------------------------------------------------------*/
561
562 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
563                                 const EventBits_t uxBitsToSet )
564 {
565     ListItem_t * pxListItem;
566     ListItem_t * pxNext;
567     ListItem_t const * pxListEnd;
568     List_t const * pxList;
569     EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
570     EventGroup_t * pxEventBits = xEventGroup;
571     BaseType_t xMatchFound = pdFALSE;
572
573     traceENTER_xEventGroupSetBits( xEventGroup, uxBitsToSet );
574
575     /* Check the user is not attempting to set the bits used by the kernel
576      * itself. */
577     configASSERT( xEventGroup );
578     configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
579
580     pxList = &( pxEventBits->xTasksWaitingForBits );
581     pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
582     vTaskSuspendAll();
583     {
584         traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
585
586         pxListItem = listGET_HEAD_ENTRY( pxList );
587
588         /* Set the bits. */
589         pxEventBits->uxEventBits |= uxBitsToSet;
590
591         /* See if the new bit value should unblock any tasks. */
592         while( pxListItem != pxListEnd )
593         {
594             pxNext = listGET_NEXT( pxListItem );
595             uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
596             xMatchFound = pdFALSE;
597
598             /* Split the bits waited for from the control bits. */
599             uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
600             uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
601
602             if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
603             {
604                 /* Just looking for single bit being set. */
605                 if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
606                 {
607                     xMatchFound = pdTRUE;
608                 }
609                 else
610                 {
611                     mtCOVERAGE_TEST_MARKER();
612                 }
613             }
614             else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
615             {
616                 /* All bits are set. */
617                 xMatchFound = pdTRUE;
618             }
619             else
620             {
621                 /* Need all bits to be set, but not all the bits were set. */
622             }
623
624             if( xMatchFound != pdFALSE )
625             {
626                 /* The bits match.  Should the bits be cleared on exit? */
627                 if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
628                 {
629                     uxBitsToClear |= uxBitsWaitedFor;
630                 }
631                 else
632                 {
633                     mtCOVERAGE_TEST_MARKER();
634                 }
635
636                 /* Store the actual event flag value in the task's event list
637                  * item before removing the task from the event list.  The
638                  * eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
639                  * that is was unblocked due to its required bits matching, rather
640                  * than because it timed out. */
641                 vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
642             }
643
644             /* Move onto the next list item.  Note pxListItem->pxNext is not
645              * used here as the list item may have been removed from the event list
646              * and inserted into the ready/pending reading list. */
647             pxListItem = pxNext;
648         }
649
650         /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
651          * bit was set in the control word. */
652         pxEventBits->uxEventBits &= ~uxBitsToClear;
653     }
654     ( void ) xTaskResumeAll();
655
656     traceRETURN_xEventGroupSetBits( pxEventBits->uxEventBits );
657
658     return pxEventBits->uxEventBits;
659 }
660 /*-----------------------------------------------------------*/
661
662 void vEventGroupDelete( EventGroupHandle_t xEventGroup )
663 {
664     EventGroup_t * pxEventBits = xEventGroup;
665     const List_t * pxTasksWaitingForBits;
666
667     traceENTER_vEventGroupDelete( xEventGroup );
668
669     configASSERT( pxEventBits );
670
671     pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
672
673     vTaskSuspendAll();
674     {
675         traceEVENT_GROUP_DELETE( xEventGroup );
676
677         while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
678         {
679             /* Unblock the task, returning 0 as the event list is being deleted
680              * and cannot therefore have any bits set. */
681             configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
682             vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
683         }
684     }
685     ( void ) xTaskResumeAll();
686
687     #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
688     {
689         /* The event group can only have been allocated dynamically - free
690          * it again. */
691         vPortFree( pxEventBits );
692     }
693     #elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
694     {
695         /* The event group could have been allocated statically or
696          * dynamically, so check before attempting to free the memory. */
697         if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
698         {
699             vPortFree( pxEventBits );
700         }
701         else
702         {
703             mtCOVERAGE_TEST_MARKER();
704         }
705     }
706     #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
707
708     traceRETURN_vEventGroupDelete();
709 }
710 /*-----------------------------------------------------------*/
711
712 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
713     BaseType_t xEventGroupGetStaticBuffer( EventGroupHandle_t xEventGroup,
714                                            StaticEventGroup_t ** ppxEventGroupBuffer )
715     {
716         BaseType_t xReturn;
717         EventGroup_t * pxEventBits = xEventGroup;
718
719         traceENTER_xEventGroupGetStaticBuffer( xEventGroup, ppxEventGroupBuffer );
720
721         configASSERT( pxEventBits );
722         configASSERT( ppxEventGroupBuffer );
723
724         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
725         {
726             /* Check if the event group was statically allocated. */
727             if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdTRUE )
728             {
729                 *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
730                 xReturn = pdTRUE;
731             }
732             else
733             {
734                 xReturn = pdFALSE;
735             }
736         }
737         #else /* configSUPPORT_DYNAMIC_ALLOCATION */
738         {
739             /* Event group must have been statically allocated. */
740             *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
741             xReturn = pdTRUE;
742         }
743         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
744
745         traceRETURN_xEventGroupGetStaticBuffer( xReturn );
746
747         return xReturn;
748     }
749 #endif /* configSUPPORT_STATIC_ALLOCATION */
750 /*-----------------------------------------------------------*/
751
752 /* For internal use only - execute a 'set bits' command that was pended from
753  * an interrupt. */
754 void vEventGroupSetBitsCallback( void * pvEventGroup,
755                                  const uint32_t ulBitsToSet )
756 {
757     traceENTER_vEventGroupSetBitsCallback( pvEventGroup, ulBitsToSet );
758
759     ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
760
761     traceRETURN_vEventGroupSetBitsCallback();
762 }
763 /*-----------------------------------------------------------*/
764
765 /* For internal use only - execute a 'clear bits' command that was pended from
766  * an interrupt. */
767 void vEventGroupClearBitsCallback( void * pvEventGroup,
768                                    const uint32_t ulBitsToClear )
769 {
770     traceENTER_vEventGroupClearBitsCallback( pvEventGroup, ulBitsToClear );
771
772     ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
773
774     traceRETURN_vEventGroupClearBitsCallback();
775 }
776 /*-----------------------------------------------------------*/
777
778 static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
779                                         const EventBits_t uxBitsToWaitFor,
780                                         const BaseType_t xWaitForAllBits )
781 {
782     BaseType_t xWaitConditionMet = pdFALSE;
783
784     if( xWaitForAllBits == pdFALSE )
785     {
786         /* Task only has to wait for one bit within uxBitsToWaitFor to be
787          * set.  Is one already set? */
788         if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
789         {
790             xWaitConditionMet = pdTRUE;
791         }
792         else
793         {
794             mtCOVERAGE_TEST_MARKER();
795         }
796     }
797     else
798     {
799         /* Task has to wait for all the bits in uxBitsToWaitFor to be set.
800          * Are they set already? */
801         if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
802         {
803             xWaitConditionMet = pdTRUE;
804         }
805         else
806         {
807             mtCOVERAGE_TEST_MARKER();
808         }
809     }
810
811     return xWaitConditionMet;
812 }
813 /*-----------------------------------------------------------*/
814
815 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
816
817     BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
818                                           const EventBits_t uxBitsToSet,
819                                           BaseType_t * pxHigherPriorityTaskWoken )
820     {
821         BaseType_t xReturn;
822
823         traceENTER_xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken );
824
825         traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
826         xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
827
828         traceRETURN_xEventGroupSetBitsFromISR( xReturn );
829
830         return xReturn;
831     }
832
833 #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
834 /*-----------------------------------------------------------*/
835
836 #if ( configUSE_TRACE_FACILITY == 1 )
837
838     UBaseType_t uxEventGroupGetNumber( void * xEventGroup )
839     {
840         UBaseType_t xReturn;
841         EventGroup_t const * pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
842
843         traceENTER_uxEventGroupGetNumber( xEventGroup );
844
845         if( xEventGroup == NULL )
846         {
847             xReturn = 0;
848         }
849         else
850         {
851             xReturn = pxEventBits->uxEventGroupNumber;
852         }
853
854         traceRETURN_uxEventGroupGetNumber( xReturn );
855
856         return xReturn;
857     }
858
859 #endif /* configUSE_TRACE_FACILITY */
860 /*-----------------------------------------------------------*/
861
862 #if ( configUSE_TRACE_FACILITY == 1 )
863
864     void vEventGroupSetNumber( void * xEventGroup,
865                                UBaseType_t uxEventGroupNumber )
866     {
867         traceENTER_vEventGroupSetNumber( xEventGroup, uxEventGroupNumber );
868
869         ( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
870
871         traceRETURN_vEventGroupSetNumber();
872     }
873
874 #endif /* configUSE_TRACE_FACILITY */
875 /*-----------------------------------------------------------*/