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