feat(freertos): make FREERTOS_PORT_THREAD_SAFE_CLAIM optinal

This commit is contained in:
wuzhenghui
2026-06-22 10:15:32 +08:00
parent 2d95d621b7
commit 3a18ec3b7f
12 changed files with 89 additions and 3 deletions
@@ -327,6 +327,7 @@ and vPortExitCritical() from precompiled libraries (.a) thereby failing linking.
void vPortEnterCritical(void);
void vPortExitCritical(void);
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
/**
* @brief Claim thread-safe region start
* If claimed, vPortEnterCritical/vPortExitCritical on the current core are no-ops.
@@ -344,6 +345,7 @@ void xPortThreadSafeClaim(void);
void xPortThreadSafeDisclaim(void);
extern volatile bool port_xThreadSafeClaimed;
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
//IDF task critical sections
#define portTRY_ENTER_CRITICAL(lock, timeout) ({(void) lock; (void) timeout; vPortEnterCritical(); pdPASS;})
@@ -77,7 +77,9 @@ StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOIN
// Variables used for IDF style critical sections. These are orthogonal to FreeRTOS critical sections
static UBaseType_t port_uxCriticalNestingIDF = 0;
static UBaseType_t port_uxCriticalOldInterruptStateIDF = 0;
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
volatile bool port_xThreadSafeClaimed = false;
#endif
/* ------------------------------------------------ IDF Compatibility --------------------------------------------------
* - These need to be defined for IDF to compile
@@ -85,6 +87,7 @@ volatile bool port_xThreadSafeClaimed = false;
// ------------------ Critical Sections --------------------
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
void xPortThreadSafeClaim(void)
{
configASSERT(!xPortCanYield());
@@ -98,12 +101,15 @@ void xPortThreadSafeDisclaim(void)
configASSERT(port_xThreadSafeClaimed);
port_xThreadSafeClaimed = false;
}
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
void vPortEnterCritical(void)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
// Save current interrupt threshold and disable interrupts
UBaseType_t old_thresh = ulPortSetInterruptMask();
// Update the IDF critical nesting count
@@ -116,9 +122,11 @@ void vPortEnterCritical(void)
void vPortExitCritical(void)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
/* Critical section nesting coung must never be negative */
configASSERT( port_uxCriticalNestingIDF > 0 );
@@ -316,7 +324,9 @@ BaseType_t xPortStartScheduler(void)
{
uxInterruptNesting = 0;
port_uxCriticalNestingIDF = 0;
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
port_xThreadSafeClaimed = false;
#endif
uxSchedulerRunning = 0;
#if configNUM_CORES > 1
port_uxCoreStartupDone[xPortGetCoreID()] = 0;
@@ -321,6 +321,7 @@ static inline void __attribute__((always_inline)) vPortCPUReleaseMutex(portMUX_T
// ------------------ Critical Sections --------------------
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
/**
* @brief Claim thread-safe region start
* If claimed, vPortEnterCritical/vPortExitCritical on the current core are no-ops.
@@ -338,6 +339,7 @@ void xPortThreadSafeClaim(void);
void xPortThreadSafeDisclaim(void);
extern volatile bool port_xThreadSafeClaimed;
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *lock, BaseType_t timeout);
@@ -104,7 +104,9 @@ Variables used by IDF critical sections only (SMP tracks critical nesting inside
*/
BaseType_t port_uxCriticalNestingIDF[portNUM_PROCESSORS] = {0};
BaseType_t port_uxCriticalOldInterruptStateIDF[portNUM_PROCESSORS] = {0};
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
volatile bool port_xThreadSafeClaimed = false;
#endif
/*
*******************************************************************************
@@ -116,6 +118,7 @@ volatile StackType_t DRAM_ATTR __attribute__((aligned(16))) port_IntStack[portNU
/* One flag for each individual CPU. */
volatile uint32_t port_switch_flag[portNUM_PROCESSORS];
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
void xPortThreadSafeClaim(void)
{
configASSERT(!xPortCanYield());
@@ -129,12 +132,15 @@ void xPortThreadSafeDisclaim(void)
configASSERT(port_xThreadSafeClaimed);
port_xThreadSafeClaimed = false;
}
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *lock, BaseType_t timeout)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return pdPASS;
}
#endif
/* Interrupts may already be disabled (if this function is called in nested
* manner). However, there's no atomic operation that will allow us to check,
* thus we have to disable interrupts again anyways.
@@ -163,9 +169,11 @@ BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *lock, BaseType_t timeout)
void vPortExitCriticalIDF(portMUX_TYPE *lock)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
/* This function may be called in a nested manner. Therefore, we only need
* to re-enable interrupts if this is the last call to exit the critical. We
* can use the nesting count to determine whether this is the last exit call.
@@ -361,7 +369,9 @@ BaseType_t xPortStartScheduler( void )
BaseType_t coreID = xPortGetCoreID();
port_xSchedulerRunning[coreID] = 1;
port_uxCoreStartupDone[coreID] = 0;
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
port_xThreadSafeClaimed = false;
#endif
#if configNUM_CORES > 1
// Workaround for non-thread safe multi-core OS startup (see IDF-4524)
@@ -44,6 +44,9 @@
#include "task.h"
#include "timers.h"
#include "stack_macros.h"
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
#include "esp_compiler.h"
#endif
/* The default definitions are only available for non-MPU ports. The
* reason is that the stack alignment requirements vary for different
@@ -6968,10 +6971,12 @@ static void prvResetNextTaskUnblockTime( void )
void vTaskEnterCritical( void )
{
if( port_xThreadSafeClaimed )
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if( unlikely( port_xThreadSafeClaimed ) )
{
return;
}
#endif
traceENTER_vTaskEnterCritical();
@@ -7100,10 +7105,12 @@ static void prvResetNextTaskUnblockTime( void )
void vTaskExitCritical( void )
{
if( port_xThreadSafeClaimed )
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if( unlikely( port_xThreadSafeClaimed ) )
{
return;
}
#endif
traceENTER_vTaskExitCritical();
@@ -230,6 +230,7 @@ void vPortEnterCritical(void);
*/
void vPortExitCritical(void);
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
/**
* @brief Claim thread-safe region start
* If claimed, vPortEnterCritical/vPortExitCritical on the current core are no-ops.
@@ -245,6 +246,7 @@ void xPortThreadSafeClaim(void);
* @note !!! Caller must guarantee thread safety between Claim and Disclaim !!!
*/
void xPortThreadSafeDisclaim(void);
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
#if (configNUM_CORES > 1)
/**
@@ -99,7 +99,9 @@ _Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK
volatile UBaseType_t port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis
volatile UBaseType_t port_uxInterruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c
volatile UBaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0};
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
volatile bool port_xThreadSafeClaimed = false;
#endif
volatile UBaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0};
volatile UBaseType_t xPortSwitchFlag[portNUM_PROCESSORS] = {0};
volatile UBaseType_t port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence
@@ -159,7 +161,9 @@ BaseType_t xPortStartScheduler(void)
BaseType_t coreID = xPortGetCoreID();
port_uxInterruptNesting[coreID] = 0;
port_uxCriticalNesting[coreID] = 0;
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
port_xThreadSafeClaimed = false;
#endif
port_xSchedulerRunning[coreID] = 0;
port_uxCoreStartupDone[coreID] = 0;
@@ -529,9 +533,11 @@ void vPortClearInterruptMaskFromISR(UBaseType_t prev_int_level)
#if (configNUM_CORES > 1)
BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TYPE *mux, BaseType_t timeout)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return pdPASS;
}
#endif
/* Interrupts may already be disabled (if this function is called in nested
* manner). However, there's no atomic operation that will allow us to check,
* thus we have to disable interrupts again anyways.
@@ -559,9 +565,11 @@ BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TY
void __attribute__((optimize("-O3"))) vPortExitCriticalMultiCore(portMUX_TYPE *mux)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
/* This function may be called in a nested manner. Therefore, we only need
* to re-enable interrupts if this is the last call to exit the critical. We
* can use the nesting count to determine whether this is the last exit call.
@@ -609,6 +617,7 @@ void vPortExitCriticalCompliance(portMUX_TYPE *mux)
}
#endif /* (configNUM_CORES > 1) */
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
void xPortThreadSafeClaim(void)
{
configASSERT(!xPortCanYield());
@@ -622,6 +631,7 @@ void xPortThreadSafeDisclaim(void)
configASSERT(port_xThreadSafeClaimed);
port_xThreadSafeClaimed = false;
}
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
void vPortEnterCritical(void)
{
@@ -629,9 +639,11 @@ void vPortEnterCritical(void)
esp_rom_printf("vPortEnterCritical(void) is not supported on multi-core targets. Please use vPortEnterCriticalMultiCore(portMUX_TYPE *mux) instead.\n");
abort();
#endif /* (configNUM_CORES > 1) */
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR();
port_uxCriticalNesting[0]++;
@@ -646,9 +658,11 @@ void vPortExitCritical(void)
esp_rom_printf("vPortExitCritical(void) is not supported on multi-core targets. Please use vPortExitCriticalMultiCore(portMUX_TYPE *mux) instead.\n");
abort();
#endif /* (configNUM_CORES > 1) */
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
/* Critical section nesting count must never be negative */
configASSERT( port_uxCriticalNesting[0] > 0 );
@@ -229,6 +229,7 @@ static inline void __attribute__((always_inline)) vPortEnterCritical(portMUX_TYP
*/
void vPortExitCritical(portMUX_TYPE *mux);
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
/**
* @brief Claim thread-safe region start
* If claimed, vPortEnterCritical/vPortExitCritical on the current core are no-ops.
@@ -244,6 +245,7 @@ void xPortThreadSafeClaim(void);
* @note !!! Caller must guarantee thread safety between Claim and Disclaim !!!
*/
void xPortThreadSafeDisclaim(void);
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
/**
* @brief FreeRTOS Compliant version of xPortEnterCriticalTimeout()
@@ -77,7 +77,9 @@ const DRAM_ATTR uint32_t offset_xCoreID = offsetof(StaticTask_t, xDummyCoreID);
volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis
unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0};
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
volatile bool port_xThreadSafeClaimed = false;
#endif
BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0};
volatile unsigned port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence
@@ -482,6 +484,7 @@ BaseType_t xPortInterruptedFromISRContext(void)
// ------------------ Critical Sections --------------------
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
void xPortThreadSafeClaim(void)
{
configASSERT(!xPortCanYield());
@@ -495,12 +498,15 @@ void xPortThreadSafeDisclaim(void)
configASSERT(port_xThreadSafeClaimed);
port_xThreadSafeClaimed = false;
}
#endif /* CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM */
BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TYPE *mux, BaseType_t timeout)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return pdPASS;
}
#endif
/* Interrupts may already be disabled (if this function is called in nested
* manner). However, there's no atomic operation that will allow us to check,
* thus we have to disable interrupts again anyways.
@@ -528,9 +534,11 @@ BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TY
void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux)
{
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
if (unlikely(port_xThreadSafeClaimed)) {
return;
}
#endif
/* This function may be called in a nested manner. Therefore, we only need
* to re-enable interrupts if this is the last call to exit the critical. We
* can use the nesting count to determine whether this is the last exit call.
+15
View File
@@ -566,6 +566,21 @@ menu "FreeRTOS"
If enabled, context of port*_CRITICAL calls (ISR or Non-ISR) would be checked to be in compliance with
Vanilla FreeRTOS. e.g Calling port*_CRITICAL from ISR context would cause assert failure
config FREERTOS_PORT_THREAD_SAFE_CLAIM
bool "Enable xPortThreadSafeClaim/xPortThreadSafeDisclaim APIs"
default y if SOC_BRANCH_PREDICTOR_SUPPORTED
default n
help
Enables the xPortThreadSafeClaim() and xPortThreadSafeDisclaim() APIs, which allow a caller to
declare that it has already ensured thread safety (e.g. by disabling interrupts and stalling all
other cores), causing subsequent vPortEnterCritical/vPortExitCritical calls to become no-ops for
the duration of the claim.
This feature adds a branch check to every port-layer critical-section enter/exit path. On chips
with a hardware branch predictor (SOC_BRANCH_PREDICTOR_SUPPORTED) the branch is predicted-not-taken
and has negligible overhead. On older chips without a branch predictor the branch has a measurable
per-critical-section cost, so this option defaults to disabled.
endmenu # Port
menu "Extra"
@@ -4,8 +4,14 @@
*/
#pragma once
#include "sdkconfig.h"
#ifndef IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP 230
#if CONFIG_FREERTOS_PORT_THREAD_SAFE_CLAIM
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP 230
#else
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP 215
#endif
#endif
#ifndef IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP_PSRAM
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP_PSRAM 300