From 0cf1fd3a5acdbf0e0665c604c5cbbf470bc7610e Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Sat, 25 Jun 2022 17:03:09 +0800 Subject: [PATCH] freertos: Add multi-core OS startup race condition workaround FreeRTOS uses a single "xSchedulerRunning" variable to tack whether the scheduler has started, and this variable is set to "pdTRUE" by core 0 via calling vTaskStartScheduler(). However, with SMP FreeRTOS, there is a race condition where core 0 has already started the scheduler and another core has not called xPortStartScheduler() yet and calls some FreeRTOS API. Thus the resultant FreeRTOS API can cause errors as it thinks the scheduler has started. This commit adds a temporary workaround (by having each core maintain their own "xSchedulerRunning" variable. --- .../include/freertos/task.h | 9 +++++++++ .../portable/xtensa/port.c | 7 +++++++ .../freertos/FreeRTOS-Kernel-SMP/tasks.c | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h index 2e36eb17b0..8a4e681e48 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h @@ -3279,6 +3279,15 @@ void vTaskYieldWithinAPI( void ); #ifdef ESP_PLATFORM +#if ( configNUM_CORES > 1 ) +/* +Workaround for non-thread safe multi-core OS startup (see IDF-4524) +This function must be called with interrupts disabled on all cores other than +core 0 during startup. +*/ +void vTaskStartSchedulerOtherCores( void ); +#endif // configNUM_CORES > 1 + #include "idf_additions.h" #endif //ESP_PLATFORM diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index 08a1cc6d2c..bbd091efe5 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -448,6 +448,13 @@ BaseType_t xPortStartScheduler( void ) port_xSchedulerRunning[xPortGetCoreID()] = 1; +#if configNUM_CORES > 1 + // Workaround for non-thread safe multi-core OS startup (see IDF-4524) + if (xPortGetCoreID() != 0) { + vTaskStartSchedulerOtherCores(); + } +#endif // configNUM_CORES > 1 + // Cannot be directly called from C; never returns __asm__ volatile ("call0 _frxt_dispatch\n"); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c index 6aa7a506fe..18d1f9570b 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c @@ -369,7 +369,15 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tas PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +#if ( ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 ) ) +/* +Workaround for non-thread safe multi-core OS startup (see IDF-4524) +*/ +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunningPerCore[ configNUM_CORES ] = { pdFALSE }; +#define xSchedulerRunning xSchedulerRunningPerCore[ portGET_CORE_ID() ] +#else // ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 ) PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +#endif // ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 ) PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U; PRIVILEGED_DATA static volatile BaseType_t xYieldPendings[ configNUM_CORES ] = { pdFALSE }; PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; @@ -6443,3 +6451,14 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, #endif #endif /* if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) */ + +#if ( ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 ) ) +/* +Workaround for non-thread safe multi-core OS startup (see IDF-4524) +*/ +void vTaskStartSchedulerOtherCores( void ) +{ + /* This function is always called with interrupts disabled*/ + xSchedulerRunning = pdTRUE; +} +#endif // ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1