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