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