mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-03 03:31:41 +03:00
feat(freertos): make FREERTOS_PORT_THREAD_SAFE_CLAIM optinal
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user