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