From fd446a674a495393d47e0a50e3be747e5df2a52b 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 955587ba42..0baffbcd82 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 4cd6918472..d39faf60f0 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -145,9 +145,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 29cc3fe096..646fa7686e 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -568,9 +568,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]); @@ -623,8 +627,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 2482826674..8d06ea30b0 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -3856,7 +3856,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 */