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