blob: 01144ad53e49b7112209b1ecdb0ad36bc3e2443a [file] [log] [blame]
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08001/*
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#include <string.h>
31
32/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33all the API functions to use the MPU wrappers. That should only be done when
34task.h is included from an application file. */
35#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
36
37/* FreeRTOS includes. */
38#include "FreeRTOS.h"
39#include "task.h"
40#include "timers.h"
41#include "stack_macros.h"
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +080042#if ENABLE_FTRACE
43#include "ftrace.h"
44#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +080045
46/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
47because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
48for the header files above, but not in this file, in order to generate the
49correct privileged Vs unprivileged linkage and placement. */
50#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
51
52/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
53functions but without including stdio.h here. */
54#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
55 /* At the bottom of this file are two optional functions that can be used
56 to generate human readable text from the raw data generated by the
57 uxTaskGetSystemState() function. Note the formatting functions are provided
58 for convenience only, and are NOT considered part of the kernel. */
59 #include <stdio.h>
60#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
61
62#if( configUSE_PREEMPTION == 0 )
63 /* If the cooperative scheduler is being used then a yield should not be
64 performed just because a higher priority task has been woken. */
65 #define taskYIELD_IF_USING_PREEMPTION()
66#else
67 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
68#endif
69
70/* Values that can be assigned to the ucNotifyState member of the TCB. */
71#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 )
72#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
73#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
74
75/*
76 * The value used to fill the stack of a task when the task is created. This
77 * is used purely for checking the high water mark for tasks.
78 */
79#define tskSTACK_FILL_BYTE ( 0xa5U )
80
81/* Bits used to recored how a task's stack and TCB were allocated. */
82#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
83#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
84#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
85
86/* If any of the following are set then task stacks are filled with a known
87value so the high water mark can be determined. If none of the following are
88set then don't fill the stack so there is no unnecessary dependency on memset. */
89#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
90 #define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
91#else
92 #define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
93#endif
94
95/*
96 * Macros used by vListTask to indicate which state a task is in.
97 */
98#define tskRUNNING_CHAR ( 'X' )
99#define tskBLOCKED_CHAR ( 'B' )
100#define tskREADY_CHAR ( 'R' )
101#define tskDELETED_CHAR ( 'D' )
102#define tskSUSPENDED_CHAR ( 'S' )
103
104/*
105 * Some kernel aware debuggers require the data the debugger needs access to be
106 * global, rather than file scope.
107 */
108#ifdef portREMOVE_STATIC_QUALIFIER
109 #define static
110#endif
111
112/* The name allocated to the Idle task. This can be overridden by defining
113configIDLE_TASK_NAME in FreeRTOSConfig.h. */
114#ifndef configIDLE_TASK_NAME
115 #define configIDLE_TASK_NAME "IDLE"
116#endif
117
118#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
119
120 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
121 performed in a generic way that is not optimised to any particular
122 microcontroller architecture. */
123
124 /* uxTopReadyPriority holds the priority of the highest priority ready
125 state task. */
126 #define taskRECORD_READY_PRIORITY( uxPriority ) \
127 { \
128 if( ( uxPriority ) > uxTopReadyPriority ) \
129 { \
130 uxTopReadyPriority = ( uxPriority ); \
131 } \
132 } /* taskRECORD_READY_PRIORITY */
133
134 /*-----------------------------------------------------------*/
135
136 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
137 { \
138 UBaseType_t uxTopPriority = uxTopReadyPriority; \
139 \
140 /* Find the highest priority queue that contains ready tasks. */ \
141 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
142 { \
143 configASSERT( uxTopPriority ); \
144 --uxTopPriority; \
145 } \
146 \
147 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
148 the same priority get an equal share of the processor time. */ \
149 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
150 uxTopReadyPriority = uxTopPriority; \
151 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
152
153 /*-----------------------------------------------------------*/
154
155 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
156 they are only required when a port optimised method of task selection is
157 being used. */
158 #define taskRESET_READY_PRIORITY( uxPriority )
159 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
160
161#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
162
163 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
164 performed in a way that is tailored to the particular microcontroller
165 architecture being used. */
166
167 /* A port optimised version is provided. Call the port defined macros. */
168 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
169
170 /*-----------------------------------------------------------*/
171
172 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
173 { \
174 UBaseType_t uxTopPriority; \
175 \
176 /* Find the highest priority list that contains ready tasks. */ \
177 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
178 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
179 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
180 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
181
182 /*-----------------------------------------------------------*/
183
184 /* A port optimised version is provided, call it only if the TCB being reset
185 is being referenced from a ready list. If it is referenced from a delayed
186 or suspended list then it won't be in a ready list. */
187 #define taskRESET_READY_PRIORITY( uxPriority ) \
188 { \
189 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
190 { \
191 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
192 } \
193 }
194
195#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
196
197/*-----------------------------------------------------------*/
198
199/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
200count overflows. */
201#define taskSWITCH_DELAYED_LISTS() \
202{ \
203 List_t *pxTemp; \
204 \
205 /* The delayed tasks list should be empty when the lists are switched. */ \
206 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
207 \
208 pxTemp = pxDelayedTaskList; \
209 pxDelayedTaskList = pxOverflowDelayedTaskList; \
210 pxOverflowDelayedTaskList = pxTemp; \
211 xNumOfOverflows++; \
212 prvResetNextTaskUnblockTime(); \
213}
214
215/*-----------------------------------------------------------*/
216
217/*
218 * Place the task represented by pxTCB into the appropriate ready list for
219 * the task. It is inserted at the end of the list.
220 */
221#define prvAddTaskToReadyList( pxTCB ) \
222 traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
223 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
224 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
225 tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
226/*-----------------------------------------------------------*/
227
228/*
229 * Several functions take an TaskHandle_t parameter that can optionally be NULL,
230 * where NULL is used to indicate that the handle of the currently executing
231 * task should be used in place of the parameter. This macro simply checks to
232 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
233 */
234#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )
235
236/* The item value of the event list item is normally used to hold the priority
237of the task to which it belongs (coded to allow it to be held in reverse
238priority order). However, it is occasionally borrowed for other purposes. It
239is important its value is not updated due to a task priority change while it is
240being used for another purpose. The following bit definition is used to inform
241the scheduler that the value should not be changed - in which case it is the
242responsibility of whichever module is using the value to ensure it gets set back
243to its original value when it is released. */
244#if( configUSE_16_BIT_TICKS == 1 )
245 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
246#else
247 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
248#endif
249
250/*
251 * Task control block. A task control block (TCB) is allocated for each task,
252 * and stores task state information, including a pointer to the task's context
253 * (the task's run time environment, including register values)
254 */
255typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
256{
257 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
258
259 #if ( portUSING_MPU_WRAPPERS == 1 )
260 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
261 #endif
262
263 ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
264 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
265 UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
266 StackType_t *pxStack; /*< Points to the start of the stack. */
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800267 StackType_t uStackDepth;
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800268 char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
269
270 #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
271 StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
272 #endif
273
274 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
275 UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
276 #endif
277
278 #if ( configUSE_TRACE_FACILITY == 1 )
279 UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
280 UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
281 #endif
282
283 #if ( configUSE_MUTEXES == 1 )
284 UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
285 UBaseType_t uxMutexesHeld;
286 #endif
287
288 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
289 TaskHookFunction_t pxTaskTag;
290 #endif
291
292 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
293 void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
294 #endif
295
296 #if( configGENERATE_RUN_TIME_STATS == 1 )
297 uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
298 #endif
299
300 #if ( configUSE_NEWLIB_REENTRANT == 1 )
301 /* Allocate a Newlib reent structure that is specific to this task.
302 Note Newlib support has been included by popular demand, but is not
303 used by the FreeRTOS maintainers themselves. FreeRTOS is not
304 responsible for resulting newlib operation. User must be familiar with
305 newlib and must provide system-wide implementations of the necessary
306 stubs. Be warned that (at the time of writing) the current newlib design
307 implements a system-wide malloc() that must be provided with locks. */
308 struct _reent xNewLib_reent;
309 #endif
310
311 #if( configUSE_TASK_NOTIFICATIONS == 1 )
312 volatile uint32_t ulNotifiedValue;
313 volatile uint8_t ucNotifyState;
314 #endif
315
316 /* See the comments in FreeRTOS.h with the definition of
317 tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
318 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
319 uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
320 #endif
321
322 #if( INCLUDE_xTaskAbortDelay == 1 )
323 uint8_t ucDelayAborted;
324 #endif
325
326 #if( configUSE_POSIX_ERRNO == 1 )
327 int iTaskErrno;
328 #endif
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800329 #if ( configUSE_TASK_START_HOOK == 1 )
330 void *pxTaskFun;
331 void *pxTaskPara;
332 #endif
333 #if ENABLE_KASAN
334 int kasan_depth;
335 #endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800336} tskTCB;
337
338/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
339below to enable the use of older kernel aware debuggers. */
340typedef tskTCB TCB_t;
341
342/*lint -save -e956 A manual analysis and inspection has been used to determine
343which static variables must be declared volatile. */
344PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
345
346/* Lists for ready and blocked tasks. --------------------
347xDelayedTaskList1 and xDelayedTaskList2 could be move to function scople but
348doing so breaks some kernel aware debuggers and debuggers that rely on removing
349the static qualifier. */
350PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
351PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */
352PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
353PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
354PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
355PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
356
357#if( INCLUDE_vTaskDelete == 1 )
358
359 PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */
360 PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;
361
362#endif
363
364#if ( INCLUDE_vTaskSuspend == 1 )
365
366 PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */
367
368#endif
369
370/* Global POSIX errno. Its value is changed upon context switching to match
371the errno of the currently running task. */
372#if ( configUSE_POSIX_ERRNO == 1 )
373 int FreeRTOS_errno = 0;
374#endif
375
376/* Other file private variables. --------------------------------*/
377PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
378PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
379PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
380PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
381PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
382PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
383PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
384PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
385PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
386PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
387
388/* Context switches are held pending while the scheduler is suspended. Also,
389interrupts must not manipulate the xStateListItem of a TCB, or any of the
390lists the xStateListItem can be referenced from, if the scheduler is suspended.
391If an interrupt needs to unblock a task while the scheduler is suspended then it
392moves the task's event list item into the xPendingReadyList, ready for the
393kernel to move the task from the pending ready list into the real ready list
394when the scheduler is unsuspended. The pending ready list itself can only be
395accessed from a critical section. */
396PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
397
398#if ( configGENERATE_RUN_TIME_STATS == 1 )
399
400 /* Do not move these variables to function scope as doing so prevents the
401 code working with debuggers that need to remove the static qualifier. */
402 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
403 PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
404
405#endif
406
407/*lint -restore */
408
409/*-----------------------------------------------------------*/
410
411/* Callback function prototypes. --------------------------*/
412#if( configCHECK_FOR_STACK_OVERFLOW > 0 )
413
414 extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
415
416#endif
417
418#if( configUSE_TICK_HOOK > 0 )
419
420 extern void vApplicationTickHook( void ); /*lint !e526 Symbol not defined as it is an application callback. */
421
422#endif
423
424#if( configSUPPORT_STATIC_ALLOCATION == 1 )
425
426 extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); /*lint !e526 Symbol not defined as it is an application callback. */
427
428#endif
429
430/* File private functions. --------------------------------*/
431
432/**
433 * Utility task that simply returns pdTRUE if the task referenced by xTask is
434 * currently in the Suspended state, or pdFALSE if the task referenced by xTask
435 * is in any other state.
436 */
437#if ( INCLUDE_vTaskSuspend == 1 )
438
439 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
440
441#endif /* INCLUDE_vTaskSuspend */
442
443/*
444 * Utility to ready all the lists used by the scheduler. This is called
445 * automatically upon the creation of the first task.
446 */
447static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
448
449/*
450 * The idle task, which as all tasks is implemented as a never ending loop.
451 * The idle task is automatically created and added to the ready lists upon
452 * creation of the first user task.
453 *
454 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
455 * language extensions. The equivalent prototype for this function is:
456 *
457 * void prvIdleTask( void *pvParameters );
458 *
459 */
460static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
461
462/*
463 * Utility to free all memory allocated by the scheduler to hold a TCB,
464 * including the stack pointed to by the TCB.
465 *
466 * This does not free memory allocated by the task itself (i.e. memory
467 * allocated by calls to pvPortMalloc from within the tasks application code).
468 */
469#if ( INCLUDE_vTaskDelete == 1 )
470
471 static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION;
472
473#endif
474
475/*
476 * Used only by the idle task. This checks to see if anything has been placed
477 * in the list of tasks waiting to be deleted. If so the task is cleaned up
478 * and its TCB deleted.
479 */
480static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
481
482/*
483 * The currently executing task is entering the Blocked state. Add the task to
484 * either the current or the overflow delayed task list.
485 */
486static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION;
487
488/*
489 * Fills an TaskStatus_t structure with information on each task that is
490 * referenced from the pxList list (which may be a ready list, a delayed list,
491 * a suspended list, etc.).
492 *
493 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
494 * NORMAL APPLICATION CODE.
495 */
496#if ( configUSE_TRACE_FACILITY == 1 )
497
498 static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
499
500#endif
501
502/*
503 * Searches pxList for a task with name pcNameToQuery - returning a handle to
504 * the task if it is found, or NULL if the task is not found.
505 */
506#if ( INCLUDE_xTaskGetHandle == 1 )
507
508 static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION;
509
510#endif
511
512/*
513 * When a task is created, the stack of the task is filled with a known value.
514 * This function determines the 'high water mark' of the task stack by
515 * determining how much of the stack remains at the original preset value.
516 */
517#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
518
519 static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION;
520
521#endif
522
523/*
524 * Return the amount of time, in ticks, that will pass before the kernel will
525 * next move a task from the Blocked state to the Running state.
526 *
527 * This conditional compilation should use inequality to 0, not equality to 1.
528 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
529 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
530 * set to a value other than 1.
531 */
532#if ( configUSE_TICKLESS_IDLE != 0 )
533
534 static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
535
536#endif
537
538/*
539 * Set xNextTaskUnblockTime to the time at which the next Blocked state task
540 * will exit the Blocked state.
541 */
542static void prvResetNextTaskUnblockTime( void );
543
544#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
545
546 /*
547 * Helper function used to pad task names with spaces when printing out
548 * human readable tables of task information.
549 */
550 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION;
551
552#endif
553
554/*
555 * Called after a Task_t structure has been allocated either statically or
556 * dynamically to fill in the structure's members.
557 */
558static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
559 const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
560 const uint32_t ulStackDepth,
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800561 void * pvParameters,
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800562 UBaseType_t uxPriority,
563 TaskHandle_t * const pxCreatedTask,
564 TCB_t *pxNewTCB,
565 const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
566
567/*
568 * Called after a new task has been created and initialised to place the task
569 * under the control of the scheduler.
570 */
571static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
572
573/*
574 * freertos_tasks_c_additions_init() should only be called if the user definable
575 * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
576 * called by the function.
577 */
578#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
579
580 static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION;
581
582#endif
583
584/*-----------------------------------------------------------*/
585
586#if( configSUPPORT_STATIC_ALLOCATION == 1 )
587
588 TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
589 const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
590 const uint32_t ulStackDepth,
591 void * const pvParameters,
592 UBaseType_t uxPriority,
593 StackType_t * const puxStackBuffer,
594 StaticTask_t * const pxTaskBuffer )
595 {
596 TCB_t *pxNewTCB;
597 TaskHandle_t xReturn;
598
599 configASSERT( puxStackBuffer != NULL );
600 configASSERT( pxTaskBuffer != NULL );
601
602 #if( configASSERT_DEFINED == 1 )
603 {
604 /* Sanity check that the size of the structure used to declare a
605 variable of type StaticTask_t equals the size of the real task
606 structure. */
607 volatile size_t xSize = sizeof( StaticTask_t );
608 configASSERT( xSize == sizeof( TCB_t ) );
609 ( void ) xSize; /* Prevent lint warning when configASSERT() is not used. */
610 }
611 #endif /* configASSERT_DEFINED */
612
613
614 if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
615 {
616 /* The memory used for the task's TCB and stack are passed into this
617 function - use them. */
618 pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
619 pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
620
621 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
622 {
623 /* Tasks can be created statically or dynamically, so note this
624 task was created statically in case the task is later deleted. */
625 pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
626 }
627 #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
628
629 prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
630 prvAddNewTaskToReadyList( pxNewTCB );
631 }
632 else
633 {
634 xReturn = NULL;
635 }
636
637 return xReturn;
638 }
639
640#endif /* SUPPORT_STATIC_ALLOCATION */
641/*-----------------------------------------------------------*/
642
643#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
644
645 BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
646 {
647 TCB_t *pxNewTCB;
648 BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
649
650 configASSERT( pxTaskDefinition->puxStackBuffer != NULL );
651 configASSERT( pxTaskDefinition->pxTaskBuffer != NULL );
652
653 if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != NULL ) )
654 {
655 /* Allocate space for the TCB. Where the memory comes from depends
656 on the implementation of the port malloc function and whether or
657 not static allocation is being used. */
658 pxNewTCB = ( TCB_t * ) pxTaskDefinition->pxTaskBuffer;
659
660 /* Store the stack location in the TCB. */
661 pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
662
663 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
664 {
665 /* Tasks can be created statically or dynamically, so note this
666 task was created statically in case the task is later deleted. */
667 pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
668 }
669 #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
670
671 prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
672 pxTaskDefinition->pcName,
673 ( uint32_t ) pxTaskDefinition->usStackDepth,
674 pxTaskDefinition->pvParameters,
675 pxTaskDefinition->uxPriority,
676 pxCreatedTask, pxNewTCB,
677 pxTaskDefinition->xRegions );
678
679 prvAddNewTaskToReadyList( pxNewTCB );
680 xReturn = pdPASS;
681 }
682
683 return xReturn;
684 }
685
686#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
687/*-----------------------------------------------------------*/
688
689#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
690
691 BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
692 {
693 TCB_t *pxNewTCB;
694 BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
695
696 configASSERT( pxTaskDefinition->puxStackBuffer );
697
698 if( pxTaskDefinition->puxStackBuffer != NULL )
699 {
700 /* Allocate space for the TCB. Where the memory comes from depends
701 on the implementation of the port malloc function and whether or
702 not static allocation is being used. */
703 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
704
705 if( pxNewTCB != NULL )
706 {
707 /* Store the stack location in the TCB. */
708 pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
709
710 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
711 {
712 /* Tasks can be created statically or dynamically, so note
713 this task had a statically allocated stack in case it is
714 later deleted. The TCB was allocated dynamically. */
715 pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY;
716 }
717 #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
718
719 prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
720 pxTaskDefinition->pcName,
721 ( uint32_t ) pxTaskDefinition->usStackDepth,
722 pxTaskDefinition->pvParameters,
723 pxTaskDefinition->uxPriority,
724 pxCreatedTask, pxNewTCB,
725 pxTaskDefinition->xRegions );
726
727 prvAddNewTaskToReadyList( pxNewTCB );
728 xReturn = pdPASS;
729 }
730 }
731
732 return xReturn;
733 }
734
735#endif /* portUSING_MPU_WRAPPERS */
736/*-----------------------------------------------------------*/
737
738#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
739
740 BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
741 const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
742 const configSTACK_DEPTH_TYPE usStackDepth,
743 void * const pvParameters,
744 UBaseType_t uxPriority,
745 TaskHandle_t * const pxCreatedTask )
746 {
747 TCB_t *pxNewTCB;
748 BaseType_t xReturn;
749
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800750
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800751 /* If the stack grows down then allocate the stack then the TCB so the stack
752 does not grow into the TCB. Likewise if the stack grows up then allocate
753 the TCB then the stack. */
754 #if( portSTACK_GROWTH > 0 )
755 {
756 /* Allocate space for the TCB. Where the memory comes from depends on
757 the implementation of the port malloc function and whether or not static
758 allocation is being used. */
759 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
760
761 if( pxNewTCB != NULL )
762 {
763 /* Allocate space for the stack used by the task being created.
764 The base of the stack memory stored in the TCB so the task can
765 be deleted later if required. */
766 pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
767
768 if( pxNewTCB->pxStack == NULL )
769 {
770 /* Could not allocate the stack. Delete the allocated TCB. */
771 vPortFree( pxNewTCB );
772 pxNewTCB = NULL;
773 }
774 }
775 }
776 #else /* portSTACK_GROWTH */
777 {
778 StackType_t *pxStack;
779
780 /* Allocate space for the stack used by the task being created. */
781 pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */
782
783 if( pxStack != NULL )
784 {
785 /* Allocate space for the TCB. */
786 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */
787
788 if( pxNewTCB != NULL )
789 {
790 /* Store the stack location in the TCB. */
791 pxNewTCB->pxStack = pxStack;
792 }
793 else
794 {
795 /* The stack cannot be used as the TCB was not created. Free
796 it again. */
797 vPortFree( pxStack );
798 }
799 }
800 else
801 {
802 pxNewTCB = NULL;
803 }
804 }
805 #endif /* portSTACK_GROWTH */
806
807 if( pxNewTCB != NULL )
808 {
809 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */
810 {
811 /* Tasks can be created statically or dynamically, so note this
812 task was created dynamically in case it is later deleted. */
813 pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
814 }
815 #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
816
817 prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
818 prvAddNewTaskToReadyList( pxNewTCB );
819 xReturn = pdPASS;
820 }
821 else
822 {
823 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
824 }
825
826 return xReturn;
827 }
828
829#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
830/*-----------------------------------------------------------*/
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800831#if ( configUSE_TASK_START_HOOK == 1 )
832static void prvTaskFunWrp( void *para)
833{
834 TCB_t *pxNewTCB = (TCB_t *)para;
835 {
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800836
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800837 extern void vApplicationTaskStartHook( void );
838 vApplicationTaskStartHook();
839 }
840 ((TaskFunction_t)pxNewTCB->pxTaskFun)(pxNewTCB->pxTaskPara);
841}
842#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800843static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
844 const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
845 const uint32_t ulStackDepth,
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800846 void * pvParameters,
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800847 UBaseType_t uxPriority,
848 TaskHandle_t * const pxCreatedTask,
849 TCB_t *pxNewTCB,
850 const MemoryRegion_t * const xRegions )
851{
852StackType_t *pxTopOfStack;
853UBaseType_t x;
854
855 #if( portUSING_MPU_WRAPPERS == 1 )
856 /* Should the task be created in privileged mode? */
857 BaseType_t xRunPrivileged;
858 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
859 {
860 xRunPrivileged = pdTRUE;
861 }
862 else
863 {
864 xRunPrivileged = pdFALSE;
865 }
866 uxPriority &= ~portPRIVILEGE_BIT;
867 #endif /* portUSING_MPU_WRAPPERS == 1 */
868
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +0800869 #if ENABLE_KASAN
870 pxNewTCB->kasan_depth = 0;
871 #endif
872
873 #if ( configUSE_TASK_START_HOOK == 1 )
874 pxNewTCB->pxTaskFun = pxTaskCode;
875 pxNewTCB->pxTaskPara = pvParameters;
876 pxTaskCode = prvTaskFunWrp;
877 pvParameters = pxNewTCB;
878 #endif
879
880 pxNewTCB->uStackDepth = ulStackDepth;
kelvin.zhang57fb6ae2021-10-15 10:19:42 +0800881 /* Avoid dependency on memset() if it is not required. */
882 #if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
883 {
884 /* Fill the stack with a known value to assist debugging. */
885 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
886 }
887 #endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
888
889 /* Calculate the top of stack address. This depends on whether the stack
890 grows from high memory to low (as per the 80x86) or vice versa.
891 portSTACK_GROWTH is used to make the result positive or negative as required
892 by the port. */
893 #if( portSTACK_GROWTH < 0 )
894 {
895 pxTopOfStack = &( pxNewTCB->pxStack[ ulStackDepth - ( uint32_t ) 1 ] );
896 pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 !e9033 !e9078 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. Checked by assert(). */
897
898 /* Check the alignment of the calculated top of stack is correct. */
899 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
900
901 #if( configRECORD_STACK_HIGH_ADDRESS == 1 )
902 {
903 /* Also record the stack's high address, which may assist
904 debugging. */
905 pxNewTCB->pxEndOfStack = pxTopOfStack;
906 }
907 #endif /* configRECORD_STACK_HIGH_ADDRESS */
908 }
909 #else /* portSTACK_GROWTH */
910 {
911 pxTopOfStack = pxNewTCB->pxStack;
912
913 /* Check the alignment of the stack buffer is correct. */
914 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
915
916 /* The other extreme of the stack space is required if stack checking is
917 performed. */
918 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
919 }
920 #endif /* portSTACK_GROWTH */
921
922 /* Store the task name in the TCB. */
923 if( pcName != NULL )
924 {
925 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
926 {
927 pxNewTCB->pcTaskName[ x ] = pcName[ x ];
928
929 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
930 configMAX_TASK_NAME_LEN characters just in case the memory after the
931 string is not accessible (extremely unlikely). */
932 if( pcName[ x ] == ( char ) 0x00 )
933 {
934 break;
935 }
936 else
937 {
938 mtCOVERAGE_TEST_MARKER();
939 }
940 }
941
942 /* Ensure the name string is terminated in the case that the string length
943 was greater or equal to configMAX_TASK_NAME_LEN. */
944 pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
945 }
946 else
947 {
948 /* The task has not been given a name, so just ensure there is a NULL
949 terminator when it is read out. */
950 pxNewTCB->pcTaskName[ 0 ] = 0x00;
951 }
952
953 /* This is used as an array index so must ensure it's not too large. First
954 remove the privilege bit if one is present. */
955 if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
956 {
957 uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
958 }
959 else
960 {
961 mtCOVERAGE_TEST_MARKER();
962 }
963
964 pxNewTCB->uxPriority = uxPriority;
965 #if ( configUSE_MUTEXES == 1 )
966 {
967 pxNewTCB->uxBasePriority = uxPriority;
968 pxNewTCB->uxMutexesHeld = 0;
969 }
970 #endif /* configUSE_MUTEXES */
971
972 vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
973 vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
974
975 /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get
976 back to the containing TCB from a generic item in a list. */
977 listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
978
979 /* Event lists are always in priority order. */
980 listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
981 listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
982
983 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
984 {
985 pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
986 }
987 #endif /* portCRITICAL_NESTING_IN_TCB */
988
989 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
990 {
991 pxNewTCB->pxTaskTag = NULL;
992 }
993 #endif /* configUSE_APPLICATION_TASK_TAG */
994
995 #if ( configGENERATE_RUN_TIME_STATS == 1 )
996 {
997 pxNewTCB->ulRunTimeCounter = 0UL;
998 }
999 #endif /* configGENERATE_RUN_TIME_STATS */
1000
1001 #if ( portUSING_MPU_WRAPPERS == 1 )
1002 {
1003 vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );
1004 }
1005 #else
1006 {
1007 /* Avoid compiler warning about unreferenced parameter. */
1008 ( void ) xRegions;
1009 }
1010 #endif
1011
1012 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
1013 {
1014 for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
1015 {
1016 pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
1017 }
1018 }
1019 #endif
1020
1021 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
1022 {
1023 pxNewTCB->ulNotifiedValue = 0;
1024 pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
1025 }
1026 #endif
1027
1028 #if ( configUSE_NEWLIB_REENTRANT == 1 )
1029 {
1030 /* Initialise this task's Newlib reent structure. */
1031 _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
1032 }
1033 #endif
1034
1035 #if( INCLUDE_xTaskAbortDelay == 1 )
1036 {
1037 pxNewTCB->ucDelayAborted = pdFALSE;
1038 }
1039 #endif
1040
1041 /* Initialize the TCB stack to look as if the task was already running,
1042 but had been interrupted by the scheduler. The return address is set
1043 to the start of the task function. Once the stack has been initialised
1044 the top of stack variable is updated. */
1045 #if( portUSING_MPU_WRAPPERS == 1 )
1046 {
1047 /* If the port has capability to detect stack overflow,
1048 pass the stack end address to the stack initialization
1049 function as well. */
1050 #if( portHAS_STACK_OVERFLOW_CHECKING == 1 )
1051 {
1052 #if( portSTACK_GROWTH < 0 )
1053 {
1054 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters, xRunPrivileged );
1055 }
1056 #else /* portSTACK_GROWTH */
1057 {
1058 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters, xRunPrivileged );
1059 }
1060 #endif /* portSTACK_GROWTH */
1061 }
1062 #else /* portHAS_STACK_OVERFLOW_CHECKING */
1063 {
1064 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
1065 }
1066 #endif /* portHAS_STACK_OVERFLOW_CHECKING */
1067 }
1068 #else /* portUSING_MPU_WRAPPERS */
1069 {
1070 /* If the port has capability to detect stack overflow,
1071 pass the stack end address to the stack initialization
1072 function as well. */
1073 #if( portHAS_STACK_OVERFLOW_CHECKING == 1 )
1074 {
1075 #if( portSTACK_GROWTH < 0 )
1076 {
1077 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters );
1078 }
1079 #else /* portSTACK_GROWTH */
1080 {
1081 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters );
1082 }
1083 #endif /* portSTACK_GROWTH */
1084 }
1085 #else /* portHAS_STACK_OVERFLOW_CHECKING */
1086 {
1087 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
1088 }
1089 #endif /* portHAS_STACK_OVERFLOW_CHECKING */
1090 }
1091 #endif /* portUSING_MPU_WRAPPERS */
1092
1093 if( pxCreatedTask != NULL )
1094 {
1095 /* Pass the handle out in an anonymous way. The handle can be used to
1096 change the created task's priority, delete the created task, etc.*/
1097 *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
1098 }
1099 else
1100 {
1101 mtCOVERAGE_TEST_MARKER();
1102 }
1103}
1104/*-----------------------------------------------------------*/
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08001105#ifdef configMEMORY_LEAK
1106extern struct MemLeak MemLeak_t[configMEMLEAK_ARRAY_SIZE];
1107#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08001108
1109static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
1110{
1111 /* Ensure interrupts don't access the task lists while the lists are being
1112 updated. */
1113 taskENTER_CRITICAL();
1114 {
1115 uxCurrentNumberOfTasks++;
1116 if( pxCurrentTCB == NULL )
1117 {
1118 /* There are no other tasks, or all the other tasks are in
1119 the suspended state - make this the current task. */
1120 pxCurrentTCB = pxNewTCB;
1121
1122 if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
1123 {
1124 /* This is the first task to be created so do the preliminary
1125 initialisation required. We will not recover if this call
1126 fails, but we will report the failure. */
1127 prvInitialiseTaskLists();
1128 }
1129 else
1130 {
1131 mtCOVERAGE_TEST_MARKER();
1132 }
1133 }
1134 else
1135 {
1136 /* If the scheduler is not already running, make this task the
1137 current task if it is the highest priority task to be created
1138 so far. */
1139 if( xSchedulerRunning == pdFALSE )
1140 {
1141 if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
1142 {
1143 pxCurrentTCB = pxNewTCB;
1144 }
1145 else
1146 {
1147 mtCOVERAGE_TEST_MARKER();
1148 }
1149 }
1150 else
1151 {
1152 mtCOVERAGE_TEST_MARKER();
1153 }
1154 }
1155
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08001156#ifdef configMEMORY_LEAK
1157 int i = 0;
1158
1159 if ( xSchedulerRunning != pdFALSE ) {
1160 for (i = 1; i < configMEMLEAK_ARRAY_SIZE; i ++) {
1161 if (MemLeak_t[i].Flag == 0) {
1162 uxTaskNumber = i;
1163 break;
1164 }
1165 }
1166
1167 configASSERT( i < configMEMLEAK_ARRAY_SIZE );
1168 } else {
1169 uxTaskNumber ++;
1170 }
1171 MemLeak_t[uxTaskNumber].Flag = 1;
1172#else
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08001173 uxTaskNumber++;
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08001174#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08001175
1176 #if ( configUSE_TRACE_FACILITY == 1 )
1177 {
1178 /* Add a counter into the TCB for tracing only. */
1179 pxNewTCB->uxTCBNumber = uxTaskNumber;
1180 }
1181 #endif /* configUSE_TRACE_FACILITY */
1182 traceTASK_CREATE( pxNewTCB );
1183
1184 prvAddTaskToReadyList( pxNewTCB );
1185
1186 portSETUP_TCB( pxNewTCB );
1187 }
1188 taskEXIT_CRITICAL();
1189
1190 if( xSchedulerRunning != pdFALSE )
1191 {
1192 /* If the created task is of a higher priority than the current task
1193 then it should run now. */
1194 if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
1195 {
1196 taskYIELD_IF_USING_PREEMPTION();
1197 }
1198 else
1199 {
1200 mtCOVERAGE_TEST_MARKER();
1201 }
1202 }
1203 else
1204 {
1205 mtCOVERAGE_TEST_MARKER();
1206 }
1207}
1208/*-----------------------------------------------------------*/
1209
1210#if ( INCLUDE_vTaskDelete == 1 )
1211
1212 void vTaskDelete( TaskHandle_t xTaskToDelete )
1213 {
1214 TCB_t *pxTCB;
1215
1216 taskENTER_CRITICAL();
1217 {
1218 /* If null is passed in here then it is the calling task that is
1219 being deleted. */
1220 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
1221
1222 /* Remove task from the ready list. */
1223 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1224 {
1225 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1226 }
1227 else
1228 {
1229 mtCOVERAGE_TEST_MARKER();
1230 }
1231
1232 /* Is the task waiting on an event also? */
1233 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1234 {
1235 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1236 }
1237 else
1238 {
1239 mtCOVERAGE_TEST_MARKER();
1240 }
1241
1242 /* Increment the uxTaskNumber also so kernel aware debuggers can
1243 detect that the task lists need re-generating. This is done before
1244 portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
1245 not return. */
1246 uxTaskNumber++;
1247
1248 if( pxTCB == pxCurrentTCB )
1249 {
1250 /* A task is deleting itself. This cannot complete within the
1251 task itself, as a context switch to another task is required.
1252 Place the task in the termination list. The idle task will
1253 check the termination list and free up any memory allocated by
1254 the scheduler for the TCB and stack of the deleted task. */
1255 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
1256
1257 /* Increment the ucTasksDeleted variable so the idle task knows
1258 there is a task that has been deleted and that it should therefore
1259 check the xTasksWaitingTermination list. */
1260 ++uxDeletedTasksWaitingCleanUp;
1261
1262 /* The pre-delete hook is primarily for the Windows simulator,
1263 in which Windows specific clean up operations are performed,
1264 after which it is not possible to yield away from this task -
1265 hence xYieldPending is used to latch that a context switch is
1266 required. */
1267 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
1268 }
1269 else
1270 {
1271 --uxCurrentNumberOfTasks;
1272 prvDeleteTCB( pxTCB );
1273
1274 /* Reset the next expected unblock time in case it referred to
1275 the task that has just been deleted. */
1276 prvResetNextTaskUnblockTime();
1277 }
1278
1279 traceTASK_DELETE( pxTCB );
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08001280#ifdef configMEMORY_LEAK
1281 MemLeak_t[pxTCB->uxTCBNumber].Flag = 0;
1282 MemLeak_t[pxTCB->uxTCBNumber].TaskNum = 0;
1283 MemLeak_t[pxTCB->uxTCBNumber].WantSize = 0;
1284 MemLeak_t[pxTCB->uxTCBNumber].WantTotalSize = 0;
1285 MemLeak_t[pxTCB->uxTCBNumber].MallocCount = 0;
1286 if (MemLeak_t[pxTCB->uxTCBNumber].TaskName)
1287 memset(MemLeak_t[pxTCB->uxTCBNumber].TaskName, 0, 20);
1288 MemLeak_t[pxTCB->uxTCBNumber].FreeSize = 0;
1289 MemLeak_t[pxTCB->uxTCBNumber].FreeTotalSize = 0;
1290 MemLeak_t[pxTCB->uxTCBNumber].FreeCount = 0;
1291#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08001292 }
1293 taskEXIT_CRITICAL();
1294
1295 /* Force a reschedule if it is the currently running task that has just
1296 been deleted. */
1297 if( xSchedulerRunning != pdFALSE )
1298 {
1299 if( pxTCB == pxCurrentTCB )
1300 {
1301 configASSERT( uxSchedulerSuspended == 0 );
1302 portYIELD_WITHIN_API();
1303 }
1304 else
1305 {
1306 mtCOVERAGE_TEST_MARKER();
1307 }
1308 }
1309 }
1310
1311#endif /* INCLUDE_vTaskDelete */
1312/*-----------------------------------------------------------*/
1313
1314#if ( INCLUDE_vTaskDelayUntil == 1 )
1315
1316 void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
1317 {
1318 TickType_t xTimeToWake;
1319 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
1320
1321 configASSERT( pxPreviousWakeTime );
1322 configASSERT( ( xTimeIncrement > 0U ) );
1323 configASSERT( uxSchedulerSuspended == 0 );
1324
1325 vTaskSuspendAll();
1326 {
1327 /* Minor optimisation. The tick count cannot change in this
1328 block. */
1329 const TickType_t xConstTickCount = xTickCount;
1330
1331 /* Generate the tick time at which the task wants to wake. */
1332 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
1333
1334 if( xConstTickCount < *pxPreviousWakeTime )
1335 {
1336 /* The tick count has overflowed since this function was
1337 lasted called. In this case the only time we should ever
1338 actually delay is if the wake time has also overflowed,
1339 and the wake time is greater than the tick time. When this
1340 is the case it is as if neither time had overflowed. */
1341 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
1342 {
1343 xShouldDelay = pdTRUE;
1344 }
1345 else
1346 {
1347 mtCOVERAGE_TEST_MARKER();
1348 }
1349 }
1350 else
1351 {
1352 /* The tick time has not overflowed. In this case we will
1353 delay if either the wake time has overflowed, and/or the
1354 tick time is less than the wake time. */
1355 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
1356 {
1357 xShouldDelay = pdTRUE;
1358 }
1359 else
1360 {
1361 mtCOVERAGE_TEST_MARKER();
1362 }
1363 }
1364
1365 /* Update the wake time ready for the next call. */
1366 *pxPreviousWakeTime = xTimeToWake;
1367
1368 if( xShouldDelay != pdFALSE )
1369 {
1370 traceTASK_DELAY_UNTIL( xTimeToWake );
1371
1372 /* prvAddCurrentTaskToDelayedList() needs the block time, not
1373 the time to wake, so subtract the current tick count. */
1374 prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
1375 }
1376 else
1377 {
1378 mtCOVERAGE_TEST_MARKER();
1379 }
1380 }
1381 xAlreadyYielded = xTaskResumeAll();
1382
1383 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1384 have put ourselves to sleep. */
1385 if( xAlreadyYielded == pdFALSE )
1386 {
1387 portYIELD_WITHIN_API();
1388 }
1389 else
1390 {
1391 mtCOVERAGE_TEST_MARKER();
1392 }
1393 }
1394
1395#endif /* INCLUDE_vTaskDelayUntil */
1396/*-----------------------------------------------------------*/
1397
1398#if ( INCLUDE_vTaskDelay == 1 )
1399
1400 void vTaskDelay( const TickType_t xTicksToDelay )
1401 {
1402 BaseType_t xAlreadyYielded = pdFALSE;
1403
1404 /* A delay time of zero just forces a reschedule. */
1405 if( xTicksToDelay > ( TickType_t ) 0U )
1406 {
1407 configASSERT( uxSchedulerSuspended == 0 );
1408 vTaskSuspendAll();
1409 {
1410 traceTASK_DELAY();
1411
1412 /* A task that is removed from the event list while the
1413 scheduler is suspended will not get placed in the ready
1414 list or removed from the blocked list until the scheduler
1415 is resumed.
1416
1417 This task cannot be in an event list as it is the currently
1418 executing task. */
1419 prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
1420 }
1421 xAlreadyYielded = xTaskResumeAll();
1422 }
1423 else
1424 {
1425 mtCOVERAGE_TEST_MARKER();
1426 }
1427
1428 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1429 have put ourselves to sleep. */
1430 if( xAlreadyYielded == pdFALSE )
1431 {
1432 portYIELD_WITHIN_API();
1433 }
1434 else
1435 {
1436 mtCOVERAGE_TEST_MARKER();
1437 }
1438 }
1439
1440#endif /* INCLUDE_vTaskDelay */
1441/*-----------------------------------------------------------*/
1442
1443#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_xTaskAbortDelay == 1 ) )
1444
1445 eTaskState eTaskGetState( TaskHandle_t xTask )
1446 {
1447 eTaskState eReturn;
1448 List_t const * pxStateList, *pxDelayedList, *pxOverflowedDelayedList;
1449 const TCB_t * const pxTCB = xTask;
1450
1451 configASSERT( pxTCB );
1452
1453 if( pxTCB == pxCurrentTCB )
1454 {
1455 /* The task calling this function is querying its own state. */
1456 eReturn = eRunning;
1457 }
1458 else
1459 {
1460 taskENTER_CRITICAL();
1461 {
1462 pxStateList = listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) );
1463 pxDelayedList = pxDelayedTaskList;
1464 pxOverflowedDelayedList = pxOverflowDelayedTaskList;
1465 }
1466 taskEXIT_CRITICAL();
1467
1468 if( ( pxStateList == pxDelayedList ) || ( pxStateList == pxOverflowedDelayedList ) )
1469 {
1470 /* The task being queried is referenced from one of the Blocked
1471 lists. */
1472 eReturn = eBlocked;
1473 }
1474
1475 #if ( INCLUDE_vTaskSuspend == 1 )
1476 else if( pxStateList == &xSuspendedTaskList )
1477 {
1478 /* The task being queried is referenced from the suspended
1479 list. Is it genuinely suspended or is it blocked
1480 indefinitely? */
1481 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
1482 {
1483 #if( configUSE_TASK_NOTIFICATIONS == 1 )
1484 {
1485 /* The task does not appear on the event list item of
1486 and of the RTOS objects, but could still be in the
1487 blocked state if it is waiting on its notification
1488 rather than waiting on an object. */
1489 if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
1490 {
1491 eReturn = eBlocked;
1492 }
1493 else
1494 {
1495 eReturn = eSuspended;
1496 }
1497 }
1498 #else
1499 {
1500 eReturn = eSuspended;
1501 }
1502 #endif
1503 }
1504 else
1505 {
1506 eReturn = eBlocked;
1507 }
1508 }
1509 #endif
1510
1511 #if ( INCLUDE_vTaskDelete == 1 )
1512 else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) )
1513 {
1514 /* The task being queried is referenced from the deleted
1515 tasks list, or it is not referenced from any lists at
1516 all. */
1517 eReturn = eDeleted;
1518 }
1519 #endif
1520
1521 else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */
1522 {
1523 /* If the task is not in any other state, it must be in the
1524 Ready (including pending ready) state. */
1525 eReturn = eReady;
1526 }
1527 }
1528
1529 return eReturn;
1530 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1531
1532#endif /* INCLUDE_eTaskGetState */
1533/*-----------------------------------------------------------*/
1534
1535#if ( INCLUDE_uxTaskPriorityGet == 1 )
1536
1537 UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
1538 {
1539 TCB_t const *pxTCB;
1540 UBaseType_t uxReturn;
1541
1542 taskENTER_CRITICAL();
1543 {
1544 /* If null is passed in here then it is the priority of the task
1545 that called uxTaskPriorityGet() that is being queried. */
1546 pxTCB = prvGetTCBFromHandle( xTask );
1547 uxReturn = pxTCB->uxPriority;
1548 }
1549 taskEXIT_CRITICAL();
1550
1551 return uxReturn;
1552 }
1553
1554#endif /* INCLUDE_uxTaskPriorityGet */
1555/*-----------------------------------------------------------*/
1556
1557#if ( INCLUDE_uxTaskPriorityGet == 1 )
1558
1559 UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask )
1560 {
1561 TCB_t const *pxTCB;
1562 UBaseType_t uxReturn, uxSavedInterruptState;
1563
1564 /* RTOS ports that support interrupt nesting have the concept of a
1565 maximum system call (or maximum API call) interrupt priority.
1566 Interrupts that are above the maximum system call priority are keep
1567 permanently enabled, even when the RTOS kernel is in a critical section,
1568 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1569 is defined in FreeRTOSConfig.h then
1570 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1571 failure if a FreeRTOS API function is called from an interrupt that has
1572 been assigned a priority above the configured maximum system call
1573 priority. Only FreeRTOS functions that end in FromISR can be called
1574 from interrupts that have been assigned a priority at or (logically)
1575 below the maximum system call interrupt priority. FreeRTOS maintains a
1576 separate interrupt safe API to ensure interrupt entry is as fast and as
1577 simple as possible. More information (albeit Cortex-M specific) is
1578 provided on the following link:
1579 https://www.freertos.org/RTOS-Cortex-M3-M4.html */
1580 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1581
1582 uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR();
1583 {
1584 /* If null is passed in here then it is the priority of the calling
1585 task that is being queried. */
1586 pxTCB = prvGetTCBFromHandle( xTask );
1587 uxReturn = pxTCB->uxPriority;
1588 }
1589 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState );
1590
1591 return uxReturn;
1592 }
1593
1594#endif /* INCLUDE_uxTaskPriorityGet */
1595/*-----------------------------------------------------------*/
1596
1597#if ( INCLUDE_vTaskPrioritySet == 1 )
1598
1599 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
1600 {
1601 TCB_t *pxTCB;
1602 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
1603 BaseType_t xYieldRequired = pdFALSE;
1604
1605 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
1606
1607 /* Ensure the new priority is valid. */
1608 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
1609 {
1610 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
1611 }
1612 else
1613 {
1614 mtCOVERAGE_TEST_MARKER();
1615 }
1616
1617 taskENTER_CRITICAL();
1618 {
1619 /* If null is passed in here then it is the priority of the calling
1620 task that is being changed. */
1621 pxTCB = prvGetTCBFromHandle( xTask );
1622
1623 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
1624
1625 #if ( configUSE_MUTEXES == 1 )
1626 {
1627 uxCurrentBasePriority = pxTCB->uxBasePriority;
1628 }
1629 #else
1630 {
1631 uxCurrentBasePriority = pxTCB->uxPriority;
1632 }
1633 #endif
1634
1635 if( uxCurrentBasePriority != uxNewPriority )
1636 {
1637 /* The priority change may have readied a task of higher
1638 priority than the calling task. */
1639 if( uxNewPriority > uxCurrentBasePriority )
1640 {
1641 if( pxTCB != pxCurrentTCB )
1642 {
1643 /* The priority of a task other than the currently
1644 running task is being raised. Is the priority being
1645 raised above that of the running task? */
1646 if( uxNewPriority >= pxCurrentTCB->uxPriority )
1647 {
1648 xYieldRequired = pdTRUE;
1649 }
1650 else
1651 {
1652 mtCOVERAGE_TEST_MARKER();
1653 }
1654 }
1655 else
1656 {
1657 /* The priority of the running task is being raised,
1658 but the running task must already be the highest
1659 priority task able to run so no yield is required. */
1660 }
1661 }
1662 else if( pxTCB == pxCurrentTCB )
1663 {
1664 /* Setting the priority of the running task down means
1665 there may now be another task of higher priority that
1666 is ready to execute. */
1667 xYieldRequired = pdTRUE;
1668 }
1669 else
1670 {
1671 /* Setting the priority of any other task down does not
1672 require a yield as the running task must be above the
1673 new priority of the task being modified. */
1674 }
1675
1676 /* Remember the ready list the task might be referenced from
1677 before its uxPriority member is changed so the
1678 taskRESET_READY_PRIORITY() macro can function correctly. */
1679 uxPriorityUsedOnEntry = pxTCB->uxPriority;
1680
1681 #if ( configUSE_MUTEXES == 1 )
1682 {
1683 /* Only change the priority being used if the task is not
1684 currently using an inherited priority. */
1685 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
1686 {
1687 pxTCB->uxPriority = uxNewPriority;
1688 }
1689 else
1690 {
1691 mtCOVERAGE_TEST_MARKER();
1692 }
1693
1694 /* The base priority gets set whatever. */
1695 pxTCB->uxBasePriority = uxNewPriority;
1696 }
1697 #else
1698 {
1699 pxTCB->uxPriority = uxNewPriority;
1700 }
1701 #endif
1702
1703 /* Only reset the event list item value if the value is not
1704 being used for anything else. */
1705 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
1706 {
1707 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
1708 }
1709 else
1710 {
1711 mtCOVERAGE_TEST_MARKER();
1712 }
1713
1714 /* If the task is in the blocked or suspended list we need do
1715 nothing more than change its priority variable. However, if
1716 the task is in a ready list it needs to be removed and placed
1717 in the list appropriate to its new priority. */
1718 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
1719 {
1720 /* The task is currently in its ready list - remove before
1721 adding it to it's new ready list. As we are in a critical
1722 section we can do this even if the scheduler is suspended. */
1723 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1724 {
1725 /* It is known that the task is in its ready list so
1726 there is no need to check again and the port level
1727 reset macro can be called directly. */
1728 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
1729 }
1730 else
1731 {
1732 mtCOVERAGE_TEST_MARKER();
1733 }
1734 prvAddTaskToReadyList( pxTCB );
1735 }
1736 else
1737 {
1738 mtCOVERAGE_TEST_MARKER();
1739 }
1740
1741 if( xYieldRequired != pdFALSE )
1742 {
1743 taskYIELD_IF_USING_PREEMPTION();
1744 }
1745 else
1746 {
1747 mtCOVERAGE_TEST_MARKER();
1748 }
1749
1750 /* Remove compiler warning about unused variables when the port
1751 optimised task selection is not being used. */
1752 ( void ) uxPriorityUsedOnEntry;
1753 }
1754 }
1755 taskEXIT_CRITICAL();
1756 }
1757
1758#endif /* INCLUDE_vTaskPrioritySet */
1759/*-----------------------------------------------------------*/
1760
1761#if ( INCLUDE_vTaskSuspend == 1 )
1762
1763 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
1764 {
1765 TCB_t *pxTCB;
1766
1767 taskENTER_CRITICAL();
1768 {
1769 /* If null is passed in here then it is the running task that is
1770 being suspended. */
1771 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
1772
1773 traceTASK_SUSPEND( pxTCB );
1774
1775 /* Remove task from the ready/delayed list and place in the
1776 suspended list. */
1777 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1778 {
1779 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1780 }
1781 else
1782 {
1783 mtCOVERAGE_TEST_MARKER();
1784 }
1785
1786 /* Is the task waiting on an event also? */
1787 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1788 {
1789 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1790 }
1791 else
1792 {
1793 mtCOVERAGE_TEST_MARKER();
1794 }
1795
1796 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
1797
1798 #if( configUSE_TASK_NOTIFICATIONS == 1 )
1799 {
1800 if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
1801 {
1802 /* The task was blocked to wait for a notification, but is
1803 now suspended, so no notification was received. */
1804 pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
1805 }
1806 }
1807 #endif
1808 }
1809 taskEXIT_CRITICAL();
1810
1811 if( xSchedulerRunning != pdFALSE )
1812 {
1813 /* Reset the next expected unblock time in case it referred to the
1814 task that is now in the Suspended state. */
1815 taskENTER_CRITICAL();
1816 {
1817 prvResetNextTaskUnblockTime();
1818 }
1819 taskEXIT_CRITICAL();
1820 }
1821 else
1822 {
1823 mtCOVERAGE_TEST_MARKER();
1824 }
1825
1826 if( pxTCB == pxCurrentTCB )
1827 {
1828 if( xSchedulerRunning != pdFALSE )
1829 {
1830 /* The current task has just been suspended. */
1831 configASSERT( uxSchedulerSuspended == 0 );
1832 portYIELD_WITHIN_API();
1833 }
1834 else
1835 {
1836 /* The scheduler is not running, but the task that was pointed
1837 to by pxCurrentTCB has just been suspended and pxCurrentTCB
1838 must be adjusted to point to a different task. */
1839 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */
1840 {
1841 /* No other tasks are ready, so set pxCurrentTCB back to
1842 NULL so when the next task is created pxCurrentTCB will
1843 be set to point to it no matter what its relative priority
1844 is. */
1845 pxCurrentTCB = NULL;
1846 }
1847 else
1848 {
1849 vTaskSwitchContext();
1850 }
1851 }
1852 }
1853 else
1854 {
1855 mtCOVERAGE_TEST_MARKER();
1856 }
1857 }
1858
1859#endif /* INCLUDE_vTaskSuspend */
1860/*-----------------------------------------------------------*/
1861
1862#if ( INCLUDE_vTaskSuspend == 1 )
1863
1864 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
1865 {
1866 BaseType_t xReturn = pdFALSE;
1867 const TCB_t * const pxTCB = xTask;
1868
1869 /* Accesses xPendingReadyList so must be called from a critical
1870 section. */
1871
1872 /* It does not make sense to check if the calling task is suspended. */
1873 configASSERT( xTask );
1874
1875 /* Is the task being resumed actually in the suspended list? */
1876 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE )
1877 {
1878 /* Has the task already been resumed from within an ISR? */
1879 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
1880 {
1881 /* Is it in the suspended list because it is in the Suspended
1882 state, or because is is blocked with no timeout? */
1883 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */
1884 {
1885 xReturn = pdTRUE;
1886 }
1887 else
1888 {
1889 mtCOVERAGE_TEST_MARKER();
1890 }
1891 }
1892 else
1893 {
1894 mtCOVERAGE_TEST_MARKER();
1895 }
1896 }
1897 else
1898 {
1899 mtCOVERAGE_TEST_MARKER();
1900 }
1901
1902 return xReturn;
1903 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1904
1905#endif /* INCLUDE_vTaskSuspend */
1906/*-----------------------------------------------------------*/
1907
1908#if ( INCLUDE_vTaskSuspend == 1 )
1909
1910 void vTaskResume( TaskHandle_t xTaskToResume )
1911 {
1912 TCB_t * const pxTCB = xTaskToResume;
1913
1914 /* It does not make sense to resume the calling task. */
1915 configASSERT( xTaskToResume );
1916
1917 /* The parameter cannot be NULL as it is impossible to resume the
1918 currently executing task. */
1919 if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
1920 {
1921 taskENTER_CRITICAL();
1922 {
1923 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
1924 {
1925 traceTASK_RESUME( pxTCB );
1926
1927 /* The ready list can be accessed even if the scheduler is
1928 suspended because this is inside a critical section. */
1929 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
1930 prvAddTaskToReadyList( pxTCB );
1931
1932 /* A higher priority task may have just been resumed. */
1933 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1934 {
1935 /* This yield may not cause the task just resumed to run,
1936 but will leave the lists in the correct state for the
1937 next yield. */
1938 taskYIELD_IF_USING_PREEMPTION();
1939 }
1940 else
1941 {
1942 mtCOVERAGE_TEST_MARKER();
1943 }
1944 }
1945 else
1946 {
1947 mtCOVERAGE_TEST_MARKER();
1948 }
1949 }
1950 taskEXIT_CRITICAL();
1951 }
1952 else
1953 {
1954 mtCOVERAGE_TEST_MARKER();
1955 }
1956 }
1957
1958#endif /* INCLUDE_vTaskSuspend */
1959
1960/*-----------------------------------------------------------*/
1961
1962#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1963
1964 BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
1965 {
1966 BaseType_t xYieldRequired = pdFALSE;
1967 TCB_t * const pxTCB = xTaskToResume;
1968 UBaseType_t uxSavedInterruptStatus;
1969
1970 configASSERT( xTaskToResume );
1971
1972 /* RTOS ports that support interrupt nesting have the concept of a
1973 maximum system call (or maximum API call) interrupt priority.
1974 Interrupts that are above the maximum system call priority are keep
1975 permanently enabled, even when the RTOS kernel is in a critical section,
1976 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1977 is defined in FreeRTOSConfig.h then
1978 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1979 failure if a FreeRTOS API function is called from an interrupt that has
1980 been assigned a priority above the configured maximum system call
1981 priority. Only FreeRTOS functions that end in FromISR can be called
1982 from interrupts that have been assigned a priority at or (logically)
1983 below the maximum system call interrupt priority. FreeRTOS maintains a
1984 separate interrupt safe API to ensure interrupt entry is as fast and as
1985 simple as possible. More information (albeit Cortex-M specific) is
1986 provided on the following link:
1987 https://www.freertos.org/RTOS-Cortex-M3-M4.html */
1988 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1989
1990 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
1991 {
1992 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
1993 {
1994 traceTASK_RESUME_FROM_ISR( pxTCB );
1995
1996 /* Check the ready lists can be accessed. */
1997 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1998 {
1999 /* Ready lists can be accessed so move the task from the
2000 suspended list to the ready list directly. */
2001 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2002 {
2003 xYieldRequired = pdTRUE;
2004 }
2005 else
2006 {
2007 mtCOVERAGE_TEST_MARKER();
2008 }
2009
2010 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2011 prvAddTaskToReadyList( pxTCB );
2012 }
2013 else
2014 {
2015 /* The delayed or ready lists cannot be accessed so the task
2016 is held in the pending ready list until the scheduler is
2017 unsuspended. */
2018 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
2019 }
2020 }
2021 else
2022 {
2023 mtCOVERAGE_TEST_MARKER();
2024 }
2025 }
2026 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2027
2028 return xYieldRequired;
2029 }
2030
2031#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
2032/*-----------------------------------------------------------*/
2033
2034void vTaskStartScheduler( void )
2035{
2036BaseType_t xReturn;
2037
2038 /* Add the idle task at the lowest priority. */
2039 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
2040 {
2041 StaticTask_t *pxIdleTaskTCBBuffer = NULL;
2042 StackType_t *pxIdleTaskStackBuffer = NULL;
2043 uint32_t ulIdleTaskStackSize;
2044
2045 /* The Idle task is created using user provided RAM - obtain the
2046 address of the RAM then create the idle task. */
2047 vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
2048 xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
2049 configIDLE_TASK_NAME,
2050 ulIdleTaskStackSize,
2051 ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
2052 portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2053 pxIdleTaskStackBuffer,
2054 pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2055
2056 if( xIdleTaskHandle != NULL )
2057 {
2058 xReturn = pdPASS;
2059 }
2060 else
2061 {
2062 xReturn = pdFAIL;
2063 }
2064 }
2065 #else
2066 {
2067 /* The Idle task is being created using dynamically allocated RAM. */
2068 xReturn = xTaskCreate( prvIdleTask,
2069 configIDLE_TASK_NAME,
2070 configMINIMAL_STACK_SIZE,
2071 ( void * ) NULL,
2072 portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2073 &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2074 }
2075 #endif /* configSUPPORT_STATIC_ALLOCATION */
2076
2077 #if ( configUSE_TIMERS == 1 )
2078 {
2079 if( xReturn == pdPASS )
2080 {
2081 xReturn = xTimerCreateTimerTask();
2082 }
2083 else
2084 {
2085 mtCOVERAGE_TEST_MARKER();
2086 }
2087 }
2088 #endif /* configUSE_TIMERS */
2089
2090 if( xReturn == pdPASS )
2091 {
2092 /* freertos_tasks_c_additions_init() should only be called if the user
2093 definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
2094 the only macro called by the function. */
2095 #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
2096 {
2097 freertos_tasks_c_additions_init();
2098 }
2099 #endif
2100
2101 /* Interrupts are turned off here, to ensure a tick does not occur
2102 before or during the call to xPortStartScheduler(). The stacks of
2103 the created tasks contain a status word with interrupts switched on
2104 so interrupts will automatically get re-enabled when the first task
2105 starts to run. */
2106 portDISABLE_INTERRUPTS();
2107
2108 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2109 {
2110 /* Switch Newlib's _impure_ptr variable to point to the _reent
2111 structure specific to the task that will run first. */
2112 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2113 }
2114 #endif /* configUSE_NEWLIB_REENTRANT */
2115
2116 xNextTaskUnblockTime = portMAX_DELAY;
2117 xSchedulerRunning = pdTRUE;
2118 xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
2119
2120 /* If configGENERATE_RUN_TIME_STATS is defined then the following
2121 macro must be defined to configure the timer/counter used to generate
2122 the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS
2123 is set to 0 and the following line fails to build then ensure you do not
2124 have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
2125 FreeRTOSConfig.h file. */
2126 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
2127
2128 traceTASK_SWITCHED_IN();
2129
2130 /* Setting up the timer tick is hardware specific and thus in the
2131 portable interface. */
2132 if( xPortStartScheduler() != pdFALSE )
2133 {
2134 /* Should not reach here as if the scheduler is running the
2135 function will not return. */
2136 }
2137 else
2138 {
2139 /* Should only reach here if a task calls xTaskEndScheduler(). */
2140 }
2141 }
2142 else
2143 {
2144 /* This line will only be reached if the kernel could not be started,
2145 because there was not enough FreeRTOS heap to create the idle task
2146 or the timer task. */
2147 configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
2148 }
2149
2150 /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
2151 meaning xIdleTaskHandle is not used anywhere else. */
2152 ( void ) xIdleTaskHandle;
2153}
2154/*-----------------------------------------------------------*/
2155
2156void vTaskEndScheduler( void )
2157{
2158 /* Stop the scheduler interrupts and call the portable scheduler end
2159 routine so the original ISRs can be restored if necessary. The port
2160 layer must ensure interrupts enable bit is left in the correct state. */
2161 portDISABLE_INTERRUPTS();
2162 xSchedulerRunning = pdFALSE;
2163 vPortEndScheduler();
2164}
2165/*----------------------------------------------------------*/
2166
2167void vTaskSuspendAll( void )
2168{
2169 /* A critical section is not required as the variable is of type
2170 BaseType_t. Please read Richard Barry's reply in the following link to a
2171 post in the FreeRTOS support forum before reporting this as a bug! -
2172 http://goo.gl/wu4acr */
2173 ++uxSchedulerSuspended;
2174 portMEMORY_BARRIER();
2175}
2176/*----------------------------------------------------------*/
2177
2178#if ( configUSE_TICKLESS_IDLE != 0 )
2179
2180 static TickType_t prvGetExpectedIdleTime( void )
2181 {
2182 TickType_t xReturn;
2183 UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;
2184
2185 /* uxHigherPriorityReadyTasks takes care of the case where
2186 configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
2187 task that are in the Ready state, even though the idle task is
2188 running. */
2189 #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
2190 {
2191 if( uxTopReadyPriority > tskIDLE_PRIORITY )
2192 {
2193 uxHigherPriorityReadyTasks = pdTRUE;
2194 }
2195 }
2196 #else
2197 {
2198 const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;
2199
2200 /* When port optimised task selection is used the uxTopReadyPriority
2201 variable is used as a bit map. If bits other than the least
2202 significant bit are set then there are tasks that have a priority
2203 above the idle priority that are in the Ready state. This takes
2204 care of the case where the co-operative scheduler is in use. */
2205 if( uxTopReadyPriority > uxLeastSignificantBit )
2206 {
2207 uxHigherPriorityReadyTasks = pdTRUE;
2208 }
2209 }
2210 #endif
2211
2212 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
2213 {
2214 xReturn = 0;
2215 }
2216 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
2217 {
2218 /* There are other idle priority tasks in the ready state. If
2219 time slicing is used then the very next tick interrupt must be
2220 processed. */
2221 xReturn = 0;
2222 }
2223 else if( uxHigherPriorityReadyTasks != pdFALSE )
2224 {
2225 /* There are tasks in the Ready state that have a priority above the
2226 idle priority. This path can only be reached if
2227 configUSE_PREEMPTION is 0. */
2228 xReturn = 0;
2229 }
2230 else
2231 {
2232 xReturn = xNextTaskUnblockTime - xTickCount;
2233 }
2234
2235 return xReturn;
2236 }
2237
2238#endif /* configUSE_TICKLESS_IDLE */
2239/*----------------------------------------------------------*/
2240
2241BaseType_t xTaskResumeAll( void )
2242{
2243TCB_t *pxTCB = NULL;
2244BaseType_t xAlreadyYielded = pdFALSE;
2245
2246 /* If uxSchedulerSuspended is zero then this function does not match a
2247 previous call to vTaskSuspendAll(). */
2248 configASSERT( uxSchedulerSuspended );
2249
2250 /* It is possible that an ISR caused a task to be removed from an event
2251 list while the scheduler was suspended. If this was the case then the
2252 removed task will have been added to the xPendingReadyList. Once the
2253 scheduler has been resumed it is safe to move all the pending ready
2254 tasks from this list into their appropriate ready list. */
2255 taskENTER_CRITICAL();
2256 {
2257 --uxSchedulerSuspended;
2258
2259 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2260 {
2261 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
2262 {
2263 /* Move any readied tasks from the pending list into the
2264 appropriate ready list. */
2265 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
2266 {
2267 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
2268 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2269 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2270 prvAddTaskToReadyList( pxTCB );
2271
2272 /* If the moved task has a priority higher than the current
2273 task then a yield must be performed. */
2274 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2275 {
2276 xYieldPending = pdTRUE;
2277 }
2278 else
2279 {
2280 mtCOVERAGE_TEST_MARKER();
2281 }
2282 }
2283
2284 if( pxTCB != NULL )
2285 {
2286 /* A task was unblocked while the scheduler was suspended,
2287 which may have prevented the next unblock time from being
2288 re-calculated, in which case re-calculate it now. Mainly
2289 important for low power tickless implementations, where
2290 this can prevent an unnecessary exit from low power
2291 state. */
2292 prvResetNextTaskUnblockTime();
2293 }
2294
2295 /* If any ticks occurred while the scheduler was suspended then
2296 they should be processed now. This ensures the tick count does
2297 not slip, and that any delayed tasks are resumed at the correct
2298 time. */
2299 {
2300 UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */
2301
2302 if( uxPendedCounts > ( UBaseType_t ) 0U )
2303 {
2304 do
2305 {
2306 if( xTaskIncrementTick() != pdFALSE )
2307 {
2308 xYieldPending = pdTRUE;
2309 }
2310 else
2311 {
2312 mtCOVERAGE_TEST_MARKER();
2313 }
2314 --uxPendedCounts;
2315 } while( uxPendedCounts > ( UBaseType_t ) 0U );
2316
2317 uxPendedTicks = 0;
2318 }
2319 else
2320 {
2321 mtCOVERAGE_TEST_MARKER();
2322 }
2323 }
2324
2325 if( xYieldPending != pdFALSE )
2326 {
2327 #if( configUSE_PREEMPTION != 0 )
2328 {
2329 xAlreadyYielded = pdTRUE;
2330 }
2331 #endif
2332 taskYIELD_IF_USING_PREEMPTION();
2333 }
2334 else
2335 {
2336 mtCOVERAGE_TEST_MARKER();
2337 }
2338 }
2339 }
2340 else
2341 {
2342 mtCOVERAGE_TEST_MARKER();
2343 }
2344 }
2345 taskEXIT_CRITICAL();
2346
2347 return xAlreadyYielded;
2348}
2349/*-----------------------------------------------------------*/
2350
2351TickType_t xTaskGetTickCount( void )
2352{
2353TickType_t xTicks;
2354
2355 /* Critical section required if running on a 16 bit processor. */
2356 portTICK_TYPE_ENTER_CRITICAL();
2357 {
2358 xTicks = xTickCount;
2359 }
2360 portTICK_TYPE_EXIT_CRITICAL();
2361
2362 return xTicks;
2363}
2364/*-----------------------------------------------------------*/
2365
2366TickType_t xTaskGetTickCountFromISR( void )
2367{
2368TickType_t xReturn;
2369UBaseType_t uxSavedInterruptStatus;
2370
2371 /* RTOS ports that support interrupt nesting have the concept of a maximum
2372 system call (or maximum API call) interrupt priority. Interrupts that are
2373 above the maximum system call priority are kept permanently enabled, even
2374 when the RTOS kernel is in a critical section, but cannot make any calls to
2375 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
2376 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
2377 failure if a FreeRTOS API function is called from an interrupt that has been
2378 assigned a priority above the configured maximum system call priority.
2379 Only FreeRTOS functions that end in FromISR can be called from interrupts
2380 that have been assigned a priority at or (logically) below the maximum
2381 system call interrupt priority. FreeRTOS maintains a separate interrupt
2382 safe API to ensure interrupt entry is as fast and as simple as possible.
2383 More information (albeit Cortex-M specific) is provided on the following
2384 link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */
2385 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
2386
2387 uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
2388 {
2389 xReturn = xTickCount;
2390 }
2391 portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2392
2393 return xReturn;
2394}
2395/*-----------------------------------------------------------*/
2396
2397UBaseType_t uxTaskGetNumberOfTasks( void )
2398{
2399 /* A critical section is not required because the variables are of type
2400 BaseType_t. */
2401 return uxCurrentNumberOfTasks;
2402}
2403/*-----------------------------------------------------------*/
2404
2405char *pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2406{
2407TCB_t *pxTCB;
2408
2409 /* If null is passed in here then the name of the calling task is being
2410 queried. */
2411 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08002412#ifdef configMEMORY_LEAK
2413 if (pxTCB == NULL)
2414 return NULL;
2415#else
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08002416 configASSERT( pxTCB );
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08002417#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08002418 return &( pxTCB->pcTaskName[ 0 ] );
2419}
2420/*-----------------------------------------------------------*/
2421
2422#if ( INCLUDE_xTaskGetHandle == 1 )
2423
2424 static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] )
2425 {
2426 TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
2427 UBaseType_t x;
2428 char cNextChar;
2429 BaseType_t xBreakLoop;
2430
2431 /* This function is called with the scheduler suspended. */
2432
2433 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
2434 {
2435 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
2436
2437 do
2438 {
2439 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
2440
2441 /* Check each character in the name looking for a match or
2442 mismatch. */
2443 xBreakLoop = pdFALSE;
2444 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
2445 {
2446 cNextChar = pxNextTCB->pcTaskName[ x ];
2447
2448 if( cNextChar != pcNameToQuery[ x ] )
2449 {
2450 /* Characters didn't match. */
2451 xBreakLoop = pdTRUE;
2452 }
2453 else if( cNextChar == ( char ) 0x00 )
2454 {
2455 /* Both strings terminated, a match must have been
2456 found. */
2457 pxReturn = pxNextTCB;
2458 xBreakLoop = pdTRUE;
2459 }
2460 else
2461 {
2462 mtCOVERAGE_TEST_MARKER();
2463 }
2464
2465 if( xBreakLoop != pdFALSE )
2466 {
2467 break;
2468 }
2469 }
2470
2471 if( pxReturn != NULL )
2472 {
2473 /* The handle has been found. */
2474 break;
2475 }
2476
2477 } while( pxNextTCB != pxFirstTCB );
2478 }
2479 else
2480 {
2481 mtCOVERAGE_TEST_MARKER();
2482 }
2483
2484 return pxReturn;
2485 }
2486
2487#endif /* INCLUDE_xTaskGetHandle */
2488/*-----------------------------------------------------------*/
2489
2490#if ( INCLUDE_xTaskGetHandle == 1 )
2491
2492 TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2493 {
2494 UBaseType_t uxQueue = configMAX_PRIORITIES;
2495 TCB_t* pxTCB;
2496
2497 /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */
2498 configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN );
2499
2500 vTaskSuspendAll();
2501 {
2502 /* Search the ready lists. */
2503 do
2504 {
2505 uxQueue--;
2506 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery );
2507
2508 if( pxTCB != NULL )
2509 {
2510 /* Found the handle. */
2511 break;
2512 }
2513
2514 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2515
2516 /* Search the delayed lists. */
2517 if( pxTCB == NULL )
2518 {
2519 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery );
2520 }
2521
2522 if( pxTCB == NULL )
2523 {
2524 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery );
2525 }
2526
2527 #if ( INCLUDE_vTaskSuspend == 1 )
2528 {
2529 if( pxTCB == NULL )
2530 {
2531 /* Search the suspended list. */
2532 pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery );
2533 }
2534 }
2535 #endif
2536
2537 #if( INCLUDE_vTaskDelete == 1 )
2538 {
2539 if( pxTCB == NULL )
2540 {
2541 /* Search the deleted list. */
2542 pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery );
2543 }
2544 }
2545 #endif
2546 }
2547 ( void ) xTaskResumeAll();
2548
2549 return pxTCB;
2550 }
2551
2552#endif /* INCLUDE_xTaskGetHandle */
2553/*-----------------------------------------------------------*/
2554
2555#if ( configUSE_TRACE_FACILITY == 1 )
2556
2557 UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
2558 {
2559 UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
2560
2561 vTaskSuspendAll();
2562 {
2563 /* Is there a space in the array for each task in the system? */
2564 if( uxArraySize >= uxCurrentNumberOfTasks )
2565 {
2566 /* Fill in an TaskStatus_t structure with information on each
2567 task in the Ready state. */
2568 do
2569 {
2570 uxQueue--;
2571 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
2572
2573 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2574
2575 /* Fill in an TaskStatus_t structure with information on each
2576 task in the Blocked state. */
2577 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
2578 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );
2579
2580 #if( INCLUDE_vTaskDelete == 1 )
2581 {
2582 /* Fill in an TaskStatus_t structure with information on
2583 each task that has been deleted but not yet cleaned up. */
2584 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
2585 }
2586 #endif
2587
2588 #if ( INCLUDE_vTaskSuspend == 1 )
2589 {
2590 /* Fill in an TaskStatus_t structure with information on
2591 each task in the Suspended state. */
2592 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
2593 }
2594 #endif
2595
2596 #if ( configGENERATE_RUN_TIME_STATS == 1)
2597 {
2598 if( pulTotalRunTime != NULL )
2599 {
2600 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2601 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
2602 #else
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08002603 *pulTotalRunTime = (uint32_t)portGET_RUN_TIME_COUNTER_VALUE();
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08002604 #endif
2605 }
2606 }
2607 #else
2608 {
2609 if( pulTotalRunTime != NULL )
2610 {
2611 *pulTotalRunTime = 0;
2612 }
2613 }
2614 #endif
2615 }
2616 else
2617 {
2618 mtCOVERAGE_TEST_MARKER();
2619 }
2620 }
2621 ( void ) xTaskResumeAll();
2622
2623 return uxTask;
2624 }
2625
2626#endif /* configUSE_TRACE_FACILITY */
2627/*----------------------------------------------------------*/
2628
2629#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
2630
2631 TaskHandle_t xTaskGetIdleTaskHandle( void )
2632 {
2633 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
2634 started, then xIdleTaskHandle will be NULL. */
2635 configASSERT( ( xIdleTaskHandle != NULL ) );
2636 return xIdleTaskHandle;
2637 }
2638
2639#endif /* INCLUDE_xTaskGetIdleTaskHandle */
2640/*----------------------------------------------------------*/
2641
2642/* This conditional compilation should use inequality to 0, not equality to 1.
2643This is to ensure vTaskStepTick() is available when user defined low power mode
2644implementations require configUSE_TICKLESS_IDLE to be set to a value other than
26451. */
2646#if ( configUSE_TICKLESS_IDLE != 0 )
2647
2648 void vTaskStepTick( const TickType_t xTicksToJump )
2649 {
2650 /* Correct the tick count value after a period during which the tick
2651 was suppressed. Note this does *not* call the tick hook function for
2652 each stepped tick. */
2653 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
2654 xTickCount += xTicksToJump;
2655 traceINCREASE_TICK_COUNT( xTicksToJump );
2656 }
2657
2658#endif /* configUSE_TICKLESS_IDLE */
2659/*----------------------------------------------------------*/
2660
2661#if ( INCLUDE_xTaskAbortDelay == 1 )
2662
2663 BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
2664 {
2665 TCB_t *pxTCB = xTask;
2666 BaseType_t xReturn;
2667
2668 configASSERT( pxTCB );
2669
2670 vTaskSuspendAll();
2671 {
2672 /* A task can only be prematurely removed from the Blocked state if
2673 it is actually in the Blocked state. */
2674 if( eTaskGetState( xTask ) == eBlocked )
2675 {
2676 xReturn = pdPASS;
2677
2678 /* Remove the reference to the task from the blocked list. An
2679 interrupt won't touch the xStateListItem because the
2680 scheduler is suspended. */
2681 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2682
2683 /* Is the task waiting on an event also? If so remove it from
2684 the event list too. Interrupts can touch the event list item,
2685 even though the scheduler is suspended, so a critical section
2686 is used. */
2687 taskENTER_CRITICAL();
2688 {
2689 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
2690 {
2691 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2692 pxTCB->ucDelayAborted = pdTRUE;
2693 }
2694 else
2695 {
2696 mtCOVERAGE_TEST_MARKER();
2697 }
2698 }
2699 taskEXIT_CRITICAL();
2700
2701 /* Place the unblocked task into the appropriate ready list. */
2702 prvAddTaskToReadyList( pxTCB );
2703
2704 /* A task being unblocked cannot cause an immediate context
2705 switch if preemption is turned off. */
2706 #if ( configUSE_PREEMPTION == 1 )
2707 {
2708 /* Preemption is on, but a context switch should only be
2709 performed if the unblocked task has a priority that is
2710 equal to or higher than the currently executing task. */
2711 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
2712 {
2713 /* Pend the yield to be performed when the scheduler
2714 is unsuspended. */
2715 xYieldPending = pdTRUE;
2716 }
2717 else
2718 {
2719 mtCOVERAGE_TEST_MARKER();
2720 }
2721 }
2722 #endif /* configUSE_PREEMPTION */
2723 }
2724 else
2725 {
2726 xReturn = pdFAIL;
2727 }
2728 }
2729 ( void ) xTaskResumeAll();
2730
2731 return xReturn;
2732 }
2733
2734#endif /* INCLUDE_xTaskAbortDelay */
2735/*----------------------------------------------------------*/
2736
2737BaseType_t xTaskIncrementTick( void )
2738{
2739TCB_t * pxTCB;
2740TickType_t xItemValue;
2741BaseType_t xSwitchRequired = pdFALSE;
2742
2743 /* Called by the portable layer each time a tick interrupt occurs.
2744 Increments the tick then checks to see if the new tick value will cause any
2745 tasks to be unblocked. */
2746 traceTASK_INCREMENT_TICK( xTickCount );
2747 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2748 {
2749 /* Minor optimisation. The tick count cannot change in this
2750 block. */
2751 const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
2752
2753 /* Increment the RTOS tick, switching the delayed and overflowed
2754 delayed lists if it wraps to 0. */
2755 xTickCount = xConstTickCount;
2756
2757 if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
2758 {
2759 taskSWITCH_DELAYED_LISTS();
2760 }
2761 else
2762 {
2763 mtCOVERAGE_TEST_MARKER();
2764 }
2765
2766 /* See if this tick has made a timeout expire. Tasks are stored in
2767 the queue in the order of their wake time - meaning once one task
2768 has been found whose block time has not expired there is no need to
2769 look any further down the list. */
2770 if( xConstTickCount >= xNextTaskUnblockTime )
2771 {
2772 for( ;; )
2773 {
2774 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
2775 {
2776 /* The delayed list is empty. Set xNextTaskUnblockTime
2777 to the maximum possible value so it is extremely
2778 unlikely that the
2779 if( xTickCount >= xNextTaskUnblockTime ) test will pass
2780 next time through. */
2781 xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2782 break;
2783 }
2784 else
2785 {
2786 /* The delayed list is not empty, get the value of the
2787 item at the head of the delayed list. This is the time
2788 at which the task at the head of the delayed list must
2789 be removed from the Blocked state. */
2790 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
2791 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
2792
2793 if( xConstTickCount < xItemValue )
2794 {
2795 /* It is not time to unblock this item yet, but the
2796 item value is the time at which the task at the head
2797 of the blocked list must be removed from the Blocked
2798 state - so record the item value in
2799 xNextTaskUnblockTime. */
2800 xNextTaskUnblockTime = xItemValue;
2801 break; /*lint !e9011 Code structure here is deedmed easier to understand with multiple breaks. */
2802 }
2803 else
2804 {
2805 mtCOVERAGE_TEST_MARKER();
2806 }
2807
2808 /* It is time to remove the item from the Blocked state. */
2809 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2810
2811 /* Is the task waiting on an event also? If so remove
2812 it from the event list. */
2813 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
2814 {
2815 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2816 }
2817 else
2818 {
2819 mtCOVERAGE_TEST_MARKER();
2820 }
2821
2822 /* Place the unblocked task into the appropriate ready
2823 list. */
2824 prvAddTaskToReadyList( pxTCB );
2825
2826 /* A task being unblocked cannot cause an immediate
2827 context switch if preemption is turned off. */
2828 #if ( configUSE_PREEMPTION == 1 )
2829 {
2830 /* Preemption is on, but a context switch should
2831 only be performed if the unblocked task has a
2832 priority that is equal to or higher than the
2833 currently executing task. */
2834 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2835 {
2836 xSwitchRequired = pdTRUE;
2837 }
2838 else
2839 {
2840 mtCOVERAGE_TEST_MARKER();
2841 }
2842 }
2843 #endif /* configUSE_PREEMPTION */
2844 }
2845 }
2846 }
2847
2848 /* Tasks of equal priority to the currently running task will share
2849 processing time (time slice) if preemption is on, and the application
2850 writer has not explicitly turned time slicing off. */
2851 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
2852 {
2853 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
2854 {
2855 xSwitchRequired = pdTRUE;
2856 }
2857 else
2858 {
2859 mtCOVERAGE_TEST_MARKER();
2860 }
2861 }
2862 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
2863
2864 #if ( configUSE_TICK_HOOK == 1 )
2865 {
2866 /* Guard against the tick hook being called when the pended tick
2867 count is being unwound (when the scheduler is being unlocked). */
2868 if( uxPendedTicks == ( UBaseType_t ) 0U )
2869 {
2870 vApplicationTickHook();
2871 }
2872 else
2873 {
2874 mtCOVERAGE_TEST_MARKER();
2875 }
2876 }
2877 #endif /* configUSE_TICK_HOOK */
2878 }
2879 else
2880 {
2881 ++uxPendedTicks;
2882
2883 /* The tick hook gets called at regular intervals, even if the
2884 scheduler is locked. */
2885 #if ( configUSE_TICK_HOOK == 1 )
2886 {
2887 vApplicationTickHook();
2888 }
2889 #endif
2890 }
2891
2892 #if ( configUSE_PREEMPTION == 1 )
2893 {
2894 if( xYieldPending != pdFALSE )
2895 {
2896 xSwitchRequired = pdTRUE;
2897 }
2898 else
2899 {
2900 mtCOVERAGE_TEST_MARKER();
2901 }
2902 }
2903 #endif /* configUSE_PREEMPTION */
2904
2905 return xSwitchRequired;
2906}
2907/*-----------------------------------------------------------*/
2908
2909#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2910
2911 void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction )
2912 {
2913 TCB_t *xTCB;
2914
2915 /* If xTask is NULL then it is the task hook of the calling task that is
2916 getting set. */
2917 if( xTask == NULL )
2918 {
2919 xTCB = ( TCB_t * ) pxCurrentTCB;
2920 }
2921 else
2922 {
2923 xTCB = xTask;
2924 }
2925
2926 /* Save the hook function in the TCB. A critical section is required as
2927 the value can be accessed from an interrupt. */
2928 taskENTER_CRITICAL();
2929 {
2930 xTCB->pxTaskTag = pxHookFunction;
2931 }
2932 taskEXIT_CRITICAL();
2933 }
2934
2935#endif /* configUSE_APPLICATION_TASK_TAG */
2936/*-----------------------------------------------------------*/
2937
2938#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2939
2940 TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask )
2941 {
2942 TCB_t *pxTCB;
2943 TaskHookFunction_t xReturn;
2944
2945 /* If xTask is NULL then set the calling task's hook. */
2946 pxTCB = prvGetTCBFromHandle( xTask );
2947
2948 /* Save the hook function in the TCB. A critical section is required as
2949 the value can be accessed from an interrupt. */
2950 taskENTER_CRITICAL();
2951 {
2952 xReturn = pxTCB->pxTaskTag;
2953 }
2954 taskEXIT_CRITICAL();
2955
2956 return xReturn;
2957 }
2958
2959#endif /* configUSE_APPLICATION_TASK_TAG */
2960/*-----------------------------------------------------------*/
2961
2962#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2963
2964 TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask )
2965 {
2966 TCB_t *pxTCB;
2967 TaskHookFunction_t xReturn;
2968 UBaseType_t uxSavedInterruptStatus;
2969
2970 /* If xTask is NULL then set the calling task's hook. */
2971 pxTCB = prvGetTCBFromHandle( xTask );
2972
2973 /* Save the hook function in the TCB. A critical section is required as
2974 the value can be accessed from an interrupt. */
2975 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
2976 {
2977 xReturn = pxTCB->pxTaskTag;
2978 }
2979 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2980
2981 return xReturn;
2982 }
2983
2984#endif /* configUSE_APPLICATION_TASK_TAG */
2985/*-----------------------------------------------------------*/
2986
2987#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2988
2989 BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
2990 {
2991 TCB_t *xTCB;
2992 BaseType_t xReturn;
2993
2994 /* If xTask is NULL then we are calling our own task hook. */
2995 if( xTask == NULL )
2996 {
2997 xTCB = pxCurrentTCB;
2998 }
2999 else
3000 {
3001 xTCB = xTask;
3002 }
3003
3004 if( xTCB->pxTaskTag != NULL )
3005 {
3006 xReturn = xTCB->pxTaskTag( pvParameter );
3007 }
3008 else
3009 {
3010 xReturn = pdFAIL;
3011 }
3012
3013 return xReturn;
3014 }
3015
3016#endif /* configUSE_APPLICATION_TASK_TAG */
3017/*-----------------------------------------------------------*/
3018
3019void vTaskSwitchContext( void )
3020{
3021 if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
3022 {
3023 /* The scheduler is currently suspended - do not allow a context
3024 switch. */
3025 xYieldPending = pdTRUE;
3026 }
3027 else
3028 {
3029 xYieldPending = pdFALSE;
3030 traceTASK_SWITCHED_OUT();
3031
3032 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3033 {
3034 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
3035 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
3036 #else
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08003037 ulTotalRunTime = (uint32_t)portGET_RUN_TIME_COUNTER_VALUE();
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08003038 #endif
3039
3040 /* Add the amount of time the task has been running to the
3041 accumulated time so far. The time the task started running was
3042 stored in ulTaskSwitchedInTime. Note that there is no overflow
3043 protection here so count values are only valid until the timer
3044 overflows. The guard against negative values is to protect
3045 against suspect run time stat counter implementations - which
3046 are provided by the application, not the kernel. */
3047 if( ulTotalRunTime > ulTaskSwitchedInTime )
3048 {
3049 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08003050#if ENABLE_FTRACE
3051 int ret = vGetFtraceIndex();
3052 struct ftrace_node *p = NULL;
3053 if (ret >= 0) {
3054 p = &ptracer->pnode[ret];
3055 p->runtime = (uint32_t)(ulTotalRunTime - ulTaskSwitchedInTime);
3056 p->starttime = ulTaskSwitchedInTime;
3057 p->pid = (uint32_t)pxCurrentTCB->uxTCBNumber;
3058 p->irqnum = 500;
3059 p->type = running;
3060 }
3061#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08003062 }
3063 else
3064 {
3065 mtCOVERAGE_TEST_MARKER();
3066 }
3067 ulTaskSwitchedInTime = ulTotalRunTime;
3068 }
3069 #endif /* configGENERATE_RUN_TIME_STATS */
3070
3071 /* Check for stack overflow, if configured. */
3072 taskCHECK_FOR_STACK_OVERFLOW();
3073
3074 /* Before the currently running task is switched out, save its errno. */
3075 #if( configUSE_POSIX_ERRNO == 1 )
3076 {
3077 pxCurrentTCB->iTaskErrno = FreeRTOS_errno;
3078 }
3079 #endif
3080
3081 /* Select a new task to run using either the generic C or port
3082 optimised asm code. */
3083 taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3084 traceTASK_SWITCHED_IN();
3085
3086 /* After the new task is switched in, update the global errno. */
3087 #if( configUSE_POSIX_ERRNO == 1 )
3088 {
3089 FreeRTOS_errno = pxCurrentTCB->iTaskErrno;
3090 }
3091 #endif
3092
3093 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3094 {
3095 /* Switch Newlib's _impure_ptr variable to point to the _reent
3096 structure specific to this task. */
3097 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
3098 }
3099 #endif /* configUSE_NEWLIB_REENTRANT */
3100 }
3101}
3102/*-----------------------------------------------------------*/
3103
3104void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
3105{
3106 configASSERT( pxEventList );
3107
3108 /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
3109 SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
3110
3111 /* Place the event list item of the TCB in the appropriate event list.
3112 This is placed in the list in priority order so the highest priority task
3113 is the first to be woken by the event. The queue that contains the event
3114 list is locked, preventing simultaneous access from interrupts. */
3115 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
3116
3117 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
3118}
3119/*-----------------------------------------------------------*/
3120
3121void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait )
3122{
3123 configASSERT( pxEventList );
3124
3125 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
3126 the event groups implementation. */
3127 configASSERT( uxSchedulerSuspended != 0 );
3128
3129 /* Store the item value in the event list item. It is safe to access the
3130 event list item here as interrupts won't access the event list item of a
3131 task that is not in the Blocked state. */
3132 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
3133
3134 /* Place the event list item of the TCB at the end of the appropriate event
3135 list. It is safe to access the event list here because it is part of an
3136 event group implementation - and interrupts don't access event groups
3137 directly (instead they access them indirectly by pending function calls to
3138 the task level). */
3139 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
3140
3141 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
3142}
3143/*-----------------------------------------------------------*/
3144
3145#if( configUSE_TIMERS == 1 )
3146
3147 void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
3148 {
3149 configASSERT( pxEventList );
3150
3151 /* This function should not be called by application code hence the
3152 'Restricted' in its name. It is not part of the public API. It is
3153 designed for use by kernel code, and has special calling requirements -
3154 it should be called with the scheduler suspended. */
3155
3156
3157 /* Place the event list item of the TCB in the appropriate event list.
3158 In this case it is assume that this is the only task that is going to
3159 be waiting on this event list, so the faster vListInsertEnd() function
3160 can be used in place of vListInsert. */
3161 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
3162
3163 /* If the task should block indefinitely then set the block time to a
3164 value that will be recognised as an indefinite delay inside the
3165 prvAddCurrentTaskToDelayedList() function. */
3166 if( xWaitIndefinitely != pdFALSE )
3167 {
3168 xTicksToWait = portMAX_DELAY;
3169 }
3170
3171 traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) );
3172 prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely );
3173 }
3174
3175#endif /* configUSE_TIMERS */
3176/*-----------------------------------------------------------*/
3177
3178BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
3179{
3180TCB_t *pxUnblockedTCB;
3181BaseType_t xReturn;
3182
3183 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
3184 called from a critical section within an ISR. */
3185
3186 /* The event list is sorted in priority order, so the first in the list can
3187 be removed as it is known to be the highest priority. Remove the TCB from
3188 the delayed list, and add it to the ready list.
3189
3190 If an event is for a queue that is locked then this function will never
3191 get called - the lock count on the queue will get modified instead. This
3192 means exclusive access to the event list is guaranteed here.
3193
3194 This function assumes that a check has already been made to ensure that
3195 pxEventList is not empty. */
3196 pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3197 configASSERT( pxUnblockedTCB );
3198 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
3199
3200 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
3201 {
3202 ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) );
3203 prvAddTaskToReadyList( pxUnblockedTCB );
3204
3205 #if( configUSE_TICKLESS_IDLE != 0 )
3206 {
3207 /* If a task is blocked on a kernel object then xNextTaskUnblockTime
3208 might be set to the blocked task's time out time. If the task is
3209 unblocked for a reason other than a timeout xNextTaskUnblockTime is
3210 normally left unchanged, because it is automatically reset to a new
3211 value when the tick count equals xNextTaskUnblockTime. However if
3212 tickless idling is used it might be more important to enter sleep mode
3213 at the earliest possible time - so reset xNextTaskUnblockTime here to
3214 ensure it is updated at the earliest possible time. */
3215 prvResetNextTaskUnblockTime();
3216 }
3217 #endif
3218 }
3219 else
3220 {
3221 /* The delayed and ready lists cannot be accessed, so hold this task
3222 pending until the scheduler is resumed. */
3223 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
3224 }
3225
3226 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
3227 {
3228 /* Return true if the task removed from the event list has a higher
3229 priority than the calling task. This allows the calling task to know if
3230 it should force a context switch now. */
3231 xReturn = pdTRUE;
3232
3233 /* Mark that a yield is pending in case the user is not using the
3234 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
3235 xYieldPending = pdTRUE;
3236 }
3237 else
3238 {
3239 xReturn = pdFALSE;
3240 }
3241
3242 return xReturn;
3243}
3244/*-----------------------------------------------------------*/
3245
3246void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
3247{
3248TCB_t *pxUnblockedTCB;
3249
3250 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
3251 the event flags implementation. */
3252 configASSERT( uxSchedulerSuspended != pdFALSE );
3253
3254 /* Store the new item value in the event list. */
3255 listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
3256
3257 /* Remove the event list form the event flag. Interrupts do not access
3258 event flags. */
3259 pxUnblockedTCB = listGET_LIST_ITEM_OWNER( pxEventListItem ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3260 configASSERT( pxUnblockedTCB );
3261 ( void ) uxListRemove( pxEventListItem );
3262
3263 /* Remove the task from the delayed list and add it to the ready list. The
3264 scheduler is suspended so interrupts will not be accessing the ready
3265 lists. */
3266 ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) );
3267 prvAddTaskToReadyList( pxUnblockedTCB );
3268
3269 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
3270 {
3271 /* The unblocked task has a priority above that of the calling task, so
3272 a context switch is required. This function is called with the
3273 scheduler suspended so xYieldPending is set so the context switch
3274 occurs immediately that the scheduler is resumed (unsuspended). */
3275 xYieldPending = pdTRUE;
3276 }
3277}
3278/*-----------------------------------------------------------*/
3279
3280void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
3281{
3282 configASSERT( pxTimeOut );
3283 taskENTER_CRITICAL();
3284 {
3285 pxTimeOut->xOverflowCount = xNumOfOverflows;
3286 pxTimeOut->xTimeOnEntering = xTickCount;
3287 }
3288 taskEXIT_CRITICAL();
3289}
3290/*-----------------------------------------------------------*/
3291
3292void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
3293{
3294 /* For internal use only as it does not use a critical section. */
3295 pxTimeOut->xOverflowCount = xNumOfOverflows;
3296 pxTimeOut->xTimeOnEntering = xTickCount;
3297}
3298/*-----------------------------------------------------------*/
3299
3300BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait )
3301{
3302BaseType_t xReturn;
3303
3304 configASSERT( pxTimeOut );
3305 configASSERT( pxTicksToWait );
3306
3307 taskENTER_CRITICAL();
3308 {
3309 /* Minor optimisation. The tick count cannot change in this block. */
3310 const TickType_t xConstTickCount = xTickCount;
3311 const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
3312
3313 #if( INCLUDE_xTaskAbortDelay == 1 )
3314 if( pxCurrentTCB->ucDelayAborted != ( uint8_t ) pdFALSE )
3315 {
3316 /* The delay was aborted, which is not the same as a time out,
3317 but has the same result. */
3318 pxCurrentTCB->ucDelayAborted = pdFALSE;
3319 xReturn = pdTRUE;
3320 }
3321 else
3322 #endif
3323
3324 #if ( INCLUDE_vTaskSuspend == 1 )
3325 if( *pxTicksToWait == portMAX_DELAY )
3326 {
3327 /* If INCLUDE_vTaskSuspend is set to 1 and the block time
3328 specified is the maximum block time then the task should block
3329 indefinitely, and therefore never time out. */
3330 xReturn = pdFALSE;
3331 }
3332 else
3333 #endif
3334
3335 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
3336 {
3337 /* The tick count is greater than the time at which
3338 vTaskSetTimeout() was called, but has also overflowed since
3339 vTaskSetTimeOut() was called. It must have wrapped all the way
3340 around and gone past again. This passed since vTaskSetTimeout()
3341 was called. */
3342 xReturn = pdTRUE;
3343 }
3344 else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
3345 {
3346 /* Not a genuine timeout. Adjust parameters for time remaining. */
3347 *pxTicksToWait -= xElapsedTime;
3348 vTaskInternalSetTimeOutState( pxTimeOut );
3349 xReturn = pdFALSE;
3350 }
3351 else
3352 {
3353 *pxTicksToWait = 0;
3354 xReturn = pdTRUE;
3355 }
3356 }
3357 taskEXIT_CRITICAL();
3358
3359 return xReturn;
3360}
3361/*-----------------------------------------------------------*/
3362
3363void vTaskMissedYield( void )
3364{
3365 xYieldPending = pdTRUE;
3366}
3367/*-----------------------------------------------------------*/
3368
3369#if ( configUSE_TRACE_FACILITY == 1 )
3370
3371 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask )
3372 {
3373 UBaseType_t uxReturn;
3374 TCB_t const *pxTCB;
3375
3376 if( xTask != NULL )
3377 {
3378 pxTCB = xTask;
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08003379 uxReturn = pxTCB->uxTCBNumber;
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08003380 }
3381 else
3382 {
3383 uxReturn = 0U;
3384 }
3385
3386 return uxReturn;
3387 }
3388
3389#endif /* configUSE_TRACE_FACILITY */
3390/*-----------------------------------------------------------*/
3391
3392#if ( configUSE_TRACE_FACILITY == 1 )
3393
3394 void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle )
3395 {
3396 TCB_t * pxTCB;
3397
3398 if( xTask != NULL )
3399 {
3400 pxTCB = xTask;
3401 pxTCB->uxTaskNumber = uxHandle;
3402 }
3403 }
3404
3405#endif /* configUSE_TRACE_FACILITY */
3406
3407/*
3408 * -----------------------------------------------------------
3409 * The Idle task.
3410 * ----------------------------------------------------------
3411 *
3412 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
3413 * language extensions. The equivalent prototype for this function is:
3414 *
3415 * void prvIdleTask( void *pvParameters );
3416 *
3417 */
3418static portTASK_FUNCTION( prvIdleTask, pvParameters )
3419{
3420 /* Stop warnings. */
3421 ( void ) pvParameters;
3422
3423 /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
3424 SCHEDULER IS STARTED. **/
3425
3426 /* In case a task that has a secure context deletes itself, in which case
3427 the idle task is responsible for deleting the task's secure context, if
3428 any. */
3429 portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
3430
3431 for( ;; )
3432 {
3433 /* See if any tasks have deleted themselves - if so then the idle task
3434 is responsible for freeing the deleted task's TCB and stack. */
3435 prvCheckTasksWaitingTermination();
3436
3437 #if ( configUSE_PREEMPTION == 0 )
3438 {
3439 /* If we are not using preemption we keep forcing a task switch to
3440 see if any other task has become available. If we are using
3441 preemption we don't need to do this as any task becoming available
3442 will automatically get the processor anyway. */
3443 taskYIELD();
3444 }
3445 #endif /* configUSE_PREEMPTION */
3446
3447 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
3448 {
3449 /* When using preemption tasks of equal priority will be
3450 timesliced. If a task that is sharing the idle priority is ready
3451 to run then the idle task should yield before the end of the
3452 timeslice.
3453
3454 A critical region is not required here as we are just reading from
3455 the list, and an occasional incorrect value will not matter. If
3456 the ready list at the idle priority contains more than one task
3457 then a task other than the idle task is ready to execute. */
3458 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
3459 {
3460 taskYIELD();
3461 }
3462 else
3463 {
3464 mtCOVERAGE_TEST_MARKER();
3465 }
3466 }
3467 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
3468
3469 #if ( configUSE_IDLE_HOOK == 1 )
3470 {
3471 extern void vApplicationIdleHook( void );
3472
3473 /* Call the user defined function from within the idle task. This
3474 allows the application designer to add background functionality
3475 without the overhead of a separate task.
3476 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
3477 CALL A FUNCTION THAT MIGHT BLOCK. */
3478 vApplicationIdleHook();
3479 }
3480 #endif /* configUSE_IDLE_HOOK */
3481
3482 /* This conditional compilation should use inequality to 0, not equality
3483 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
3484 user defined low power mode implementations require
3485 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
3486 #if ( configUSE_TICKLESS_IDLE != 0 )
3487 {
3488 TickType_t xExpectedIdleTime;
3489
3490 /* It is not desirable to suspend then resume the scheduler on
3491 each iteration of the idle task. Therefore, a preliminary
3492 test of the expected idle time is performed without the
3493 scheduler suspended. The result here is not necessarily
3494 valid. */
3495 xExpectedIdleTime = prvGetExpectedIdleTime();
3496
3497 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3498 {
3499 vTaskSuspendAll();
3500 {
3501 /* Now the scheduler is suspended, the expected idle
3502 time can be sampled again, and this time its value can
3503 be used. */
3504 configASSERT( xNextTaskUnblockTime >= xTickCount );
3505 xExpectedIdleTime = prvGetExpectedIdleTime();
3506
3507 /* Define the following macro to set xExpectedIdleTime to 0
3508 if the application does not want
3509 portSUPPRESS_TICKS_AND_SLEEP() to be called. */
3510 configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
3511
3512 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3513 {
3514 traceLOW_POWER_IDLE_BEGIN();
3515 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
3516 traceLOW_POWER_IDLE_END();
3517 }
3518 else
3519 {
3520 mtCOVERAGE_TEST_MARKER();
3521 }
3522 }
3523 ( void ) xTaskResumeAll();
3524 }
3525 else
3526 {
3527 mtCOVERAGE_TEST_MARKER();
3528 }
3529 }
3530 #endif /* configUSE_TICKLESS_IDLE */
3531 }
3532}
3533/*-----------------------------------------------------------*/
3534
3535#if( configUSE_TICKLESS_IDLE != 0 )
3536
3537 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
3538 {
3539 /* The idle task exists in addition to the application tasks. */
3540 const UBaseType_t uxNonApplicationTasks = 1;
3541 eSleepModeStatus eReturn = eStandardSleep;
3542
3543 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
3544 {
3545 /* A task was made ready while the scheduler was suspended. */
3546 eReturn = eAbortSleep;
3547 }
3548 else if( xYieldPending != pdFALSE )
3549 {
3550 /* A yield was pended while the scheduler was suspended. */
3551 eReturn = eAbortSleep;
3552 }
3553 else
3554 {
3555 /* If all the tasks are in the suspended list (which might mean they
3556 have an infinite block time rather than actually being suspended)
3557 then it is safe to turn all clocks off and just wait for external
3558 interrupts. */
3559 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
3560 {
3561 eReturn = eNoTasksWaitingTimeout;
3562 }
3563 else
3564 {
3565 mtCOVERAGE_TEST_MARKER();
3566 }
3567 }
3568
3569 return eReturn;
3570 }
3571
3572#endif /* configUSE_TICKLESS_IDLE */
3573/*-----------------------------------------------------------*/
3574
3575#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3576
3577 void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue )
3578 {
3579 TCB_t *pxTCB;
3580
3581 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3582 {
3583 pxTCB = prvGetTCBFromHandle( xTaskToSet );
3584 pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
3585 }
3586 }
3587
3588#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3589/*-----------------------------------------------------------*/
3590
3591#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3592
3593 void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex )
3594 {
3595 void *pvReturn = NULL;
3596 TCB_t *pxTCB;
3597
3598 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3599 {
3600 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
3601 pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ];
3602 }
3603 else
3604 {
3605 pvReturn = NULL;
3606 }
3607
3608 return pvReturn;
3609 }
3610
3611#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3612/*-----------------------------------------------------------*/
3613
3614#if ( portUSING_MPU_WRAPPERS == 1 )
3615
3616 void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions )
3617 {
3618 TCB_t *pxTCB;
3619
3620 /* If null is passed in here then we are modifying the MPU settings of
3621 the calling task. */
3622 pxTCB = prvGetTCBFromHandle( xTaskToModify );
3623
3624 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
3625 }
3626
3627#endif /* portUSING_MPU_WRAPPERS */
3628/*-----------------------------------------------------------*/
3629
3630static void prvInitialiseTaskLists( void )
3631{
3632UBaseType_t uxPriority;
3633
3634 for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
3635 {
3636 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
3637 }
3638
3639 vListInitialise( &xDelayedTaskList1 );
3640 vListInitialise( &xDelayedTaskList2 );
3641 vListInitialise( &xPendingReadyList );
3642
3643 #if ( INCLUDE_vTaskDelete == 1 )
3644 {
3645 vListInitialise( &xTasksWaitingTermination );
3646 }
3647 #endif /* INCLUDE_vTaskDelete */
3648
3649 #if ( INCLUDE_vTaskSuspend == 1 )
3650 {
3651 vListInitialise( &xSuspendedTaskList );
3652 }
3653 #endif /* INCLUDE_vTaskSuspend */
3654
3655 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
3656 using list2. */
3657 pxDelayedTaskList = &xDelayedTaskList1;
3658 pxOverflowDelayedTaskList = &xDelayedTaskList2;
3659}
3660/*-----------------------------------------------------------*/
3661
3662static void prvCheckTasksWaitingTermination( void )
3663{
3664
3665 /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
3666
3667 #if ( INCLUDE_vTaskDelete == 1 )
3668 {
3669 TCB_t *pxTCB;
3670
3671 /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL()
3672 being called too often in the idle task. */
3673 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
3674 {
3675 taskENTER_CRITICAL();
3676 {
3677 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3678 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
3679 --uxCurrentNumberOfTasks;
3680 --uxDeletedTasksWaitingCleanUp;
3681 }
3682 taskEXIT_CRITICAL();
3683
3684 prvDeleteTCB( pxTCB );
3685 }
3686 }
3687 #endif /* INCLUDE_vTaskDelete */
3688}
3689/*-----------------------------------------------------------*/
3690
3691#if( configUSE_TRACE_FACILITY == 1 )
3692
3693 void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
3694 {
3695 TCB_t *pxTCB;
3696
3697 /* xTask is NULL then get the state of the calling task. */
3698 pxTCB = prvGetTCBFromHandle( xTask );
3699
3700 pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;
3701 pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );
3702 pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
3703 pxTaskStatus->pxStackBase = pxTCB->pxStack;
3704 pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08003705 pxTaskStatus->uStackTotal = pxTCB->uStackDepth;
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08003706
3707 #if ( configUSE_MUTEXES == 1 )
3708 {
3709 pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
3710 }
3711 #else
3712 {
3713 pxTaskStatus->uxBasePriority = 0;
3714 }
3715 #endif
3716
3717 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3718 {
3719 pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
3720 }
3721 #else
3722 {
3723 pxTaskStatus->ulRunTimeCounter = 0;
3724 }
3725 #endif
3726
3727 /* Obtaining the task state is a little fiddly, so is only done if the
3728 value of eState passed into this function is eInvalid - otherwise the
3729 state is just set to whatever is passed in. */
3730 if( eState != eInvalid )
3731 {
3732 if( pxTCB == pxCurrentTCB )
3733 {
3734 pxTaskStatus->eCurrentState = eRunning;
3735 }
3736 else
3737 {
3738 pxTaskStatus->eCurrentState = eState;
3739
3740 #if ( INCLUDE_vTaskSuspend == 1 )
3741 {
3742 /* If the task is in the suspended list then there is a
3743 chance it is actually just blocked indefinitely - so really
3744 it should be reported as being in the Blocked state. */
3745 if( eState == eSuspended )
3746 {
3747 vTaskSuspendAll();
3748 {
3749 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
3750 {
3751 pxTaskStatus->eCurrentState = eBlocked;
3752 }
3753 }
3754 ( void ) xTaskResumeAll();
3755 }
3756 }
3757 #endif /* INCLUDE_vTaskSuspend */
3758 }
3759 }
3760 else
3761 {
3762 pxTaskStatus->eCurrentState = eTaskGetState( pxTCB );
3763 }
3764
3765 /* Obtaining the stack space takes some time, so the xGetFreeStackSpace
3766 parameter is provided to allow it to be skipped. */
3767 if( xGetFreeStackSpace != pdFALSE )
3768 {
3769 #if ( portSTACK_GROWTH > 0 )
3770 {
3771 pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );
3772 }
3773 #else
3774 {
3775 pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack );
3776 }
3777 #endif
3778 }
3779 else
3780 {
3781 pxTaskStatus->usStackHighWaterMark = 0;
3782 }
3783 }
3784
3785#endif /* configUSE_TRACE_FACILITY */
3786/*-----------------------------------------------------------*/
3787
3788#if ( configUSE_TRACE_FACILITY == 1 )
3789
3790 static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
3791 {
3792 configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;
3793 UBaseType_t uxTask = 0;
3794
3795 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
3796 {
3797 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3798
3799 /* Populate an TaskStatus_t structure within the
3800 pxTaskStatusArray array for each task that is referenced from
3801 pxList. See the definition of TaskStatus_t in task.h for the
3802 meaning of each TaskStatus_t structure member. */
3803 do
3804 {
3805 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3806 vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState );
3807 uxTask++;
3808 } while( pxNextTCB != pxFirstTCB );
3809 }
3810 else
3811 {
3812 mtCOVERAGE_TEST_MARKER();
3813 }
3814
3815 return uxTask;
3816 }
3817
3818#endif /* configUSE_TRACE_FACILITY */
3819/*-----------------------------------------------------------*/
3820
3821#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
3822
3823 static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
3824 {
3825 uint32_t ulCount = 0U;
3826
3827 while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
3828 {
3829 pucStackByte -= portSTACK_GROWTH;
3830 ulCount++;
3831 }
3832
3833 ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */
3834
3835 return ( configSTACK_DEPTH_TYPE ) ulCount;
3836 }
3837
3838#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */
3839/*-----------------------------------------------------------*/
3840
3841#if ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 )
3842
3843 /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the
3844 same except for their return type. Using configSTACK_DEPTH_TYPE allows the
3845 user to determine the return type. It gets around the problem of the value
3846 overflowing on 8-bit types without breaking backward compatibility for
3847 applications that expect an 8-bit return type. */
3848 configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask )
3849 {
3850 TCB_t *pxTCB;
3851 uint8_t *pucEndOfStack;
3852 configSTACK_DEPTH_TYPE uxReturn;
3853
3854 /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are
3855 the same except for their return type. Using configSTACK_DEPTH_TYPE
3856 allows the user to determine the return type. It gets around the
3857 problem of the value overflowing on 8-bit types without breaking
3858 backward compatibility for applications that expect an 8-bit return
3859 type. */
3860
3861 pxTCB = prvGetTCBFromHandle( xTask );
3862
3863 #if portSTACK_GROWTH < 0
3864 {
3865 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3866 }
3867 #else
3868 {
3869 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3870 }
3871 #endif
3872
3873 uxReturn = prvTaskCheckFreeStackSpace( pucEndOfStack );
3874
3875 return uxReturn;
3876 }
3877
3878#endif /* INCLUDE_uxTaskGetStackHighWaterMark2 */
3879/*-----------------------------------------------------------*/
3880
3881#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
3882
3883 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
3884 {
3885 TCB_t *pxTCB;
3886 uint8_t *pucEndOfStack;
3887 UBaseType_t uxReturn;
3888
3889 pxTCB = prvGetTCBFromHandle( xTask );
3890
3891 #if portSTACK_GROWTH < 0
3892 {
3893 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3894 }
3895 #else
3896 {
3897 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3898 }
3899 #endif
3900
3901 uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
3902
3903 return uxReturn;
3904 }
3905
3906#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
3907/*-----------------------------------------------------------*/
3908
3909#if ( INCLUDE_vTaskDelete == 1 )
3910
3911 static void prvDeleteTCB( TCB_t *pxTCB )
3912 {
3913 /* This call is required specifically for the TriCore port. It must be
3914 above the vPortFree() calls. The call is also used by ports/demos that
3915 want to allocate and clean RAM statically. */
3916 portCLEAN_UP_TCB( pxTCB );
3917
3918 /* Free up the memory allocated by the scheduler for the task. It is up
3919 to the task to free any memory allocated at the application level. */
3920 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3921 {
3922 _reclaim_reent( &( pxTCB->xNewLib_reent ) );
3923 }
3924 #endif /* configUSE_NEWLIB_REENTRANT */
3925
3926 #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
3927 {
3928 /* The task can only have been allocated dynamically - free both
3929 the stack and TCB. */
3930 vPortFree( pxTCB->pxStack );
3931 vPortFree( pxTCB );
3932 }
3933 #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
3934 {
3935 /* The task could have been allocated statically or dynamically, so
3936 check what was statically allocated before trying to free the
3937 memory. */
3938 if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
3939 {
3940 /* Both the stack and TCB were allocated dynamically, so both
3941 must be freed. */
3942 vPortFree( pxTCB->pxStack );
3943 vPortFree( pxTCB );
3944 }
3945 else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )
3946 {
3947 /* Only the stack was statically allocated, so the TCB is the
3948 only memory that must be freed. */
3949 vPortFree( pxTCB );
3950 }
3951 else
3952 {
3953 /* Neither the stack nor the TCB were allocated dynamically, so
3954 nothing needs to be freed. */
3955 configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
3956 mtCOVERAGE_TEST_MARKER();
3957 }
3958 }
3959 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
3960 }
3961
3962#endif /* INCLUDE_vTaskDelete */
3963/*-----------------------------------------------------------*/
3964
3965static void prvResetNextTaskUnblockTime( void )
3966{
3967TCB_t *pxTCB;
3968
3969 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
3970 {
3971 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
3972 the maximum possible value so it is extremely unlikely that the
3973 if( xTickCount >= xNextTaskUnblockTime ) test will pass until
3974 there is an item in the delayed list. */
3975 xNextTaskUnblockTime = portMAX_DELAY;
3976 }
3977 else
3978 {
3979 /* The new current delayed list is not empty, get the value of
3980 the item at the head of the delayed list. This is the time at
3981 which the task at the head of the delayed list should be removed
3982 from the Blocked state. */
3983 ( pxTCB ) = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
3984 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
3985 }
3986}
3987/*-----------------------------------------------------------*/
3988
3989#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
3990
3991 TaskHandle_t xTaskGetCurrentTaskHandle( void )
3992 {
3993 TaskHandle_t xReturn;
3994
3995 /* A critical section is not required as this is not called from
3996 an interrupt and the current TCB will always be the same for any
3997 individual execution thread. */
3998 xReturn = pxCurrentTCB;
3999
4000 return xReturn;
4001 }
4002
4003#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
4004/*-----------------------------------------------------------*/
4005
4006#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
4007
4008 BaseType_t xTaskGetSchedulerState( void )
4009 {
4010 BaseType_t xReturn;
4011
4012 if( xSchedulerRunning == pdFALSE )
4013 {
4014 xReturn = taskSCHEDULER_NOT_STARTED;
4015 }
4016 else
4017 {
4018 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4019 {
4020 xReturn = taskSCHEDULER_RUNNING;
4021 }
4022 else
4023 {
4024 xReturn = taskSCHEDULER_SUSPENDED;
4025 }
4026 }
4027
4028 return xReturn;
4029 }
4030
4031#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
4032/*-----------------------------------------------------------*/
4033
4034#if ( configUSE_MUTEXES == 1 )
4035
4036 BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
4037 {
4038 TCB_t * const pxMutexHolderTCB = pxMutexHolder;
4039 BaseType_t xReturn = pdFALSE;
4040
4041 /* If the mutex was given back by an interrupt while the queue was
4042 locked then the mutex holder might now be NULL. _RB_ Is this still
4043 needed as interrupts can no longer use mutexes? */
4044 if( pxMutexHolder != NULL )
4045 {
4046 /* If the holder of the mutex has a priority below the priority of
4047 the task attempting to obtain the mutex then it will temporarily
4048 inherit the priority of the task attempting to obtain the mutex. */
4049 if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
4050 {
4051 /* Adjust the mutex holder state to account for its new
4052 priority. Only reset the event list item value if the value is
4053 not being used for anything else. */
4054 if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
4055 {
4056 listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
4057 }
4058 else
4059 {
4060 mtCOVERAGE_TEST_MARKER();
4061 }
4062
4063 /* If the task being modified is in the ready state it will need
4064 to be moved into a new list. */
4065 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
4066 {
4067 if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
4068 {
4069 taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
4070 }
4071 else
4072 {
4073 mtCOVERAGE_TEST_MARKER();
4074 }
4075
4076 /* Inherit the priority before being moved into the new list. */
4077 pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
4078 prvAddTaskToReadyList( pxMutexHolderTCB );
4079 }
4080 else
4081 {
4082 /* Just inherit the priority. */
4083 pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
4084 }
4085
4086 traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );
4087
4088 /* Inheritance occurred. */
4089 xReturn = pdTRUE;
4090 }
4091 else
4092 {
4093 if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )
4094 {
4095 /* The base priority of the mutex holder is lower than the
4096 priority of the task attempting to take the mutex, but the
4097 current priority of the mutex holder is not lower than the
4098 priority of the task attempting to take the mutex.
4099 Therefore the mutex holder must have already inherited a
4100 priority, but inheritance would have occurred if that had
4101 not been the case. */
4102 xReturn = pdTRUE;
4103 }
4104 else
4105 {
4106 mtCOVERAGE_TEST_MARKER();
4107 }
4108 }
4109 }
4110 else
4111 {
4112 mtCOVERAGE_TEST_MARKER();
4113 }
4114
4115 return xReturn;
4116 }
4117
4118#endif /* configUSE_MUTEXES */
4119/*-----------------------------------------------------------*/
4120
4121#if ( configUSE_MUTEXES == 1 )
4122
4123 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
4124 {
4125 TCB_t * const pxTCB = pxMutexHolder;
4126 BaseType_t xReturn = pdFALSE;
4127
4128 if( pxMutexHolder != NULL )
4129 {
4130 /* A task can only have an inherited priority if it holds the mutex.
4131 If the mutex is held by a task then it cannot be given from an
4132 interrupt, and if a mutex is given by the holding task then it must
4133 be the running state task. */
4134 configASSERT( pxTCB == pxCurrentTCB );
4135 configASSERT( pxTCB->uxMutexesHeld );
4136 ( pxTCB->uxMutexesHeld )--;
4137
4138 /* Has the holder of the mutex inherited the priority of another
4139 task? */
4140 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
4141 {
4142 /* Only disinherit if no other mutexes are held. */
4143 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
4144 {
4145 /* A task can only have an inherited priority if it holds
4146 the mutex. If the mutex is held by a task then it cannot be
4147 given from an interrupt, and if a mutex is given by the
4148 holding task then it must be the running state task. Remove
4149 the holding task from the ready list. */
4150 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
4151 {
4152 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
4153 }
4154 else
4155 {
4156 mtCOVERAGE_TEST_MARKER();
4157 }
4158
4159 /* Disinherit the priority before adding the task into the
4160 new ready list. */
4161 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
4162 pxTCB->uxPriority = pxTCB->uxBasePriority;
4163
4164 /* Reset the event list item value. It cannot be in use for
4165 any other purpose if this task is running, and it must be
4166 running to give back the mutex. */
4167 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
4168 prvAddTaskToReadyList( pxTCB );
4169
4170 /* Return true to indicate that a context switch is required.
4171 This is only actually required in the corner case whereby
4172 multiple mutexes were held and the mutexes were given back
4173 in an order different to that in which they were taken.
4174 If a context switch did not occur when the first mutex was
4175 returned, even if a task was waiting on it, then a context
4176 switch should occur when the last mutex is returned whether
4177 a task is waiting on it or not. */
4178 xReturn = pdTRUE;
4179 }
4180 else
4181 {
4182 mtCOVERAGE_TEST_MARKER();
4183 }
4184 }
4185 else
4186 {
4187 mtCOVERAGE_TEST_MARKER();
4188 }
4189 }
4190 else
4191 {
4192 mtCOVERAGE_TEST_MARKER();
4193 }
4194
4195 return xReturn;
4196 }
4197
4198#endif /* configUSE_MUTEXES */
4199/*-----------------------------------------------------------*/
4200
4201#if ( configUSE_MUTEXES == 1 )
4202
4203 void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )
4204 {
4205 TCB_t * const pxTCB = pxMutexHolder;
4206 UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
4207 const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
4208
4209 if( pxMutexHolder != NULL )
4210 {
4211 /* If pxMutexHolder is not NULL then the holder must hold at least
4212 one mutex. */
4213 configASSERT( pxTCB->uxMutexesHeld );
4214
4215 /* Determine the priority to which the priority of the task that
4216 holds the mutex should be set. This will be the greater of the
4217 holding task's base priority and the priority of the highest
4218 priority task that is waiting to obtain the mutex. */
4219 if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )
4220 {
4221 uxPriorityToUse = uxHighestPriorityWaitingTask;
4222 }
4223 else
4224 {
4225 uxPriorityToUse = pxTCB->uxBasePriority;
4226 }
4227
4228 /* Does the priority need to change? */
4229 if( pxTCB->uxPriority != uxPriorityToUse )
4230 {
4231 /* Only disinherit if no other mutexes are held. This is a
4232 simplification in the priority inheritance implementation. If
4233 the task that holds the mutex is also holding other mutexes then
4234 the other mutexes may have caused the priority inheritance. */
4235 if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )
4236 {
4237 /* If a task has timed out because it already holds the
4238 mutex it was trying to obtain then it cannot of inherited
4239 its own priority. */
4240 configASSERT( pxTCB != pxCurrentTCB );
4241
4242 /* Disinherit the priority, remembering the previous
4243 priority to facilitate determining the subject task's
4244 state. */
4245 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
4246 uxPriorityUsedOnEntry = pxTCB->uxPriority;
4247 pxTCB->uxPriority = uxPriorityToUse;
4248
4249 /* Only reset the event list item value if the value is not
4250 being used for anything else. */
4251 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
4252 {
4253 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
4254 }
4255 else
4256 {
4257 mtCOVERAGE_TEST_MARKER();
4258 }
4259
4260 /* If the running task is not the task that holds the mutex
4261 then the task that holds the mutex could be in either the
4262 Ready, Blocked or Suspended states. Only remove the task
4263 from its current state list if it is in the Ready state as
4264 the task's priority is going to change and there is one
4265 Ready list per priority. */
4266 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
4267 {
4268 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
4269 {
4270 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
4271 }
4272 else
4273 {
4274 mtCOVERAGE_TEST_MARKER();
4275 }
4276
4277 prvAddTaskToReadyList( pxTCB );
4278 }
4279 else
4280 {
4281 mtCOVERAGE_TEST_MARKER();
4282 }
4283 }
4284 else
4285 {
4286 mtCOVERAGE_TEST_MARKER();
4287 }
4288 }
4289 else
4290 {
4291 mtCOVERAGE_TEST_MARKER();
4292 }
4293 }
4294 else
4295 {
4296 mtCOVERAGE_TEST_MARKER();
4297 }
4298 }
4299
4300#endif /* configUSE_MUTEXES */
4301/*-----------------------------------------------------------*/
4302
4303#if ( portCRITICAL_NESTING_IN_TCB == 1 )
4304
4305 void vTaskEnterCritical( void )
4306 {
4307 portDISABLE_INTERRUPTS();
4308
4309 if( xSchedulerRunning != pdFALSE )
4310 {
4311 ( pxCurrentTCB->uxCriticalNesting )++;
4312
4313 /* This is not the interrupt safe version of the enter critical
4314 function so assert() if it is being called from an interrupt
4315 context. Only API functions that end in "FromISR" can be used in an
4316 interrupt. Only assert if the critical nesting count is 1 to
4317 protect against recursive calls if the assert function also uses a
4318 critical section. */
4319 if( pxCurrentTCB->uxCriticalNesting == 1 )
4320 {
4321 portASSERT_IF_IN_ISR();
4322 }
4323 }
4324 else
4325 {
4326 mtCOVERAGE_TEST_MARKER();
4327 }
4328 }
4329
4330#endif /* portCRITICAL_NESTING_IN_TCB */
4331/*-----------------------------------------------------------*/
4332
4333#if ( portCRITICAL_NESTING_IN_TCB == 1 )
4334
4335 void vTaskExitCritical( void )
4336 {
4337 if( xSchedulerRunning != pdFALSE )
4338 {
4339 if( pxCurrentTCB->uxCriticalNesting > 0U )
4340 {
4341 ( pxCurrentTCB->uxCriticalNesting )--;
4342
4343 if( pxCurrentTCB->uxCriticalNesting == 0U )
4344 {
4345 portENABLE_INTERRUPTS();
4346 }
4347 else
4348 {
4349 mtCOVERAGE_TEST_MARKER();
4350 }
4351 }
4352 else
4353 {
4354 mtCOVERAGE_TEST_MARKER();
4355 }
4356 }
4357 else
4358 {
4359 mtCOVERAGE_TEST_MARKER();
4360 }
4361 }
4362
4363#endif /* portCRITICAL_NESTING_IN_TCB */
4364/*-----------------------------------------------------------*/
4365
4366#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4367
4368 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName )
4369 {
4370 size_t x;
4371
4372 /* Start by copying the entire string. */
4373 strcpy( pcBuffer, pcTaskName );
4374
4375 /* Pad the end of the string with spaces to ensure columns line up when
4376 printed out. */
4377 for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ )
4378 {
4379 pcBuffer[ x ] = ' ';
4380 }
4381
4382 /* Terminate. */
4383 pcBuffer[ x ] = ( char ) 0x00;
4384
4385 /* Return the new end of string. */
4386 return &( pcBuffer[ x ] );
4387 }
4388
4389#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
4390/*-----------------------------------------------------------*/
4391
4392#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
4393
4394 void vTaskList( char * pcWriteBuffer )
4395 {
4396 TaskStatus_t *pxTaskStatusArray;
4397 UBaseType_t uxArraySize, x;
4398 char cStatus;
4399
4400 /*
4401 * PLEASE NOTE:
4402 *
4403 * This function is provided for convenience only, and is used by many
4404 * of the demo applications. Do not consider it to be part of the
4405 * scheduler.
4406 *
4407 * vTaskList() calls uxTaskGetSystemState(), then formats part of the
4408 * uxTaskGetSystemState() output into a human readable table that
4409 * displays task names, states and stack usage.
4410 *
4411 * vTaskList() has a dependency on the sprintf() C library function that
4412 * might bloat the code size, use a lot of stack, and provide different
4413 * results on different platforms. An alternative, tiny, third party,
4414 * and limited functionality implementation of sprintf() is provided in
4415 * many of the FreeRTOS/Demo sub-directories in a file called
4416 * printf-stdarg.c (note printf-stdarg.c does not provide a full
4417 * snprintf() implementation!).
4418 *
4419 * It is recommended that production systems call uxTaskGetSystemState()
4420 * directly to get access to raw stats data, rather than indirectly
4421 * through a call to vTaskList().
4422 */
4423
4424
4425 /* Make sure the write buffer does not contain a string. */
4426 *pcWriteBuffer = ( char ) 0x00;
4427
4428 /* Take a snapshot of the number of tasks in case it changes while this
4429 function is executing. */
4430 uxArraySize = uxCurrentNumberOfTasks;
4431
4432 /* Allocate an array index for each task. NOTE! if
4433 configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
4434 equate to NULL. */
4435 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */
4436
4437 if( pxTaskStatusArray != NULL )
4438 {
4439 /* Generate the (binary) data. */
4440 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
4441
4442 /* Create a human readable table from the binary data. */
4443 for( x = 0; x < uxArraySize; x++ )
4444 {
4445 switch( pxTaskStatusArray[ x ].eCurrentState )
4446 {
4447 case eRunning: cStatus = tskRUNNING_CHAR;
4448 break;
4449
4450 case eReady: cStatus = tskREADY_CHAR;
4451 break;
4452
4453 case eBlocked: cStatus = tskBLOCKED_CHAR;
4454 break;
4455
4456 case eSuspended: cStatus = tskSUSPENDED_CHAR;
4457 break;
4458
4459 case eDeleted: cStatus = tskDELETED_CHAR;
4460 break;
4461
4462 case eInvalid: /* Fall through. */
4463 default: /* Should not get here, but it is included
4464 to prevent static checking errors. */
4465 cStatus = ( char ) 0x00;
4466 break;
4467 }
4468
4469 /* Write the task name to the string, padding with spaces so it
4470 can be printed in tabular form more easily. */
4471 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4472
4473 /* Write the rest of the string. */
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08004474 sprintf( pcWriteBuffer, "\t\t%c\t%u\t\t%u\t\t%u\t\t%u\t\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].uStackTotal, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08004475 pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
4476 }
4477
4478 /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
4479 is 0 then vPortFree() will be #defined to nothing. */
4480 vPortFree( pxTaskStatusArray );
4481 }
4482 else
4483 {
4484 mtCOVERAGE_TEST_MARKER();
4485 }
4486 }
4487
4488#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
4489/*----------------------------------------------------------*/
4490
4491#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
4492
4493 void vTaskGetRunTimeStats( char *pcWriteBuffer )
4494 {
4495 TaskStatus_t *pxTaskStatusArray;
4496 UBaseType_t uxArraySize, x;
4497 uint32_t ulTotalTime, ulStatsAsPercentage;
4498
4499 #if( configUSE_TRACE_FACILITY != 1 )
4500 {
4501 #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
4502 }
4503 #endif
4504
4505 /*
4506 * PLEASE NOTE:
4507 *
4508 * This function is provided for convenience only, and is used by many
4509 * of the demo applications. Do not consider it to be part of the
4510 * scheduler.
4511 *
4512 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
4513 * of the uxTaskGetSystemState() output into a human readable table that
4514 * displays the amount of time each task has spent in the Running state
4515 * in both absolute and percentage terms.
4516 *
4517 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
4518 * function that might bloat the code size, use a lot of stack, and
4519 * provide different results on different platforms. An alternative,
4520 * tiny, third party, and limited functionality implementation of
4521 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
4522 * a file called printf-stdarg.c (note printf-stdarg.c does not provide
4523 * a full snprintf() implementation!).
4524 *
4525 * It is recommended that production systems call uxTaskGetSystemState()
4526 * directly to get access to raw stats data, rather than indirectly
4527 * through a call to vTaskGetRunTimeStats().
4528 */
4529
4530 /* Make sure the write buffer does not contain a string. */
4531 *pcWriteBuffer = ( char ) 0x00;
4532
4533 /* Take a snapshot of the number of tasks in case it changes while this
4534 function is executing. */
4535 uxArraySize = uxCurrentNumberOfTasks;
4536
4537 /* Allocate an array index for each task. NOTE! If
4538 configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
4539 equate to NULL. */
4540 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */
4541
4542 if( pxTaskStatusArray != NULL )
4543 {
4544 /* Generate the (binary) data. */
4545 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
4546
4547 /* For percentage calculations. */
4548 ulTotalTime /= 100UL;
4549
4550 /* Avoid divide by zero errors. */
4551 if( ulTotalTime > 0UL )
4552 {
4553 /* Create a human readable table from the binary data. */
4554 for( x = 0; x < uxArraySize; x++ )
4555 {
4556 /* What percentage of the total run time has the task used?
4557 This will always be rounded down to the nearest integer.
4558 ulTotalRunTimeDiv100 has already been divided by 100. */
4559 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
4560
4561 /* Write the task name to the string, padding with
4562 spaces so it can be printed in tabular form more
4563 easily. */
4564 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4565
4566 if( ulStatsAsPercentage > 0UL )
4567 {
4568 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4569 {
4570 sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
4571 }
4572 #else
4573 {
4574 /* sizeof( int ) == sizeof( long ) so a smaller
4575 printf() library can be used. */
4576 sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
4577 }
4578 #endif
4579 }
4580 else
4581 {
4582 /* If the percentage is zero here then the task has
4583 consumed less than 1% of the total run time. */
4584 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4585 {
4586 sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter );
4587 }
4588 #else
4589 {
4590 /* sizeof( int ) == sizeof( long ) so a smaller
4591 printf() library can be used. */
4592 sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
4593 }
4594 #endif
4595 }
4596
4597 pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
4598 }
4599 }
4600 else
4601 {
4602 mtCOVERAGE_TEST_MARKER();
4603 }
4604
4605 /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
4606 is 0 then vPortFree() will be #defined to nothing. */
4607 vPortFree( pxTaskStatusArray );
4608 }
4609 else
4610 {
4611 mtCOVERAGE_TEST_MARKER();
4612 }
4613 }
4614
4615#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */
4616/*-----------------------------------------------------------*/
4617
4618TickType_t uxTaskResetEventItemValue( void )
4619{
4620TickType_t uxReturn;
4621
4622 uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) );
4623
4624 /* Reset the event list item to its normal value - so it can be used with
4625 queues and semaphores. */
4626 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
4627
4628 return uxReturn;
4629}
4630/*-----------------------------------------------------------*/
4631
4632#if ( configUSE_MUTEXES == 1 )
4633
4634 TaskHandle_t pvTaskIncrementMutexHeldCount( void )
4635 {
4636 /* If xSemaphoreCreateMutex() is called before any tasks have been created
4637 then pxCurrentTCB will be NULL. */
4638 if( pxCurrentTCB != NULL )
4639 {
4640 ( pxCurrentTCB->uxMutexesHeld )++;
4641 }
4642
4643 return pxCurrentTCB;
4644 }
4645
4646#endif /* configUSE_MUTEXES */
4647/*-----------------------------------------------------------*/
4648
4649#if( configUSE_TASK_NOTIFICATIONS == 1 )
4650
4651 uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
4652 {
4653 uint32_t ulReturn;
4654
4655 taskENTER_CRITICAL();
4656 {
4657 /* Only block if the notification count is not already non-zero. */
4658 if( pxCurrentTCB->ulNotifiedValue == 0UL )
4659 {
4660 /* Mark this task as waiting for a notification. */
4661 pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
4662
4663 if( xTicksToWait > ( TickType_t ) 0 )
4664 {
4665 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
4666 traceTASK_NOTIFY_TAKE_BLOCK();
4667
4668 /* All ports are written to allow a yield in a critical
4669 section (some will yield immediately, others wait until the
4670 critical section exits) - but it is not something that
4671 application code should ever do. */
4672 portYIELD_WITHIN_API();
4673 }
4674 else
4675 {
4676 mtCOVERAGE_TEST_MARKER();
4677 }
4678 }
4679 else
4680 {
4681 mtCOVERAGE_TEST_MARKER();
4682 }
4683 }
4684 taskEXIT_CRITICAL();
4685
4686 taskENTER_CRITICAL();
4687 {
4688 traceTASK_NOTIFY_TAKE();
4689 ulReturn = pxCurrentTCB->ulNotifiedValue;
4690
4691 if( ulReturn != 0UL )
4692 {
4693 if( xClearCountOnExit != pdFALSE )
4694 {
4695 pxCurrentTCB->ulNotifiedValue = 0UL;
4696 }
4697 else
4698 {
4699 pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
4700 }
4701 }
4702 else
4703 {
4704 mtCOVERAGE_TEST_MARKER();
4705 }
4706
4707 pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
4708 }
4709 taskEXIT_CRITICAL();
4710
4711 return ulReturn;
4712 }
4713
4714#endif /* configUSE_TASK_NOTIFICATIONS */
4715/*-----------------------------------------------------------*/
4716
4717#if( configUSE_TASK_NOTIFICATIONS == 1 )
4718
4719 BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
4720 {
4721 BaseType_t xReturn;
4722
4723 taskENTER_CRITICAL();
4724 {
4725 /* Only block if a notification is not already pending. */
4726 if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
4727 {
4728 /* Clear bits in the task's notification value as bits may get
4729 set by the notifying task or interrupt. This can be used to
4730 clear the value to zero. */
4731 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
4732
4733 /* Mark this task as waiting for a notification. */
4734 pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
4735
4736 if( xTicksToWait > ( TickType_t ) 0 )
4737 {
4738 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
4739 traceTASK_NOTIFY_WAIT_BLOCK();
4740
4741 /* All ports are written to allow a yield in a critical
4742 section (some will yield immediately, others wait until the
4743 critical section exits) - but it is not something that
4744 application code should ever do. */
4745 portYIELD_WITHIN_API();
4746 }
4747 else
4748 {
4749 mtCOVERAGE_TEST_MARKER();
4750 }
4751 }
4752 else
4753 {
4754 mtCOVERAGE_TEST_MARKER();
4755 }
4756 }
4757 taskEXIT_CRITICAL();
4758
4759 taskENTER_CRITICAL();
4760 {
4761 traceTASK_NOTIFY_WAIT();
4762
4763 if( pulNotificationValue != NULL )
4764 {
4765 /* Output the current notification value, which may or may not
4766 have changed. */
4767 *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
4768 }
4769
4770 /* If ucNotifyValue is set then either the task never entered the
4771 blocked state (because a notification was already pending) or the
4772 task unblocked because of a notification. Otherwise the task
4773 unblocked because of a timeout. */
4774 if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
4775 {
4776 /* A notification was not received. */
4777 xReturn = pdFALSE;
4778 }
4779 else
4780 {
4781 /* A notification was already pending or a notification was
4782 received while the task was waiting. */
4783 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
4784 xReturn = pdTRUE;
4785 }
4786
4787 pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
4788 }
4789 taskEXIT_CRITICAL();
4790
4791 return xReturn;
4792 }
4793
4794#endif /* configUSE_TASK_NOTIFICATIONS */
4795/*-----------------------------------------------------------*/
4796
4797#if( configUSE_TASK_NOTIFICATIONS == 1 )
4798
4799 BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
4800 {
4801 TCB_t * pxTCB;
4802 BaseType_t xReturn = pdPASS;
4803 uint8_t ucOriginalNotifyState;
4804
4805 configASSERT( xTaskToNotify );
4806 pxTCB = xTaskToNotify;
4807
4808 taskENTER_CRITICAL();
4809 {
4810 if( pulPreviousNotificationValue != NULL )
4811 {
4812 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4813 }
4814
4815 ucOriginalNotifyState = pxTCB->ucNotifyState;
4816
4817 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
4818
4819 switch( eAction )
4820 {
4821 case eSetBits :
4822 pxTCB->ulNotifiedValue |= ulValue;
4823 break;
4824
4825 case eIncrement :
4826 ( pxTCB->ulNotifiedValue )++;
4827 break;
4828
4829 case eSetValueWithOverwrite :
4830 pxTCB->ulNotifiedValue = ulValue;
4831 break;
4832
4833 case eSetValueWithoutOverwrite :
4834 if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
4835 {
4836 pxTCB->ulNotifiedValue = ulValue;
4837 }
4838 else
4839 {
4840 /* The value could not be written to the task. */
4841 xReturn = pdFAIL;
4842 }
4843 break;
4844
4845 case eNoAction:
4846 /* The task is being notified without its notify value being
4847 updated. */
4848 break;
4849
4850 default:
4851 /* Should not get here if all enums are handled.
4852 Artificially force an assert by testing a value the
4853 compiler can't assume is const. */
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08004854 configASSERT( pxTCB->ulNotifiedValue == ~0U );
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08004855
4856 break;
4857 }
4858
4859 traceTASK_NOTIFY();
4860
4861 /* If the task is in the blocked state specifically to wait for a
4862 notification then unblock it now. */
4863 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
4864 {
4865 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
4866 prvAddTaskToReadyList( pxTCB );
4867
4868 /* The task should not have been on an event list. */
4869 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4870
4871 #if( configUSE_TICKLESS_IDLE != 0 )
4872 {
4873 /* If a task is blocked waiting for a notification then
4874 xNextTaskUnblockTime might be set to the blocked task's time
4875 out time. If the task is unblocked for a reason other than
4876 a timeout xNextTaskUnblockTime is normally left unchanged,
4877 because it will automatically get reset to a new value when
4878 the tick count equals xNextTaskUnblockTime. However if
4879 tickless idling is used it might be more important to enter
4880 sleep mode at the earliest possible time - so reset
4881 xNextTaskUnblockTime here to ensure it is updated at the
4882 earliest possible time. */
4883 prvResetNextTaskUnblockTime();
4884 }
4885 #endif
4886
4887 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4888 {
4889 /* The notified task has a priority above the currently
4890 executing task so a yield is required. */
4891 taskYIELD_IF_USING_PREEMPTION();
4892 }
4893 else
4894 {
4895 mtCOVERAGE_TEST_MARKER();
4896 }
4897 }
4898 else
4899 {
4900 mtCOVERAGE_TEST_MARKER();
4901 }
4902 }
4903 taskEXIT_CRITICAL();
4904
4905 return xReturn;
4906 }
4907
4908#endif /* configUSE_TASK_NOTIFICATIONS */
4909/*-----------------------------------------------------------*/
4910
4911#if( configUSE_TASK_NOTIFICATIONS == 1 )
4912
4913 BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
4914 {
4915 TCB_t * pxTCB;
4916 uint8_t ucOriginalNotifyState;
4917 BaseType_t xReturn = pdPASS;
4918 UBaseType_t uxSavedInterruptStatus;
4919
4920 configASSERT( xTaskToNotify );
4921
4922 /* RTOS ports that support interrupt nesting have the concept of a
4923 maximum system call (or maximum API call) interrupt priority.
4924 Interrupts that are above the maximum system call priority are keep
4925 permanently enabled, even when the RTOS kernel is in a critical section,
4926 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4927 is defined in FreeRTOSConfig.h then
4928 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4929 failure if a FreeRTOS API function is called from an interrupt that has
4930 been assigned a priority above the configured maximum system call
4931 priority. Only FreeRTOS functions that end in FromISR can be called
4932 from interrupts that have been assigned a priority at or (logically)
4933 below the maximum system call interrupt priority. FreeRTOS maintains a
4934 separate interrupt safe API to ensure interrupt entry is as fast and as
4935 simple as possible. More information (albeit Cortex-M specific) is
4936 provided on the following link:
4937 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4938 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4939
4940 pxTCB = xTaskToNotify;
4941
4942 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4943 {
4944 if( pulPreviousNotificationValue != NULL )
4945 {
4946 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4947 }
4948
4949 ucOriginalNotifyState = pxTCB->ucNotifyState;
4950 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
4951
4952 switch( eAction )
4953 {
4954 case eSetBits :
4955 pxTCB->ulNotifiedValue |= ulValue;
4956 break;
4957
4958 case eIncrement :
4959 ( pxTCB->ulNotifiedValue )++;
4960 break;
4961
4962 case eSetValueWithOverwrite :
4963 pxTCB->ulNotifiedValue = ulValue;
4964 break;
4965
4966 case eSetValueWithoutOverwrite :
4967 if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
4968 {
4969 pxTCB->ulNotifiedValue = ulValue;
4970 }
4971 else
4972 {
4973 /* The value could not be written to the task. */
4974 xReturn = pdFAIL;
4975 }
4976 break;
4977
4978 case eNoAction :
4979 /* The task is being notified without its notify value being
4980 updated. */
4981 break;
4982
4983 default:
4984 /* Should not get here if all enums are handled.
4985 Artificially force an assert by testing a value the
4986 compiler can't assume is const. */
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08004987 configASSERT( pxTCB->ulNotifiedValue == ~0U );
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08004988 break;
4989 }
4990
4991 traceTASK_NOTIFY_FROM_ISR();
4992
4993 /* If the task is in the blocked state specifically to wait for a
4994 notification then unblock it now. */
4995 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
4996 {
4997 /* The task should not have been on an event list. */
4998 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4999
5000 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
5001 {
5002 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
5003 prvAddTaskToReadyList( pxTCB );
5004 }
5005 else
5006 {
5007 /* The delayed and ready lists cannot be accessed, so hold
5008 this task pending until the scheduler is resumed. */
5009 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
5010 }
5011
5012 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
5013 {
5014 /* The notified task has a priority above the currently
5015 executing task so a yield is required. */
5016 if( pxHigherPriorityTaskWoken != NULL )
5017 {
5018 *pxHigherPriorityTaskWoken = pdTRUE;
5019 }
5020
5021 /* Mark that a yield is pending in case the user is not
5022 using the "xHigherPriorityTaskWoken" parameter to an ISR
5023 safe FreeRTOS function. */
5024 xYieldPending = pdTRUE;
5025 }
5026 else
5027 {
5028 mtCOVERAGE_TEST_MARKER();
5029 }
5030 }
5031 }
5032 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
5033
5034 return xReturn;
5035 }
5036
5037#endif /* configUSE_TASK_NOTIFICATIONS */
5038/*-----------------------------------------------------------*/
5039
5040#if( configUSE_TASK_NOTIFICATIONS == 1 )
5041
5042 void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
5043 {
5044 TCB_t * pxTCB;
5045 uint8_t ucOriginalNotifyState;
5046 UBaseType_t uxSavedInterruptStatus;
5047
5048 configASSERT( xTaskToNotify );
5049
5050 /* RTOS ports that support interrupt nesting have the concept of a
5051 maximum system call (or maximum API call) interrupt priority.
5052 Interrupts that are above the maximum system call priority are keep
5053 permanently enabled, even when the RTOS kernel is in a critical section,
5054 but cannot make any calls to FreeRTOS API functions. If configASSERT()
5055 is defined in FreeRTOSConfig.h then
5056 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
5057 failure if a FreeRTOS API function is called from an interrupt that has
5058 been assigned a priority above the configured maximum system call
5059 priority. Only FreeRTOS functions that end in FromISR can be called
5060 from interrupts that have been assigned a priority at or (logically)
5061 below the maximum system call interrupt priority. FreeRTOS maintains a
5062 separate interrupt safe API to ensure interrupt entry is as fast and as
5063 simple as possible. More information (albeit Cortex-M specific) is
5064 provided on the following link:
5065 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
5066 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
5067
5068 pxTCB = xTaskToNotify;
5069
5070 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
5071 {
5072 ucOriginalNotifyState = pxTCB->ucNotifyState;
5073 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
5074
5075 /* 'Giving' is equivalent to incrementing a count in a counting
5076 semaphore. */
5077 ( pxTCB->ulNotifiedValue )++;
5078
5079 traceTASK_NOTIFY_GIVE_FROM_ISR();
5080
5081 /* If the task is in the blocked state specifically to wait for a
5082 notification then unblock it now. */
5083 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
5084 {
5085 /* The task should not have been on an event list. */
5086 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
5087
5088 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
5089 {
5090 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
5091 prvAddTaskToReadyList( pxTCB );
5092 }
5093 else
5094 {
5095 /* The delayed and ready lists cannot be accessed, so hold
5096 this task pending until the scheduler is resumed. */
5097 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
5098 }
5099
5100 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
5101 {
5102 /* The notified task has a priority above the currently
5103 executing task so a yield is required. */
5104 if( pxHigherPriorityTaskWoken != NULL )
5105 {
5106 *pxHigherPriorityTaskWoken = pdTRUE;
5107 }
5108
5109 /* Mark that a yield is pending in case the user is not
5110 using the "xHigherPriorityTaskWoken" parameter in an ISR
5111 safe FreeRTOS function. */
5112 xYieldPending = pdTRUE;
5113 }
5114 else
5115 {
5116 mtCOVERAGE_TEST_MARKER();
5117 }
5118 }
5119 }
5120 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
5121 }
5122
5123#endif /* configUSE_TASK_NOTIFICATIONS */
5124
5125/*-----------------------------------------------------------*/
5126
5127#if( configUSE_TASK_NOTIFICATIONS == 1 )
5128
5129 BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask )
5130 {
5131 TCB_t *pxTCB;
5132 BaseType_t xReturn;
5133
5134 /* If null is passed in here then it is the calling task that is having
5135 its notification state cleared. */
5136 pxTCB = prvGetTCBFromHandle( xTask );
5137
5138 taskENTER_CRITICAL();
5139 {
5140 if( pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED )
5141 {
5142 pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
5143 xReturn = pdPASS;
5144 }
5145 else
5146 {
5147 xReturn = pdFAIL;
5148 }
5149 }
5150 taskEXIT_CRITICAL();
5151
5152 return xReturn;
5153 }
5154
5155#endif /* configUSE_TASK_NOTIFICATIONS */
5156/*-----------------------------------------------------------*/
5157
5158#if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) )
5159 TickType_t xTaskGetIdleRunTimeCounter( void )
5160 {
5161 return xIdleTaskHandle->ulRunTimeCounter;
5162 }
5163#endif
5164/*-----------------------------------------------------------*/
5165
5166static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
5167{
5168TickType_t xTimeToWake;
5169const TickType_t xConstTickCount = xTickCount;
5170
5171 #if( INCLUDE_xTaskAbortDelay == 1 )
5172 {
5173 /* About to enter a delayed list, so ensure the ucDelayAborted flag is
5174 reset to pdFALSE so it can be detected as having been set to pdTRUE
5175 when the task leaves the Blocked state. */
5176 pxCurrentTCB->ucDelayAborted = pdFALSE;
5177 }
5178 #endif
5179
5180 /* Remove the task from the ready list before adding it to the blocked list
5181 as the same list item is used for both lists. */
5182 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
5183 {
5184 /* The current task must be in a ready list, so there is no need to
5185 check, and the port reset macro can be called directly. */
5186 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task. pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */
5187 }
5188 else
5189 {
5190 mtCOVERAGE_TEST_MARKER();
5191 }
5192
5193 #if ( INCLUDE_vTaskSuspend == 1 )
5194 {
5195 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
5196 {
5197 /* Add the task to the suspended task list instead of a delayed task
5198 list to ensure it is not woken by a timing event. It will block
5199 indefinitely. */
5200 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
5201 }
5202 else
5203 {
5204 /* Calculate the time at which the task should be woken if the event
5205 does not occur. This may overflow but this doesn't matter, the
5206 kernel will manage it correctly. */
5207 xTimeToWake = xConstTickCount + xTicksToWait;
5208
5209 /* The list item will be inserted in wake time order. */
5210 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
5211
5212 if( xTimeToWake < xConstTickCount )
5213 {
5214 /* Wake time has overflowed. Place this item in the overflow
5215 list. */
5216 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
5217 }
5218 else
5219 {
5220 /* The wake time has not overflowed, so the current block list
5221 is used. */
5222 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
5223
5224 /* If the task entering the blocked state was placed at the
5225 head of the list of blocked tasks then xNextTaskUnblockTime
5226 needs to be updated too. */
5227 if( xTimeToWake < xNextTaskUnblockTime )
5228 {
5229 xNextTaskUnblockTime = xTimeToWake;
5230 }
5231 else
5232 {
5233 mtCOVERAGE_TEST_MARKER();
5234 }
5235 }
5236 }
5237 }
5238 #else /* INCLUDE_vTaskSuspend */
5239 {
5240 /* Calculate the time at which the task should be woken if the event
5241 does not occur. This may overflow but this doesn't matter, the kernel
5242 will manage it correctly. */
5243 xTimeToWake = xConstTickCount + xTicksToWait;
5244
5245 /* The list item will be inserted in wake time order. */
5246 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
5247
5248 if( xTimeToWake < xConstTickCount )
5249 {
5250 /* Wake time has overflowed. Place this item in the overflow list. */
5251 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
5252 }
5253 else
5254 {
5255 /* The wake time has not overflowed, so the current block list is used. */
5256 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
5257
5258 /* If the task entering the blocked state was placed at the head of the
5259 list of blocked tasks then xNextTaskUnblockTime needs to be updated
5260 too. */
5261 if( xTimeToWake < xNextTaskUnblockTime )
5262 {
5263 xNextTaskUnblockTime = xTimeToWake;
5264 }
5265 else
5266 {
5267 mtCOVERAGE_TEST_MARKER();
5268 }
5269 }
5270
5271 /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */
5272 ( void ) xCanBlockIndefinitely;
5273 }
5274 #endif /* INCLUDE_vTaskSuspend */
5275}
5276
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08005277#if ( configUSE_TRACE_FACILITY == 1 )
5278static TaskHandle_t prvFindTasksWithinSingleList( List_t *pxList, UBaseType_t tasknum )
5279{
5280 configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB, *pxFound=NULL;
5281
5282 if ( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
5283 {
5284 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
5285 do
5286 {
5287 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
5288 if (!pxFound && tasknum == pxNextTCB->uxTCBNumber)
5289 pxFound = pxNextTCB;
5290 } while( pxNextTCB != pxFirstTCB );
5291 }
5292 else
5293 {
5294 mtCOVERAGE_TEST_MARKER();
5295 }
5296
5297 return pxFound;
5298}
5299TaskHandle_t xGetTaskHandleOfNum(UBaseType_t tasknum)
5300{
5301 UBaseType_t uxQueue = configMAX_PRIORITIES;
5302 TCB_t *pxFirstTCB=NULL;
5303 do
5304 {
5305 uxQueue--;
5306 pxFirstTCB = prvFindTasksWithinSingleList( &( pxReadyTasksLists[ uxQueue ] ), tasknum );
5307 if (pxFirstTCB)
5308 goto GetTaskHandleOfNumExit;
5309 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY );
5310 pxFirstTCB = prvFindTasksWithinSingleList( ( List_t * ) pxDelayedTaskList, tasknum );
5311 if (pxFirstTCB)
5312 goto GetTaskHandleOfNumExit;
5313 pxFirstTCB = prvFindTasksWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, tasknum );
5314 if (pxFirstTCB)
5315 goto GetTaskHandleOfNumExit;
5316 #if( INCLUDE_vTaskDelete == 1 )
5317 {
5318 pxFirstTCB = prvFindTasksWithinSingleList( &xTasksWaitingTermination, tasknum );
5319 if (pxFirstTCB)
5320 goto GetTaskHandleOfNumExit;
5321 }
5322 #endif
5323
5324 #if ( INCLUDE_vTaskSuspend == 1 )
5325 {
5326 pxFirstTCB = prvFindTasksWithinSingleList( &xSuspendedTaskList, tasknum );
5327 if (pxFirstTCB)
5328 goto GetTaskHandleOfNumExit;
5329 }
5330 #endif
5331GetTaskHandleOfNumExit:
5332 return pxFirstTCB;
5333}
5334#endif
5335void vTaskRename( TaskHandle_t xTask, const char *name)
5336{
5337 TCB_t *pxTCB;
5338
5339 pxTCB = prvGetTCBFromHandle( xTask );
5340 configASSERT( pxTCB );
5341
5342 strncpy(pxTCB->pcTaskName, name, configMAX_TASK_NAME_LEN);
5343 pxTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';
5344}
5345
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08005346/* Code below here allows additional code to be inserted into this source file,
5347especially where access to file scope functions and data is needed (for example
5348when performing module tests). */
5349
5350#ifdef FREERTOS_MODULE_TEST
5351 #include "tasks_test_access_functions.h"
5352#endif
5353
5354
5355#if( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 )
5356
5357 #include "freertos_tasks_c_additions.h"
5358
5359 #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
5360 static void freertos_tasks_c_additions_init( void )
5361 {
5362 FREERTOS_TASKS_C_ADDITIONS_INIT();
5363 }
5364 #endif
5365
5366#endif
5367
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08005368#if ENABLE_STACKTRACE
5369void task_stack_range(TaskHandle_t xTask, unsigned long *low, unsigned long *high);
5370void task_stack_range(TaskHandle_t xTask, unsigned long *low, unsigned long *high)
5371{
5372 TCB_t *pxTCB;
5373 pxTCB = prvGetTCBFromHandle( xTask );
5374 *low = (unsigned long)pxTCB->pxStack;
5375 *high = *low + pxTCB->uStackDepth * sizeof(StackType_t);
5376}
5377#endif
kelvin.zhang57fb6ae2021-10-15 10:19:42 +08005378
Xiaohu.Huang2c96ef42021-10-15 16:12:27 +08005379#if ENABLE_KASAN
5380void kasan_enable_current(void)
5381{
5382 if (pxCurrentTCB)
5383 pxCurrentTCB->kasan_depth--;
5384}
5385
5386void kasan_disable_current(void)
5387{
5388 if (pxCurrentTCB)
5389 pxCurrentTCB->kasan_depth++;
5390}
5391
5392int kasan_current_enabled(void)
5393{
5394 if (pxCurrentTCB)
5395 return (pxCurrentTCB->kasan_depth<=0);
5396 return 0;
5397}
5398#endif