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 955587ba427..0baffbcd82e 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 4cd6918472f..d39faf60f02 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 33253f2240e..4e851768c7f 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 29cc3fe0963..646fa7686ec 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 9722a2c3087..b35b71ac12c 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 2482826674e..8d06ea30b0d 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 */