mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
fix(freertos): close vTaskDeleteWithCaps cross-core delete race on SMP preview kernel
Replace the eTaskGetState() polling guard in prvTaskDeleteWithCaps() with a per-core xTaskGetCurrentTaskHandleForCore() check, so the predicate matches vTaskDelete()'s immediate-vs-deferred decision. This closes the taskTASK_SCHEDULED_TO_YIELD race against the IDLE-deferred TCB cleanup on the SMP preview kernel; behaviour is unchanged on the default IDF kernel and on single-core targets.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -94,14 +94,36 @@ err:
|
||||
* So we suspend the task before deleting it. */
|
||||
vTaskSuspend( xTaskToDelete );
|
||||
|
||||
/* Wait for the task to be suspended */
|
||||
while( eRunning == eTaskGetState( xTaskToDelete ) )
|
||||
/* Wait until the task is no longer the current task on any core.
|
||||
*
|
||||
* Polling on pxCurrentTCBs[] (via xTaskGetCurrentTaskHandleForCore())
|
||||
* matches the predicate vTaskDelete() uses to choose between immediate
|
||||
* and IDLE-deferred TCB cleanup. By waiting on it here, we guarantee
|
||||
* that the vTaskDelete() call below takes the immediate path and that
|
||||
* prvDeleteTCB() runs synchronously before vTaskDelete() returns, so
|
||||
* the heap_caps_free() / vPortFree() that follow cannot race with the
|
||||
* IDLE task. */
|
||||
for( ;; )
|
||||
{
|
||||
BaseType_t xStillOnCore = pdFALSE;
|
||||
|
||||
for( BaseType_t xCoreID = 0; xCoreID < configNUMBER_OF_CORES; xCoreID++ )
|
||||
{
|
||||
if( xTaskGetCurrentTaskHandleForCore( xCoreID ) == xTaskToDelete )
|
||||
{
|
||||
xStillOnCore = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( xStillOnCore == pdFALSE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
configASSERT( eRunning != eTaskGetState( xTaskToDelete ) );
|
||||
|
||||
/* We can delete the task and free the memory buffers.
|
||||
* First, we must call `vTaskDelete` so that the port task delete callback is called.
|
||||
* On targets that have coprocessors, it may be possible that the stack pointer is modified (restored)
|
||||
|
||||
Reference in New Issue
Block a user