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 /* 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 ( ( 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 ( ( 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, uxReturnBits;
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             /* Snapshot resulting bits. */
640             uxReturnBits = pxEventBits->uxEventBits;
641         }
642         ( void ) xTaskResumeAll();
643 
644         traceRETURN_xEventGroupSetBits( uxReturnBits );
645 
646         return uxReturnBits;
647     }
648 /*-----------------------------------------------------------*/
649 
vEventGroupDelete(EventGroupHandle_t xEventGroup)650     void vEventGroupDelete( EventGroupHandle_t xEventGroup )
651     {
652         EventGroup_t * pxEventBits = xEventGroup;
653         const List_t * pxTasksWaitingForBits;
654 
655         traceENTER_vEventGroupDelete( xEventGroup );
656 
657         configASSERT( pxEventBits );
658 
659         pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
660 
661         vTaskSuspendAll();
662         {
663             traceEVENT_GROUP_DELETE( xEventGroup );
664 
665             while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
666             {
667                 /* Unblock the task, returning 0 as the event list is being deleted
668                  * and cannot therefore have any bits set. */
669                 configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
670                 vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
671             }
672         }
673         ( void ) xTaskResumeAll();
674 
675         #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
676         {
677             /* The event group can only have been allocated dynamically - free
678              * it again. */
679             vPortFree( pxEventBits );
680         }
681         #elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
682         {
683             /* The event group could have been allocated statically or
684              * dynamically, so check before attempting to free the memory. */
685             if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
686             {
687                 vPortFree( pxEventBits );
688             }
689             else
690             {
691                 mtCOVERAGE_TEST_MARKER();
692             }
693         }
694         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
695 
696         traceRETURN_vEventGroupDelete();
697     }
698 /*-----------------------------------------------------------*/
699 
700     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
xEventGroupGetStaticBuffer(EventGroupHandle_t xEventGroup,StaticEventGroup_t ** ppxEventGroupBuffer)701         BaseType_t xEventGroupGetStaticBuffer( EventGroupHandle_t xEventGroup,
702                                                StaticEventGroup_t ** ppxEventGroupBuffer )
703         {
704             BaseType_t xReturn;
705             EventGroup_t * pxEventBits = xEventGroup;
706 
707             traceENTER_xEventGroupGetStaticBuffer( xEventGroup, ppxEventGroupBuffer );
708 
709             configASSERT( pxEventBits );
710             configASSERT( ppxEventGroupBuffer );
711 
712             #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
713             {
714                 /* Check if the event group was statically allocated. */
715                 if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdTRUE )
716                 {
717                     /* MISRA Ref 11.3.1 [Misaligned access] */
718                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
719                     /* coverity[misra_c_2012_rule_11_3_violation] */
720                     *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
721                     xReturn = pdTRUE;
722                 }
723                 else
724                 {
725                     xReturn = pdFALSE;
726                 }
727             }
728             #else /* configSUPPORT_DYNAMIC_ALLOCATION */
729             {
730                 /* Event group must have been statically allocated. */
731                 /* MISRA Ref 11.3.1 [Misaligned access] */
732                 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
733                 /* coverity[misra_c_2012_rule_11_3_violation] */
734                 *ppxEventGroupBuffer = ( StaticEventGroup_t * ) pxEventBits;
735                 xReturn = pdTRUE;
736             }
737             #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
738 
739             traceRETURN_xEventGroupGetStaticBuffer( xReturn );
740 
741             return xReturn;
742         }
743     #endif /* configSUPPORT_STATIC_ALLOCATION */
744 /*-----------------------------------------------------------*/
745 
746 /* For internal use only - execute a 'set bits' command that was pended from
747  * an interrupt. */
vEventGroupSetBitsCallback(void * pvEventGroup,uint32_t ulBitsToSet)748     void vEventGroupSetBitsCallback( void * pvEventGroup,
749                                      uint32_t ulBitsToSet )
750     {
751         traceENTER_vEventGroupSetBitsCallback( pvEventGroup, ulBitsToSet );
752 
753         /* MISRA Ref 11.5.4 [Callback function parameter] */
754         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
755         /* coverity[misra_c_2012_rule_11_5_violation] */
756         ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet );
757 
758         traceRETURN_vEventGroupSetBitsCallback();
759     }
760 /*-----------------------------------------------------------*/
761 
762 /* For internal use only - execute a 'clear bits' command that was pended from
763  * an interrupt. */
vEventGroupClearBitsCallback(void * pvEventGroup,uint32_t ulBitsToClear)764     void vEventGroupClearBitsCallback( void * pvEventGroup,
765                                        uint32_t ulBitsToClear )
766     {
767         traceENTER_vEventGroupClearBitsCallback( pvEventGroup, ulBitsToClear );
768 
769         /* MISRA Ref 11.5.4 [Callback function parameter] */
770         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
771         /* coverity[misra_c_2012_rule_11_5_violation] */
772         ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear );
773 
774         traceRETURN_vEventGroupClearBitsCallback();
775     }
776 /*-----------------------------------------------------------*/
777 
prvTestWaitCondition(const EventBits_t uxCurrentEventBits,const EventBits_t uxBitsToWaitFor,const BaseType_t xWaitForAllBits)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 ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
816 
xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t * pxHigherPriorityTaskWoken)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 );
827 
828             traceRETURN_xEventGroupSetBitsFromISR( xReturn );
829 
830             return xReturn;
831         }
832 
833     #endif /* if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
834 /*-----------------------------------------------------------*/
835 
836     #if ( configUSE_TRACE_FACILITY == 1 )
837 
uxEventGroupGetNumber(void * xEventGroup)838         UBaseType_t uxEventGroupGetNumber( void * xEventGroup )
839         {
840             UBaseType_t xReturn;
841 
842             /* MISRA Ref 11.5.2 [Opaque pointer] */
843             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
844             /* coverity[misra_c_2012_rule_11_5_violation] */
845             EventGroup_t const * pxEventBits = ( EventGroup_t * ) xEventGroup;
846 
847             traceENTER_uxEventGroupGetNumber( xEventGroup );
848 
849             if( xEventGroup == NULL )
850             {
851                 xReturn = 0;
852             }
853             else
854             {
855                 xReturn = pxEventBits->uxEventGroupNumber;
856             }
857 
858             traceRETURN_uxEventGroupGetNumber( xReturn );
859 
860             return xReturn;
861         }
862 
863     #endif /* configUSE_TRACE_FACILITY */
864 /*-----------------------------------------------------------*/
865 
866     #if ( configUSE_TRACE_FACILITY == 1 )
867 
vEventGroupSetNumber(void * xEventGroup,UBaseType_t uxEventGroupNumber)868         void vEventGroupSetNumber( void * xEventGroup,
869                                    UBaseType_t uxEventGroupNumber )
870         {
871             traceENTER_vEventGroupSetNumber( xEventGroup, uxEventGroupNumber );
872 
873             /* MISRA Ref 11.5.2 [Opaque pointer] */
874             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
875             /* coverity[misra_c_2012_rule_11_5_violation] */
876             ( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber;
877 
878             traceRETURN_vEventGroupSetNumber();
879         }
880 
881     #endif /* configUSE_TRACE_FACILITY */
882 /*-----------------------------------------------------------*/
883 
884 /* This entire source file will be skipped if the application is not configured
885  * to include event groups functionality. If you want to include event groups
886  * then ensure configUSE_EVENT_GROUPS is set to 1 in FreeRTOSConfig.h. */
887 #endif /* configUSE_EVENT_GROUPS == 1 */
888