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