From 411ef4557a9044de0ada12cc804206b50a30457a Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 8 Aug 2024 09:24:55 +0200 Subject: [PATCH] fix(freertos): Fixed critical section macro in vTaskPlaceOnEventListRestricted() The vTaskPlaceOnEventListRestricted() did not use the correct macro when exiting a kernel cirtical section. This does not affect the HW targets but on the Linux port, this caused an issue as the critical nesting count became negative, leading to deadlocks. This commit fixes the bug and updates the linux port to prevent the nesting count from going negative. --- .../freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c | 5 +++++ .../freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c | 5 +++++ .../freertos/FreeRTOS-Kernel/portable/linux/port.c | 8 +++++++- .../freertos/FreeRTOS-Kernel/portable/riscv/port.c | 9 +++++++++ .../freertos/FreeRTOS-Kernel/portable/xtensa/port.c | 4 ++++ components/freertos/FreeRTOS-Kernel/tasks.c | 2 +- 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index cf11c4a5c6..e132d0a0e2 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -90,8 +90,13 @@ void vPortEnterCritical(void) void vPortExitCritical(void) { + + /* Critical section nesting coung must never be negative */ + configASSERT( port_uxCriticalNestingIDF > 0 ); + if (port_uxCriticalNestingIDF > 0) { port_uxCriticalNestingIDF--; + if (port_uxCriticalNestingIDF == 0) { // Restore the saved interrupt threshold vPortClearInterruptMask((int)port_uxCriticalOldInterruptStateIDF); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index f3b87a426b..b8eefa5f08 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -143,9 +143,14 @@ void vPortExitCriticalIDF(portMUX_TYPE *lock) spinlock_release(lock); BaseType_t coreID = xPortGetCoreID(); BaseType_t nesting = port_uxCriticalNestingIDF[coreID]; + + /* Critical section nesting count must never be negative */ + configASSERT( nesting > 0 ); + if (nesting > 0) { nesting--; port_uxCriticalNestingIDF[coreID] = nesting; + //This is the last exit call, restore the saved interrupt level if ( nesting == 0 ) { XTOS_RESTORE_JUST_INTLEVEL((int) port_uxCriticalOldInterruptStateIDF[coreID]); diff --git a/components/freertos/FreeRTOS-Kernel/portable/linux/port.c b/components/freertos/FreeRTOS-Kernel/portable/linux/port.c index 33253f2240..4e851768c7 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/linux/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/linux/port.c @@ -261,7 +261,13 @@ void vPortEnterCritical( void ) void vPortExitCritical( void ) { - uxCriticalNesting--; + if ( uxCriticalNesting > 0 ) + { + uxCriticalNesting--; + } + + /* Critical section nesting count must always be >= 0. */ + configASSERT( uxCriticalNesting >= 0 ); /* If we have reached 0 then re-enable the interrupts. */ if( uxCriticalNesting == 0 ) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index fb9dcf7166..a36636ce2c 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -565,9 +565,13 @@ void __attribute__((optimize("-O3"))) vPortExitCriticalMultiCore(portMUX_TYPE *m BaseType_t coreID = xPortGetCoreID(); BaseType_t nesting = port_uxCriticalNesting[coreID]; + /* Critical section nesting count must never be negative */ + configASSERT( nesting > 0 ); + if (nesting > 0) { nesting--; port_uxCriticalNesting[coreID] = nesting; + //This is the last exit call, restore the saved interrupt level if ( nesting == 0 ) { portCLEAR_INTERRUPT_MASK_FROM_ISR(port_uxOldInterruptState[coreID]); @@ -620,8 +624,13 @@ void vPortExitCritical(void) esp_rom_printf("vPortExitCritical(void) is not supported on single-core targets. Please use vPortExitCriticalMultiCore(portMUX_TYPE *mux) instead.\n"); abort(); #endif /* (configNUM_CORES > 1) */ + + /* Critical section nesting count must never be negative */ + configASSERT( port_uxCriticalNesting[0] > 0 ); + if (port_uxCriticalNesting[0] > 0) { port_uxCriticalNesting[0]--; + if (port_uxCriticalNesting[0] == 0) { portCLEAR_INTERRUPT_MASK_FROM_ISR(port_uxOldInterruptState[0]); } diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index 9722a2c308..b35b71ac12 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -497,9 +497,13 @@ void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) BaseType_t coreID = xPortGetCoreID(); BaseType_t nesting = port_uxCriticalNesting[coreID]; + /* Critical section nesting count must never be negative */ + configASSERT( nesting > 0 ); + if (nesting > 0) { nesting--; port_uxCriticalNesting[coreID] = nesting; + //This is the last exit call, restore the saved interrupt level if ( nesting == 0 ) { portCLEAR_INTERRUPT_MASK_FROM_ISR(port_uxOldInterruptState[coreID]); diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 182d2f5ae2..963a170664 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -3819,7 +3819,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); } /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL( &xKernelLock ); + prvEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } #endif /* configUSE_TIMERS */