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