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