Merge branch 'bugfix/tw9313_dual_core_issue' into 'master'

freertos: fix dual core issue

This commit try to fix dual issue tw9313 raised by QA
1. Put per-core data into critical session or interrupt disabled/enabled session
2. Idle task may have problem when it terminate the task in both core

See merge request !333
This commit is contained in:
Jiang Jiang Jian 2016-12-27 22:06:55 +08:00
commit 6d0fd80af4
3 changed files with 41 additions and 25 deletions

View file

@ -3,7 +3,7 @@ menu "FreeRTOS"
# This is actually also handled in the ESP32 startup code, not only in FreeRTOS. # This is actually also handled in the ESP32 startup code, not only in FreeRTOS.
config FREERTOS_UNICORE config FREERTOS_UNICORE
bool "Run FreeRTOS only on first core" bool "Run FreeRTOS only on first core"
default y default n
help help
This version of FreeRTOS normally takes control of all cores of 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. the CPU. Select this if you only want to start it on the first core.
@ -195,8 +195,6 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE
If enabled, additional debug information will be printed for recursive If enabled, additional debug information will be printed for recursive
portMUX usage. portMUX usage.
endif # FREERTOS_DEBUG_INTERNALS endif # FREERTOS_DEBUG_INTERNALS
endmenu endmenu

View file

@ -213,7 +213,6 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux);
#define portEXIT_CRITICAL_ISR(mux) vPortCPUReleaseMutex(mux) #define portEXIT_CRITICAL_ISR(mux) vPortCPUReleaseMutex(mux)
#endif #endif
// Cleaner and preferred solution allows nested interrupts disabling and restoring via local registers or stack. // Cleaner and preferred solution allows nested interrupts disabling and restoring via local registers or stack.
// They can be called from interrupts too. // They can be called from interrupts too.
//NOT SMP-COMPATIBLE! Use only if all you want is to disable the interrupts locally! //NOT SMP-COMPATIBLE! Use only if all you want is to disable the interrupts locally!

View file

@ -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 \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
the same priority get an equal share of the processor time. */ \ 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 */ } /* 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. */ \ /* Find the highest priority queue that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ 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() */ } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -456,7 +456,7 @@ count overflows. */
* see if the parameter is NULL and returns a pointer to the appropriate TCB. * see if the parameter is NULL and returns a pointer to the appropriate TCB.
*/ */
/* ToDo: See if this still works for multicore. */ /* 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 /* 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 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 ) void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
{ {
TCB_t *curTCB = xTaskGetCurrentTaskHandle();
BaseType_t i; BaseType_t i;
if (xCoreID != tskNO_AFFINITY) { if (xCoreID != tskNO_AFFINITY) {
if ( pxCurrentTCB[ xCoreID ]->uxPriority < uxPriority ) { if ( curTCB->uxPriority < uxPriority ) {
vPortYieldOtherCore( xCoreID ); vPortYieldOtherCore( xCoreID );
} }
} }
@ -1039,6 +1041,7 @@ UBaseType_t x;
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID )
{ {
TCB_t *curTCB;
BaseType_t i; BaseType_t i;
/* Ensure interrupts don't access the task lists while the lists are being /* Ensure interrupts don't access the task lists while the lists are being
@ -1111,23 +1114,25 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
portSETUP_TCB( pxNewTCB ); portSETUP_TCB( pxNewTCB );
} }
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
taskEXIT_CRITICAL(&xTaskQueueMutex); taskEXIT_CRITICAL(&xTaskQueueMutex);
if( xSchedulerRunning != pdFALSE ) if( xSchedulerRunning != pdFALSE )
{ {
taskENTER_CRITICAL(&xTaskQueueMutex);
/* Scheduler is running. If the created task is of a higher priority than an executing task /* Scheduler is running. If the created task is of a higher priority than an executing task
then it should run now. then it should run now.
ToDo: This only works for the current core. If a task is scheduled on an other processor, ToDo: This only works for the current core. If a task is scheduled on an other processor,
the other processor will keep running the task it's working on, and only switch to the newer the other processor will keep running the task it's working on, and only switch to the newer
task on a timer interrupt. */ task on a timer interrupt. */
//No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. //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 /* Scheduler is running. If the created task is of a higher priority than an executing task
then it should run now. then it should run now.
No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. 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(); taskYIELD_IF_USING_PREEMPTION();
} }
@ -1143,6 +1148,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
taskEXIT_CRITICAL(&xTaskQueueMutex);
} }
else else
{ {
@ -1409,11 +1415,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
eTaskState eReturn; eTaskState eReturn;
List_t *pxStateList; List_t *pxStateList;
const TCB_t * const pxTCB = ( TCB_t * ) xTask; const TCB_t * const pxTCB = ( TCB_t * ) xTask;
TCB_t * curTCB = xTaskGetCurrentTaskHandle();
UNTESTED_FUNCTION(); UNTESTED_FUNCTION();
configASSERT( pxTCB ); configASSERT( pxTCB );
if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] ) if( pxTCB == curTCB )
{ {
/* The task calling this function is querying its own state. */ /* The task calling this function is querying its own state. */
eReturn = eRunning; eReturn = eRunning;
@ -1691,6 +1698,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
void vTaskSuspend( TaskHandle_t xTaskToSuspend ) void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{ {
TCB_t *pxTCB; TCB_t *pxTCB;
TCB_t *curTCB;
UNTESTED_FUNCTION(); UNTESTED_FUNCTION();
taskENTER_CRITICAL(&xTaskQueueMutex); taskENTER_CRITICAL(&xTaskQueueMutex);
@ -1723,10 +1731,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
} }
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
} }
taskEXIT_CRITICAL(&xTaskQueueMutex); taskEXIT_CRITICAL(&xTaskQueueMutex);
if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] ) if( pxTCB == curTCB )
{ {
if( xSchedulerRunning != pdFALSE ) if( xSchedulerRunning != pdFALSE )
{ {
@ -2034,7 +2043,7 @@ void vTaskEndScheduler( void )
//Return global reent struct if FreeRTOS isn't running, //Return global reent struct if FreeRTOS isn't running,
struct _reent* __getreent() { struct _reent* __getreent() {
//No lock needed because if this changes, we won't be running anymore. //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) { if (currTask==NULL) {
//No task running. Return global struct. //No task running. Return global struct.
return _GLOBAL_REENT; return _GLOBAL_REENT;
@ -2052,7 +2061,11 @@ void vTaskSuspendAll( void )
BaseType_t. Please read Richard Barry's reply in the following link to a 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! - post in the FreeRTOS support forum before reporting this as a bug! -
http://goo.gl/wu4acr */ http://goo.gl/wu4acr */
unsigned state;
state = portENTER_CRITICAL_NESTED();
++uxSchedulerSuspended[ xPortGetCoreID() ]; ++uxSchedulerSuspended[ xPortGetCoreID() ];
portEXIT_CRITICAL_NESTED(state);
} }
/*----------------------------------------------------------*/ /*----------------------------------------------------------*/
@ -2595,7 +2608,7 @@ BaseType_t xSwitchRequired = pdFALSE;
/* If xTask is NULL then we are setting our own task hook. */ /* If xTask is NULL then we are setting our own task hook. */
if( xTask == NULL ) if( xTask == NULL )
{ {
xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ]; xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle();
} }
else else
{ {
@ -2626,7 +2639,7 @@ BaseType_t xSwitchRequired = pdFALSE;
/* If xTask is NULL then we are calling our own task hook. */ /* If xTask is NULL then we are calling our own task hook. */
if( xTask == NULL ) if( xTask == NULL )
{ {
xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ]; xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle();
} }
else else
{ {
@ -3387,8 +3400,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{ {
pxTCB = prvGetTCBFromHandle( xTaskToSet );
taskENTER_CRITICAL(&xTaskQueueMutex); taskENTER_CRITICAL(&xTaskQueueMutex);
pxTCB = prvGetTCBFromHandle( xTaskToSet );
pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback; pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback;
taskEXIT_CRITICAL(&xTaskQueueMutex); taskEXIT_CRITICAL(&xTaskQueueMutex);
@ -3408,8 +3421,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{ {
taskENTER_CRITICAL(&xTaskQueueMutex);
pxTCB = prvGetTCBFromHandle( xTaskToSet ); pxTCB = prvGetTCBFromHandle( xTaskToSet );
pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
taskEXIT_CRITICAL(&xTaskQueueMutex);
} }
} }
#endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS */ #endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS */
@ -3496,26 +3511,23 @@ static void prvCheckTasksWaitingTermination( void )
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */ too often in the idle task. */
taskENTER_CRITICAL(&xTaskQueueMutex);
while( uxTasksDeleted > ( UBaseType_t ) 0U ) while( uxTasksDeleted > ( UBaseType_t ) 0U )
{ {
taskENTER_CRITICAL(&xTaskQueueMutex);
{ {
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
} }
taskEXIT_CRITICAL(&xTaskQueueMutex);
if( xListIsEmpty == pdFALSE ) if( xListIsEmpty == pdFALSE )
{ {
TCB_t *pxTCB; TCB_t *pxTCB;
taskENTER_CRITICAL(&xTaskQueueMutex);
{ {
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks; --uxCurrentNumberOfTasks;
--uxTasksDeleted; --uxTasksDeleted;
} }
taskEXIT_CRITICAL(&xTaskQueueMutex);
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
{ {
@ -3536,6 +3548,7 @@ static void prvCheckTasksWaitingTermination( void )
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
taskEXIT_CRITICAL(&xTaskQueueMutex);
} }
#endif /* vTaskDelete */ #endif /* vTaskDelete */
} }
@ -3805,11 +3818,11 @@ TCB_t *pxTCB;
TaskHandle_t xTaskGetCurrentTaskHandle( void ) TaskHandle_t xTaskGetCurrentTaskHandle( void )
{ {
TaskHandle_t xReturn; TaskHandle_t xReturn;
unsigned state;
/* A critical section is not required as this is not called from state = portENTER_CRITICAL_NESTED();
an interrupt and the current TCB will always be the same for any
individual execution thread. */
xReturn = pxCurrentTCB[ xPortGetCoreID() ]; xReturn = pxCurrentTCB[ xPortGetCoreID() ];
portEXIT_CRITICAL_NESTED(state);
return xReturn; return xReturn;
} }
@ -3835,7 +3848,9 @@ TCB_t *pxTCB;
BaseType_t xTaskGetSchedulerState( void ) BaseType_t xTaskGetSchedulerState( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
unsigned state;
state = portENTER_CRITICAL_NESTED();
if( xSchedulerRunning == pdFALSE ) if( xSchedulerRunning == pdFALSE )
{ {
xReturn = taskSCHEDULER_NOT_STARTED; xReturn = taskSCHEDULER_NOT_STARTED;
@ -3851,6 +3866,7 @@ TCB_t *pxTCB;
xReturn = taskSCHEDULER_SUSPENDED; xReturn = taskSCHEDULER_SUSPENDED;
} }
} }
portEXIT_CRITICAL_NESTED(state);
return xReturn; return xReturn;
} }
@ -4386,6 +4402,8 @@ TickType_t uxReturn;
void *pvTaskIncrementMutexHeldCount( void ) void *pvTaskIncrementMutexHeldCount( void )
{ {
TCB_t *curTCB;
/* If xSemaphoreCreateMutex() is called before any tasks have been created /* If xSemaphoreCreateMutex() is called before any tasks have been created
then pxCurrentTCB will be NULL. */ then pxCurrentTCB will be NULL. */
taskENTER_CRITICAL(&xTaskQueueMutex); taskENTER_CRITICAL(&xTaskQueueMutex);
@ -4393,9 +4411,10 @@ TickType_t uxReturn;
{ {
( pxCurrentTCB[ xPortGetCoreID() ]->uxMutexesHeld )++; ( pxCurrentTCB[ xPortGetCoreID() ]->uxMutexesHeld )++;
} }
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
taskEXIT_CRITICAL(&xTaskQueueMutex); taskEXIT_CRITICAL(&xTaskQueueMutex);
return pxCurrentTCB[ xPortGetCoreID() ]; return curTCB;
} }
#endif /* configUSE_MUTEXES */ #endif /* configUSE_MUTEXES */