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