From d33041da735cf5678e5625bc9478c8c77d531c1e Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Wed, 16 Oct 2024 09:59:45 +0200 Subject: [PATCH] fix(freertos): Fixed SMP race condition in xStreamBufferSend() This commit fixes a race condition in dual-core SMP mode where in the xStreamBufferSend() makes the xTaskWaitingToSend NULL but it may have already been evaluated to not be NULL by xStreamBufferReceive() running on another core and eventually leading to a crash in tasks.c. --- components/freertos/FreeRTOS-Kernel/idf_changes.md | 2 ++ components/freertos/FreeRTOS-Kernel/stream_buffer.c | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/components/freertos/FreeRTOS-Kernel/idf_changes.md b/components/freertos/FreeRTOS-Kernel/idf_changes.md index 1180ee2f26..94890fb800 100644 --- a/components/freertos/FreeRTOS-Kernel/idf_changes.md +++ b/components/freertos/FreeRTOS-Kernel/idf_changes.md @@ -125,6 +125,8 @@ The following functions were modified to accommodate SMP behavior: - Added extra check to see if current blocking task has already been deleted by the other core. - `xStreamBufferReceive()` - Added a critical section for setting `xTaskWaitingToReceive` to `NULL` so that the write is SMP safe. +- `xStreamBufferSend()` + - Added a critical section for setting `xTaskWaitingToSend` to `NULL` so that the write is SMP safe. ### Critical Section Changes diff --git a/components/freertos/FreeRTOS-Kernel/stream_buffer.c b/components/freertos/FreeRTOS-Kernel/stream_buffer.c index 9982b3caa3..7ce9881a5b 100644 --- a/components/freertos/FreeRTOS-Kernel/stream_buffer.c +++ b/components/freertos/FreeRTOS-Kernel/stream_buffer.c @@ -773,7 +773,18 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); - pxStreamBuffer->xTaskWaitingToSend = NULL; + /* In SMP mode, the task may have been woken and scheduled on + * another core. Hence, we must clear the xTaskWaitingToSend + * handle in a critical section. */ + #if ( configNUMBER_OF_CORES > 1 ) + taskENTER_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); + #endif /* configNUMBER_OF_CORES > 1 */ + { + pxStreamBuffer->xTaskWaitingToSend = NULL; + } + #if ( configNUMBER_OF_CORES > 1 ) + taskEXIT_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); + #endif /* configNUMBER_OF_CORES > 1 */ } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ); } else