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