From 2cffaf9cc841cbc5d2b495a326a2ba8bd3930d1b Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Thu, 22 Dec 2016 10:17:39 +0800 Subject: [PATCH 1/5] freertos: fix dual core issue This commit fixes: 1. xTaskGetCurrentTaskHandle may return wrong TCB when current task switch to a different core 2. Idle task may have problem when it terminate the task in both core --- components/freertos/tasks.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 16cce3b967..baaccb43e5 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3496,26 +3496,27 @@ static void prvCheckTasksWaitingTermination( void ) /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called too often in the idle task. */ + taskENTER_CRITICAL(&xTaskQueueMutex); while( uxTasksDeleted > ( UBaseType_t ) 0U ) { - taskENTER_CRITICAL(&xTaskQueueMutex); + //taskENTER_CRITICAL(&xTaskQueueMutex); { xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); } - taskEXIT_CRITICAL(&xTaskQueueMutex); + //taskEXIT_CRITICAL(&xTaskQueueMutex); if( xListIsEmpty == pdFALSE ) { TCB_t *pxTCB; - taskENTER_CRITICAL(&xTaskQueueMutex); + //taskENTER_CRITICAL(&xTaskQueueMutex); { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); --uxCurrentNumberOfTasks; --uxTasksDeleted; } - taskEXIT_CRITICAL(&xTaskQueueMutex); + //taskEXIT_CRITICAL(&xTaskQueueMutex); #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) { @@ -3535,7 +3536,8 @@ static void prvCheckTasksWaitingTermination( void ) { mtCOVERAGE_TEST_MARKER(); } - } + } + taskEXIT_CRITICAL(&xTaskQueueMutex); } #endif /* vTaskDelete */ } @@ -3806,10 +3808,12 @@ TCB_t *pxTCB; { TaskHandle_t xReturn; + vPortCPUAcquireMutex(&xTaskQueueMutex); /* A critical section is not required as this is not called from an interrupt and the current TCB will always be the same for any individual execution thread. */ xReturn = pxCurrentTCB[ xPortGetCoreID() ]; + vPortCPUReleaseMutex(&xTaskQueueMutex); return xReturn; } From 3a2fbda35c7bb0d1cbc99a59a6db32258be549f1 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Thu, 22 Dec 2016 10:51:40 +0800 Subject: [PATCH 2/5] freertos: minor change according to review comments --- components/freertos/tasks.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index baaccb43e5..f2bdf8ccb0 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3499,24 +3499,20 @@ static void prvCheckTasksWaitingTermination( void ) taskENTER_CRITICAL(&xTaskQueueMutex); while( uxTasksDeleted > ( UBaseType_t ) 0U ) { - //taskENTER_CRITICAL(&xTaskQueueMutex); { xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); } - //taskEXIT_CRITICAL(&xTaskQueueMutex); if( xListIsEmpty == pdFALSE ) { TCB_t *pxTCB; - //taskENTER_CRITICAL(&xTaskQueueMutex); { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); --uxCurrentNumberOfTasks; --uxTasksDeleted; } - //taskEXIT_CRITICAL(&xTaskQueueMutex); #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) { @@ -3809,9 +3805,6 @@ TCB_t *pxTCB; TaskHandle_t xReturn; vPortCPUAcquireMutex(&xTaskQueueMutex); - /* A critical section is not required as this is not called from - an interrupt and the current TCB will always be the same for any - individual execution thread. */ xReturn = pxCurrentTCB[ xPortGetCoreID() ]; vPortCPUReleaseMutex(&xTaskQueueMutex); From 99f4c697ee16d69f1f02ce6e14e64a4e35fc2651 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Thu, 22 Dec 2016 13:37:07 +0800 Subject: [PATCH 3/5] freertos: enable dual core by default --- components/freertos/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index f03da6bc01..b9db00e50b 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -3,7 +3,7 @@ menu "FreeRTOS" # This is actually also handled in the ESP32 startup code, not only in FreeRTOS. config FREERTOS_UNICORE bool "Run FreeRTOS only on first core" - default y + default n help This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want to start it on the first core. From d2e58193d235bcde15b1124af63358300412d31c Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Mon, 26 Dec 2016 19:04:41 +0800 Subject: [PATCH 4/5] add more protection for per-core data --- components/freertos/Kconfig | 6 ++- .../freertos/include/freertos/portmacro.h | 4 +- components/freertos/tasks.c | 54 +++++++++++++------ 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index b9db00e50b..859ece2c09 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -195,7 +195,11 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE If enabled, additional debug information will be printed for recursive portMUX usage. - +config FREERTOS_INT_DISABLING_DURATION_DEBUG + bool "Debug interrupt disabling duration" + default n + help + If enabled, the longest interrupt disabling duration will be recorded. endif # FREERTOS_DEBUG_INTERNALS diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index f20a4a1e26..9c15eebf9a 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -213,7 +213,6 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux); #define portEXIT_CRITICAL_ISR(mux) vPortCPUReleaseMutex(mux) #endif - // Cleaner and preferred solution allows nested interrupts disabling and restoring via local registers or stack. // They can be called from interrupts too. //NOT SMP-COMPATIBLE! Use only if all you want is to disable the interrupts locally! @@ -225,6 +224,9 @@ static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_I #define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state) +#define portDisableINT() portENTER_CRITICAL_NESTED() +#define portEnableINT(state) portEXIT_CRITICAL_NESTED((state)) + /* * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare * *mux to compare, and if it's the same, will set *mux to set. It will return the old value diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index f2bdf8ccb0..00df0df871 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -369,7 +369,7 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ the same priority get an equal share of the processor time. */ \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ + listGET_OWNER_OF_NEXT_ENTRY( xTaskGetCurrentTaskHandle(), &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ } /* taskSELECT_HIGHEST_PRIORITY_TASK */ /*-----------------------------------------------------------*/ @@ -398,7 +398,7 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK /* Find the highest priority queue that contains ready tasks. */ \ portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + listGET_OWNER_OF_NEXT_ENTRY( xTaskGetCurrentTaskHandle(), &( pxReadyTasksLists[ uxTopPriority ] ) ); \ } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ /*-----------------------------------------------------------*/ @@ -456,7 +456,7 @@ count overflows. */ * see if the parameter is NULL and returns a pointer to the appropriate TCB. */ /* ToDo: See if this still works for multicore. */ -#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ] : ( TCB_t * ) ( pxHandle ) ) +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) xTaskGetCurrentTaskHandle() : ( TCB_t * ) ( pxHandle ) ) /* The item value of the event list item is normally used to hold the priority of the task to which it belongs (coded to allow it to be held in reverse @@ -631,9 +631,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode */ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority ) { + TCB_t *curTCB = xTaskGetCurrentTaskHandle(); BaseType_t i; + if (xCoreID != tskNO_AFFINITY) { - if ( pxCurrentTCB[ xCoreID ]->uxPriority < uxPriority ) { + if ( curTCB->uxPriority < uxPriority ) { vPortYieldOtherCore( xCoreID ); } } @@ -1039,6 +1041,7 @@ UBaseType_t x; static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) { + TCB_t *curTCB; BaseType_t i; /* Ensure interrupts don't access the task lists while the lists are being @@ -1111,6 +1114,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode portSETUP_TCB( pxNewTCB ); } + curTCB = pxCurrentTCB[ xPortGetCoreID() ]; taskEXIT_CRITICAL(&xTaskQueueMutex); if( xSchedulerRunning != pdFALSE ) @@ -1121,17 +1125,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode the other processor will keep running the task it's working on, and only switch to the newer task on a timer interrupt. */ //No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. - if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority ) + if( curTCB->uxPriority < pxNewTCB->uxPriority ) { /* Scheduler is running. If the created task is of a higher priority than an executing task then it should run now. No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. */ - if( tskCAN_RUN_HERE( xCoreID ) && pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority ) + if( tskCAN_RUN_HERE( xCoreID ) && curTCB->uxPriority < pxNewTCB->uxPriority ) { taskYIELD_IF_USING_PREEMPTION(); } - else if( xCoreID != xPortGetCoreID() ) { + else if( xCoreID != xPortGetCoreID() ) {//TODO taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority); } else @@ -1409,11 +1413,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode eTaskState eReturn; List_t *pxStateList; const TCB_t * const pxTCB = ( TCB_t * ) xTask; + TCB_t * curTCB = xTaskGetCurrentTaskHandle(); UNTESTED_FUNCTION(); configASSERT( pxTCB ); - if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] ) + if( pxTCB == curTCB ) { /* The task calling this function is querying its own state. */ eReturn = eRunning; @@ -1691,6 +1696,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode void vTaskSuspend( TaskHandle_t xTaskToSuspend ) { TCB_t *pxTCB; + TCB_t *curTCB; UNTESTED_FUNCTION(); taskENTER_CRITICAL(&xTaskQueueMutex); @@ -1723,10 +1729,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode } vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); + curTCB = pxCurrentTCB[ xPortGetCoreID() ]; } taskEXIT_CRITICAL(&xTaskQueueMutex); - if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] ) + if( pxTCB == curTCB ) { if( xSchedulerRunning != pdFALSE ) { @@ -2034,7 +2041,7 @@ void vTaskEndScheduler( void ) //Return global reent struct if FreeRTOS isn't running, struct _reent* __getreent() { //No lock needed because if this changes, we won't be running anymore. - TCB_t *currTask=pxCurrentTCB[ xPortGetCoreID() ]; + TCB_t *currTask=xTaskGetCurrentTaskHandle(); if (currTask==NULL) { //No task running. Return global struct. return _GLOBAL_REENT; @@ -2052,7 +2059,11 @@ void vTaskSuspendAll( void ) BaseType_t. Please read Richard Barry's reply in the following link to a post in the FreeRTOS support forum before reporting this as a bug! - http://goo.gl/wu4acr */ + unsigned state; + + state = portDisableINT(); ++uxSchedulerSuspended[ xPortGetCoreID() ]; + portEnableINT(state); } /*----------------------------------------------------------*/ @@ -2595,7 +2606,7 @@ BaseType_t xSwitchRequired = pdFALSE; /* If xTask is NULL then we are setting our own task hook. */ if( xTask == NULL ) { - xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ]; + xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle(); } else { @@ -2626,7 +2637,7 @@ BaseType_t xSwitchRequired = pdFALSE; /* If xTask is NULL then we are calling our own task hook. */ if( xTask == NULL ) { - xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ]; + xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle(); } else { @@ -3387,8 +3398,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) { - pxTCB = prvGetTCBFromHandle( xTaskToSet ); taskENTER_CRITICAL(&xTaskQueueMutex); + pxTCB = prvGetTCBFromHandle( xTaskToSet ); pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback; taskEXIT_CRITICAL(&xTaskQueueMutex); @@ -3408,8 +3419,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) { + taskENTER_CRITICAL(&xTaskQueueMutex); pxTCB = prvGetTCBFromHandle( xTaskToSet ); pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; + taskEXIT_CRITICAL(&xTaskQueueMutex); } } #endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS */ @@ -3803,10 +3816,11 @@ TCB_t *pxTCB; TaskHandle_t xTaskGetCurrentTaskHandle( void ) { TaskHandle_t xReturn; + unsigned state; - vPortCPUAcquireMutex(&xTaskQueueMutex); + state = portDisableINT(); xReturn = pxCurrentTCB[ xPortGetCoreID() ]; - vPortCPUReleaseMutex(&xTaskQueueMutex); + portEnableINT(state); return xReturn; } @@ -3832,7 +3846,9 @@ TCB_t *pxTCB; BaseType_t xTaskGetSchedulerState( void ) { BaseType_t xReturn; + unsigned state; + state = portDisableINT(); if( xSchedulerRunning == pdFALSE ) { xReturn = taskSCHEDULER_NOT_STARTED; @@ -3848,6 +3864,7 @@ TCB_t *pxTCB; xReturn = taskSCHEDULER_SUSPENDED; } } + portEnableINT(state); return xReturn; } @@ -4383,16 +4400,19 @@ TickType_t uxReturn; void *pvTaskIncrementMutexHeldCount( void ) { + TCB_t *curTCB; + /* If xSemaphoreCreateMutex() is called before any tasks have been created - then pxCurrentTCB will be NULL. */ + then xTaskGetCurrentTaskHandle() will be NULL. */ taskENTER_CRITICAL(&xTaskQueueMutex); if( pxCurrentTCB[ xPortGetCoreID() ] != NULL ) { ( pxCurrentTCB[ xPortGetCoreID() ]->uxMutexesHeld )++; } + curTCB = pxCurrentTCB[ xPortGetCoreID() ]; taskEXIT_CRITICAL(&xTaskQueueMutex); - return pxCurrentTCB[ xPortGetCoreID() ]; + return curTCB; } #endif /* configUSE_MUTEXES */ From d049fd392953d8aaf2c3cb4270aa8b401e4f016a Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Tue, 27 Dec 2016 12:11:07 +0800 Subject: [PATCH 5/5] freertos: rework code based on review --- components/freertos/Kconfig | 6 ------ .../freertos/include/freertos/portmacro.h | 3 --- components/freertos/tasks.c | 20 ++++++++++--------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 859ece2c09..d8b392d577 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -195,12 +195,6 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE If enabled, additional debug information will be printed for recursive portMUX usage. -config FREERTOS_INT_DISABLING_DURATION_DEBUG - bool "Debug interrupt disabling duration" - default n - help - If enabled, the longest interrupt disabling duration will be recorded. - endif # FREERTOS_DEBUG_INTERNALS endmenu diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index 9c15eebf9a..7cae4b05b6 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -224,9 +224,6 @@ static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_I #define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state) -#define portDisableINT() portENTER_CRITICAL_NESTED() -#define portEnableINT(state) portEXIT_CRITICAL_NESTED((state)) - /* * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare * *mux to compare, and if it's the same, will set *mux to set. It will return the old value diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 00df0df871..159d96c5b2 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -1041,7 +1041,7 @@ UBaseType_t x; static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) { - TCB_t *curTCB; + TCB_t *curTCB; BaseType_t i; /* Ensure interrupts don't access the task lists while the lists are being @@ -1119,6 +1119,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode if( xSchedulerRunning != pdFALSE ) { + taskENTER_CRITICAL(&xTaskQueueMutex); /* Scheduler is running. If the created task is of a higher priority than an executing task then it should run now. ToDo: This only works for the current core. If a task is scheduled on an other processor, @@ -1135,7 +1136,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode { taskYIELD_IF_USING_PREEMPTION(); } - else if( xCoreID != xPortGetCoreID() ) {//TODO + else if( xCoreID != xPortGetCoreID() ) { taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority); } else @@ -1147,6 +1148,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode { mtCOVERAGE_TEST_MARKER(); } + taskEXIT_CRITICAL(&xTaskQueueMutex); } else { @@ -2061,9 +2063,9 @@ void vTaskSuspendAll( void ) http://goo.gl/wu4acr */ unsigned state; - state = portDisableINT(); + state = portENTER_CRITICAL_NESTED(); ++uxSchedulerSuspended[ xPortGetCoreID() ]; - portEnableINT(state); + portEXIT_CRITICAL_NESTED(state); } /*----------------------------------------------------------*/ @@ -3818,9 +3820,9 @@ TCB_t *pxTCB; TaskHandle_t xReturn; unsigned state; - state = portDisableINT(); + state = portENTER_CRITICAL_NESTED(); xReturn = pxCurrentTCB[ xPortGetCoreID() ]; - portEnableINT(state); + portEXIT_CRITICAL_NESTED(state); return xReturn; } @@ -3848,7 +3850,7 @@ TCB_t *pxTCB; BaseType_t xReturn; unsigned state; - state = portDisableINT(); + state = portENTER_CRITICAL_NESTED(); if( xSchedulerRunning == pdFALSE ) { xReturn = taskSCHEDULER_NOT_STARTED; @@ -3864,7 +3866,7 @@ TCB_t *pxTCB; xReturn = taskSCHEDULER_SUSPENDED; } } - portEnableINT(state); + portEXIT_CRITICAL_NESTED(state); return xReturn; } @@ -4403,7 +4405,7 @@ TickType_t uxReturn; TCB_t *curTCB; /* If xSemaphoreCreateMutex() is called before any tasks have been created - then xTaskGetCurrentTaskHandle() will be NULL. */ + then pxCurrentTCB will be NULL. */ taskENTER_CRITICAL(&xTaskQueueMutex); if( pxCurrentTCB[ xPortGetCoreID() ] != NULL ) {