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