]> begriffs open source - freertos/blob - event_groups.c
Add SMP template port and example (#900)
[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         /* MISRA Ref 11.3.1 [Misaligned access] */
102         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
103         /* coverity[misra_c_2012_rule_11_3_violation] */
104         pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer;
105
106         if( pxEventBits != NULL )
107         {
108             pxEventBits->uxEventBits = 0;
109             vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
110
111             #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
112             {
113                 /* Both static and dynamic allocation can be used, so note that
114                  * this event group was created statically in case the event group
115                  * is later deleted. */
116                 pxEventBits->ucStaticallyAllocated = pdTRUE;
117             }
118             #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
119
120             traceEVENT_GROUP_CREATE( pxEventBits );
121         }
122         else
123         {
124             /* xEventGroupCreateStatic should only ever be called with
125              * pxEventGroupBuffer pointing to a pre-allocated (compile time
126              * allocated) StaticEventGroup_t variable. */
127             traceEVENT_GROUP_CREATE_FAILED();
128         }
129
130         traceRETURN_xEventGroupCreateStatic( pxEventBits );
131
132         return pxEventBits;
133     }
134
135 #endif /* configSUPPORT_STATIC_ALLOCATION */
136 /*-----------------------------------------------------------*/
137
138 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
139
140     EventGroupHandle_t xEventGroupCreate( void )
141     {
142         EventGroup_t * pxEventBits;
143
144         traceENTER_xEventGroupCreate();
145
146         /* Allocate the event group.  Justification for MISRA deviation as
147          * follows:  pvPortMalloc() always ensures returned memory blocks are
148          * aligned per the requirements of the MCU stack.  In this case
149          * pvPortMalloc() must return a pointer that is guaranteed to meet the
150          * alignment requirements of the EventGroup_t structure - which (if you
151          * follow it through) is the alignment requirements of the TickType_t type
152          * (EventBits_t being of TickType_t itself).  Therefore, whenever the
153          * stack alignment requirements are greater than or equal to the
154          * TickType_t alignment requirements the cast is safe.  In other cases,
155          * where the natural word size of the architecture is less than
156          * sizeof( TickType_t ), the TickType_t variables will be accessed in two
157          * or more reads operations, and the alignment requirements is only that
158          * of each individual read. */
159         pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
160
161         if( pxEventBits != NULL )
162         {
163             pxEventBits->uxEventBits = 0;
164             vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
165
166             #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
167             {
168                 /* Both static and dynamic allocation can be used, so note this
169                  * event group was allocated statically in case the event group is
170                  * later deleted. */
171                 pxEventBits->ucStaticallyAllocated = pdFALSE;
172             }
173             #endif /* configSUPPORT_STATIC_ALLOCATION */
174
175             traceEVENT_GROUP_CREATE( pxEventBits );
176         }
177         else
178         {
179             traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */
180         }
181
182         traceRETURN_xEventGroupCreate( pxEventBits );
183
184         return pxEventBits;
185     }
186
187 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
188 /*-----------------------------------------------------------*/
189
190 EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
191                              const EventBits_t uxBitsToSet,
192                              const EventBits_t uxBitsToWaitFor,
193                              TickType_t xTicksToWait )
194 {
195     EventBits_t uxOriginalBitValue, uxReturn;
196     EventGroup_t * pxEventBits = xEventGroup;
197     BaseType_t xAlreadyYielded;
198     BaseType_t xTimeoutOccurred = pdFALSE;
199
200     traceENTER_xEventGroupSync( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTicksToWait );
201
202     configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
203     configASSERT( uxBitsToWaitFor != 0 );
204     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
205     {
206         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
207     }
208     #endif
209
210     vTaskSuspendAll();
211     {
212         uxOriginalBitValue = pxEventBits->uxEventBits;
213
214         ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
215
216         if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
217         {
218             /* All the rendezvous bits are now set - no need to block. */
219             uxReturn = ( uxOriginalBitValue | uxBitsToSet );
220
221             /* Rendezvous always clear the bits.  They will have been cleared
222              * already unless this is the only task in the rendezvous. */
223             pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
224
225             xTicksToWait = 0;
226         }
227         else
228         {
229             if( xTicksToWait != ( TickType_t ) 0 )
230             {
231                 traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
232
233                 /* Store the bits that the calling task is waiting for in the
234                  * task's event list item so the kernel knows when a match is
235                  * found.  Then enter the blocked state. */
236                 vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
237
238                 /* This assignment is obsolete as uxReturn will get set after
239                  * the task unblocks, but some compilers mistakenly generate a
240                  * warning about uxReturn being returned without being set if the
241                  * assignment is omitted. */
242                 uxReturn = 0;
243             }
244             else
245             {
246                 /* The rendezvous bits were not set, but no block time was
247                  * specified - just return the current event bit value. */
248                 uxReturn = pxEventBits->uxEventBits;
249                 xTimeoutOccurred = pdTRUE;
250             }
251         }
252     }
253     xAlreadyYielded = xTaskResumeAll();
254
255     if( xTicksToWait != ( TickType_t ) 0 )
256     {
257         if( xAlreadyYielded == pdFALSE )
258         {
259             taskYIELD_WITHIN_API();
260         }
261         else
262         {
263             mtCOVERAGE_TEST_MARKER();
264         }
265
266         /* The task blocked to wait for its required bits to be set - at this
267          * point either the required bits were set or the block time expired.  If
268          * the required bits were set they will have been stored in the task's
269          * event list item, and they should now be retrieved then cleared. */
270         uxReturn = uxTaskResetEventItemValue();
271
272         if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
273         {
274             /* The task timed out, just return the current event bit value. */
275             taskENTER_CRITICAL();
276             {
277                 uxReturn = pxEventBits->uxEventBits;
278
279                 /* Although the task got here because it timed out before the
280                  * bits it was waiting for were set, it is possible that since it
281                  * unblocked another task has set the bits.  If this is the case
282                  * then it needs to clear the bits before exiting. */
283                 if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
284                 {
285                     pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
286                 }
287                 else
288                 {
289                     mtCOVERAGE_TEST_MARKER();
290                 }
291             }
292             taskEXIT_CRITICAL();
293
294             xTimeoutOccurred = pdTRUE;
295         }
296         else
297         {
298             /* The task unblocked because the bits were set. */
299         }
300
301         /* Control bits might be set as the task had blocked should not be
302          * returned. */
303         uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
304     }
305
306     traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
307
308     /* Prevent compiler warnings when trace macros are not used. */
309     ( void ) xTimeoutOccurred;
310
311     traceRETURN_xEventGroupSync( uxReturn );
312
313     return uxReturn;
314 }
315 /*-----------------------------------------------------------*/
316
317 EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
318                                  const EventBits_t uxBitsToWaitFor,
319                                  const BaseType_t xClearOnExit,
320                                  const BaseType_t xWaitForAllBits,
321                                  TickType_t xTicksToWait )
322 {
323     EventGroup_t * pxEventBits = xEventGroup;
324     EventBits_t uxReturn, uxControlBits = 0;
325     BaseType_t xWaitConditionMet, xAlreadyYielded;
326     BaseType_t xTimeoutOccurred = pdFALSE;
327
328     traceENTER_xEventGroupWaitBits( xEventGroup, uxBitsToWaitFor, xClearOnExit, xWaitForAllBits, xTicksToWait );
329
330     /* Check the user is not attempting to wait on the bits used by the kernel
331      * itself, and that at least one bit is being requested. */
332     configASSERT( xEventGroup );
333     configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
334     configASSERT( uxBitsToWaitFor != 0 );
335     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
336     {
337         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
338     }
339     #endif
340
341     vTaskSuspendAll();
342     {
343         const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
344
345         /* Check to see if the wait condition is already met or not. */
346         xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
347
348         if( xWaitConditionMet != pdFALSE )
349         {
350             /* The wait condition has already been met so there is no need to
351              * block. */
352             uxReturn = uxCurrentEventBits;
353             xTicksToWait = ( TickType_t ) 0;
354
355             /* Clear the wait bits if requested to do so. */
356             if( xClearOnExit != pdFALSE )
357             {
358                 pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
359             }
360             else
361             {
362                 mtCOVERAGE_TEST_MARKER();
363             }
364         }
365         else if( xTicksToWait == ( TickType_t ) 0 )
366         {
367             /* The wait condition has not been met, but no block time was
368              * specified, so just return the current value. */
369             uxReturn = uxCurrentEventBits;
370             xTimeoutOccurred = pdTRUE;
371         }
372         else
373         {
374             /* The task is going to block to wait for its required bits to be
375              * set.  uxControlBits are used to remember the specified behaviour of
376              * this call to xEventGroupWaitBits() - for use when the event bits
377              * unblock the task. */
378             if( xClearOnExit != pdFALSE )
379             {
380                 uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
381             }
382             else
383             {
384                 mtCOVERAGE_TEST_MARKER();
385             }
386
387             if( xWaitForAllBits != pdFALSE )
388             {
389                 uxControlBits |= eventWAIT_FOR_ALL_BITS;
390             }
391             else
392             {
393                 mtCOVERAGE_TEST_MARKER();
394             }
395
396             /* Store the bits that the calling task is waiting for in the
397              * task's event list item so the kernel knows when a match is
398              * found.  Then enter the blocked state. */
399             vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
400
401             /* This is obsolete as it will get set after the task unblocks, but
402              * some compilers mistakenly generate a warning about the variable
403              * being returned without being set if it is not done. */
404             uxReturn = 0;
405
406             traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
407         }
408     }
409     xAlreadyYielded = xTaskResumeAll();
410
411     if( xTicksToWait != ( TickType_t ) 0 )
412     {
413         if( xAlreadyYielded == pdFALSE )
414         {
415             taskYIELD_WITHIN_API();
416         }
417         else
418         {
419             mtCOVERAGE_TEST_MARKER();
420         }
421
422         /* The task blocked to wait for its required bits to be set - at this
423          * point either the required bits were set or the block time expired.  If
424          * the required bits were set they will have been stored in the task's
425          * event list item, and they should now be retrieved then cleared. */
426         uxReturn = uxTaskResetEventItemValue();
427
428         if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
429         {
430             taskENTER_CRITICAL();
431             {
432                 /* The task timed out, just return the current event bit value. */
433                 uxReturn = pxEventBits->uxEventBits;
434
435                 /* It is possible that the event bits were updated between this
436                  * task leaving the Blocked state and running again. */
437                 if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
438                 {
439                     if( xClearOnExit != pdFALSE )
440                     {
441                         pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
442                     }
443                     else
444                     {
445                         mtCOVERAGE_TEST_MARKER();
446                     }
447                 }
448                 else
449                 {
450                     mtCOVERAGE_TEST_MARKER();
451                 }
452
453                 xTimeoutOccurred = pdTRUE;
454             }
455             taskEXIT_CRITICAL();
456         }
457         else
458         {
459             /* The task unblocked because the bits were set. */
460         }
461
462         /* The task blocked so control bits may have been set. */
463         uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
464     }
465
466     traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
467
468     /* Prevent compiler warnings when trace macros are not used. */
469     ( void ) xTimeoutOccurred;
470
471     traceRETURN_xEventGroupWaitBits( uxReturn );
472
473     return uxReturn;
474 }
475 /*-----------------------------------------------------------*/
476
477 EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
478                                   const EventBits_t uxBitsToClear )
479 {
480     EventGroup_t * pxEventBits = xEventGroup;
481     EventBits_t uxReturn;
482
483     traceENTER_xEventGroupClearBits( xEventGroup, uxBitsToClear );
484
485     /* Check the user is not attempting to clear the bits used by the kernel
486      * itself. */
487     configASSERT( xEventGroup );
488     configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
489
490     taskENTER_CRITICAL();
491     {
492         traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
493
494         /* The value returned is the event group value prior to the bits being
495          * cleared. */
496         uxReturn = pxEventBits->uxEventBits;
497
498         /* Clear the bits. */
499         pxEventBits->uxEventBits &= ~uxBitsToClear;
500     }
501     taskEXIT_CRITICAL();
502
503     traceRETURN_xEventGroupClearBits( uxReturn );
504
505     return uxReturn;
506 }
507 /*-----------------------------------------------------------*/
508
509 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
510
511     BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
512                                             const EventBits_t uxBitsToClear )
513     {
514         BaseType_t xReturn;
515
516         traceENTER_xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear );
517
518         traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
519         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. */
520
521         traceRETURN_xEventGroupClearBitsFromISR( xReturn );
522
523         return xReturn;
524     }
525
526 #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
527 /*-----------------------------------------------------------*/
528
529 EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
530 {
531     UBaseType_t uxSavedInterruptStatus;
532     EventGroup_t const * const pxEventBits = xEventGroup;
533     EventBits_t uxReturn;
534
535     traceENTER_xEventGroupGetBitsFromISR( xEventGroup );
536
537     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
538     {
539         uxReturn = pxEventBits->uxEventBits;
540     }
541     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
542
543     traceRETURN_xEventGroupGetBitsFromISR( uxReturn );
544
545     return uxReturn;
546 } /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
547 /*-----------------------------------------------------------*/
548
549 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
550                                 const EventBits_t uxBitsToSet )
551 {
552     ListItem_t * pxListItem;
553     ListItem_t * pxNext;
554     ListItem_t const * pxListEnd;
555     List_t const * pxList;
556     EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
557     EventGroup_t * pxEventBits = xEventGroup;
558     BaseType_t xMatchFound = pdFALSE;
559
560     traceENTER_xEventGroupSetBits( xEventGroup, uxBitsToSet );
561
562     /* Check the user is not attempting to set the bits used by the kernel
563      * itself. */
564     configASSERT( xEventGroup );
565     configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
566
567     pxList = &( pxEventBits->xTasksWaitingForBits );
568     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. */
569     vTaskSuspendAll();
570     {
571         traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
572
573         pxListItem = listGET_HEAD_ENTRY( pxList );
574
575         /* Set the bits. */
576         pxEventBits->uxEventBits |= uxBitsToSet;
577
578         /* See if the new bit value should unblock any tasks. */
579         while( pxListItem != pxListEnd )
580         {
581             pxNext = listGET_NEXT( pxListItem );
582             uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
583             xMatchFound = pdFALSE;
584
585             /* Split the bits waited for from the control bits. */
586             uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
587             uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
588
589             if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
590             {
591                 /* Just looking for single bit being set. */
592                 if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
593                 {
594                     xMatchFound = pdTRUE;
595                 }
596                 else
597                 {
598                     mtCOVERAGE_TEST_MARKER();
599                 }
600             }
601             else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
602             {
603                 /* All bits are set. */
604                 xMatchFound = pdTRUE;
605             }
606             else
607             {
608                 /* Need all bits to be set, but not all the bits were set. */
609             }
610
611             if( xMatchFound != pdFALSE )
612             {
613                 /* The bits match.  Should the bits be cleared on exit? */
614                 if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
615                 {
616                     uxBitsToClear |= uxBitsWaitedFor;
617                 }
618                 else
619                 {
620                     mtCOVERAGE_TEST_MARKER();
621                 }
622
623                 /* Store the actual event flag value in the task's event list
624                  * item before removing the task from the event list.  The
625                  * eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
626                  * that is was unblocked due to its required bits matching, rather
627                  * than because it timed out. */
628                 vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
629             }
630
631             /* Move onto the next list item.  Note pxListItem->pxNext is not
632              * used here as the list item may have been removed from the event list
633              * and inserted into the ready/pending reading list. */
634             pxListItem = pxNext;
635         }
636
637         /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
638          * bit was set in the control word. */
639         pxEventBits->uxEventBits &= ~uxBitsToClear;
640     }
641     ( void ) xTaskResumeAll();
642
643     traceRETURN_xEventGroupSetBits( pxEventBits->uxEventBits );
644
645     return pxEventBits->uxEventBits;
646 }
647 /*-----------------------------------------------------------*/
648
649 void vEventGroupDelete( EventGroupHandle_t xEventGroup )
650 {
651     EventGroup_t * pxEventBits = xEventGroup;
652     const List_t * pxTasksWaitingForBits;
653
654     traceENTER_vEventGroupDelete( xEventGroup );
655
656     configASSERT( pxEventBits );
657
658     pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
659
660     vTaskSuspendAll();
661     {
662         traceEVENT_GROUP_DELETE( xEventGroup );
663
664         while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
665         {
666             /* Unblock the task, returning 0 as the event list is being deleted
667              * and cannot therefore have any bits set. */
668             configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
669             vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
670         }
671     }
672     ( void ) xTaskResumeAll();
673
674     #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
675     {
676         /* The event group can only have been allocated dynamically - free
677          * it again. */
678         vPortFree( pxEventBits );
679     }
680     #elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
681     {
682         /* The event group could have been allocated statically or
683          * dynamically, so check before attempting to free the memory. */
684         if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
685         {
686             vPortFree( pxEventBits );
687         }
688         else
689         {
690             mtCOVERAGE_TEST_MARKER();
691         }
692     }
693     #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
694
695     traceRETURN_vEventGroupDelete();
696 }
697 /*-----------------------------------------------------------*/
698
699 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
700     BaseType_t xEventGroupGetStaticBuffer( EventGroupHandle_t xEventGroup,
701                                            StaticEventGroup_t ** ppxEventGroupBuffer )
702     {
703         BaseType_t xReturn;
704         EventGroup_t * pxEventBits = xEventGroup;
705
706         traceENTER_xEventGroupGetStaticBuffer( xEventGroup, ppxEventGroupBuffer );
707
708         configASSERT( pxEventBits );
709         configASSERT( ppxEventGroupBuffer );
710
711         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
712         {
713             /* Check if the event group was statically allocated. */
714             if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdTRUE )
715             {
716                 /* MISRA Ref 11.3.1 [Misaligned access] */
717                 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
718                 /* coverity[misra_c_2012_rule_11_3_violation] */
719                 *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
720                 xReturn = pdTRUE;
721             }
722             else
723             {
724                 xReturn = pdFALSE;
725             }
726         }
727         #else /* configSUPPORT_DYNAMIC_ALLOCATION */
728         {
729             /* Event group must have been statically allocated. */
730             /* MISRA Ref 11.3.1 [Misaligned access] */
731             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
732             /* coverity[misra_c_2012_rule_11_3_violation] */
733             *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
734             xReturn = pdTRUE;
735         }
736         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
737
738         traceRETURN_xEventGroupGetStaticBuffer( xReturn );
739
740         return xReturn;
741     }
742 #endif /* configSUPPORT_STATIC_ALLOCATION */
743 /*-----------------------------------------------------------*/
744
745 /* For internal use only - execute a 'set bits' command that was pended from
746  * an interrupt. */
747 void vEventGroupSetBitsCallback( void * pvEventGroup,
748                                  const uint32_t ulBitsToSet )
749 {
750     traceENTER_vEventGroupSetBitsCallback( pvEventGroup, ulBitsToSet );
751
752     ( 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. */
753
754     traceRETURN_vEventGroupSetBitsCallback();
755 }
756 /*-----------------------------------------------------------*/
757
758 /* For internal use only - execute a 'clear bits' command that was pended from
759  * an interrupt. */
760 void vEventGroupClearBitsCallback( void * pvEventGroup,
761                                    const uint32_t ulBitsToClear )
762 {
763     traceENTER_vEventGroupClearBitsCallback( pvEventGroup, ulBitsToClear );
764
765     ( 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. */
766
767     traceRETURN_vEventGroupClearBitsCallback();
768 }
769 /*-----------------------------------------------------------*/
770
771 static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
772                                         const EventBits_t uxBitsToWaitFor,
773                                         const BaseType_t xWaitForAllBits )
774 {
775     BaseType_t xWaitConditionMet = pdFALSE;
776
777     if( xWaitForAllBits == pdFALSE )
778     {
779         /* Task only has to wait for one bit within uxBitsToWaitFor to be
780          * set.  Is one already set? */
781         if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
782         {
783             xWaitConditionMet = pdTRUE;
784         }
785         else
786         {
787             mtCOVERAGE_TEST_MARKER();
788         }
789     }
790     else
791     {
792         /* Task has to wait for all the bits in uxBitsToWaitFor to be set.
793          * Are they set already? */
794         if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
795         {
796             xWaitConditionMet = pdTRUE;
797         }
798         else
799         {
800             mtCOVERAGE_TEST_MARKER();
801         }
802     }
803
804     return xWaitConditionMet;
805 }
806 /*-----------------------------------------------------------*/
807
808 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
809
810     BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
811                                           const EventBits_t uxBitsToSet,
812                                           BaseType_t * pxHigherPriorityTaskWoken )
813     {
814         BaseType_t xReturn;
815
816         traceENTER_xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken );
817
818         traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
819         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. */
820
821         traceRETURN_xEventGroupSetBitsFromISR( xReturn );
822
823         return xReturn;
824     }
825
826 #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
827 /*-----------------------------------------------------------*/
828
829 #if ( configUSE_TRACE_FACILITY == 1 )
830
831     UBaseType_t uxEventGroupGetNumber( void * xEventGroup )
832     {
833         UBaseType_t xReturn;
834         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. */
835
836         traceENTER_uxEventGroupGetNumber( xEventGroup );
837
838         if( xEventGroup == NULL )
839         {
840             xReturn = 0;
841         }
842         else
843         {
844             xReturn = pxEventBits->uxEventGroupNumber;
845         }
846
847         traceRETURN_uxEventGroupGetNumber( xReturn );
848
849         return xReturn;
850     }
851
852 #endif /* configUSE_TRACE_FACILITY */
853 /*-----------------------------------------------------------*/
854
855 #if ( configUSE_TRACE_FACILITY == 1 )
856
857     void vEventGroupSetNumber( void * xEventGroup,
858                                UBaseType_t uxEventGroupNumber )
859     {
860         traceENTER_vEventGroupSetNumber( xEventGroup, uxEventGroupNumber );
861
862         ( ( 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. */
863
864         traceRETURN_vEventGroupSetNumber();
865     }
866
867 #endif /* configUSE_TRACE_FACILITY */
868 /*-----------------------------------------------------------*/