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