mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 13:14:32 +02:00
freertos: Inline vPortCPUAcquireMutex/vPortCPUReleaseMutex into implementations
Further improves performance: No contention -> 134 cycles Recursion -> 117 cycles Contention -> 323 cycles
This commit is contained in:
committed by
Angus Gratton
parent
db58a2732b
commit
5c996a1b29
@@ -199,8 +199,6 @@ void vPortCPUInitializeMutex(portMUX_TYPE *mux);
|
|||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux, const char *function, int line);
|
void vPortCPUAcquireMutex(portMUX_TYPE *mux, const char *function, int line);
|
||||||
portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *function, int line);
|
portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *function, int line);
|
||||||
void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *function, int line);
|
|
||||||
portBASE_TYPE vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *function, int line);
|
|
||||||
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line );
|
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line );
|
||||||
void vTaskExitCritical( portMUX_TYPE *mux, const char *function, int line );
|
void vTaskExitCritical( portMUX_TYPE *mux, const char *function, int line );
|
||||||
#define portENTER_CRITICAL(mux) vTaskEnterCritical(mux, __FUNCTION__, __LINE__)
|
#define portENTER_CRITICAL(mux) vTaskEnterCritical(mux, __FUNCTION__, __LINE__)
|
||||||
@@ -212,8 +210,6 @@ void vTaskExitCritical( portMUX_TYPE *mux );
|
|||||||
void vTaskEnterCritical( portMUX_TYPE *mux );
|
void vTaskEnterCritical( portMUX_TYPE *mux );
|
||||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux);
|
void vPortCPUAcquireMutex(portMUX_TYPE *mux);
|
||||||
void vPortCPUReleaseMutex(portMUX_TYPE *mux);
|
void vPortCPUReleaseMutex(portMUX_TYPE *mux);
|
||||||
void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux);
|
|
||||||
void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux);
|
|
||||||
|
|
||||||
#define portENTER_CRITICAL(mux) vTaskEnterCritical(mux)
|
#define portENTER_CRITICAL(mux) vTaskEnterCritical(mux)
|
||||||
#define portEXIT_CRITICAL(mux) vTaskExitCritical(mux)
|
#define portEXIT_CRITICAL(mux) vTaskExitCritical(mux)
|
||||||
|
@@ -307,6 +307,7 @@ void vPortCPUInitializeMutex(portMUX_TYPE *mux) {
|
|||||||
mux->count=0;
|
mux->count=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "portmux_impl.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.
|
* For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.
|
||||||
@@ -325,72 +326,6 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XOR one core ID with this value to get the other core ID */
|
|
||||||
#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
|
|
||||||
#else
|
|
||||||
void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux) {
|
|
||||||
#endif
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
|
||||||
uint32_t res;
|
|
||||||
portBASE_TYPE coreID, otherCoreID;
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
uint32_t timeout=(1<<16);
|
|
||||||
uint32_t owner = mux->owner;
|
|
||||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
|
||||||
ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
|
|
||||||
mux->owner=portMUX_FREE_VAL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Spin until we own the core */
|
|
||||||
|
|
||||||
RSR(PRID, coreID);
|
|
||||||
/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
|
|
||||||
not the 0/1 value returned by xPortGetCoreID()
|
|
||||||
*/
|
|
||||||
otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
|
|
||||||
do {
|
|
||||||
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
|
|
||||||
CORE_ID_APP:
|
|
||||||
|
|
||||||
- If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
|
|
||||||
- If "our" coreID, we can drop through immediately.
|
|
||||||
- If "otherCoreID", we spin here.
|
|
||||||
*/
|
|
||||||
res = coreID;
|
|
||||||
uxPortCompareSet(&mux->owner, portMUX_FREE_VAL, &res);
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
timeout--;
|
|
||||||
if (timeout == 0) {
|
|
||||||
ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
|
||||||
ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} while (res == otherCoreID);
|
|
||||||
|
|
||||||
assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */
|
|
||||||
assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */
|
|
||||||
assert(mux->count < 0xFF); /* Bad count value implies memory corruption */
|
|
||||||
|
|
||||||
/* now we own it, we can increment the refcount */
|
|
||||||
mux->count++;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
if (res==portMUX_FREE_VAL) { //initial lock
|
|
||||||
mux->lastLockedFn=fnName;
|
|
||||||
mux->lastLockedLine=line;
|
|
||||||
} else {
|
|
||||||
ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1,
|
|
||||||
mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For kernel use: Release a per-CPU mux
|
* For kernel use: Release a per-CPU mux
|
||||||
@@ -411,58 +346,12 @@ void vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
|
|
||||||
#else
|
|
||||||
void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux) {
|
|
||||||
#endif
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
|
||||||
portBASE_TYPE coreID;
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
const char *lastLockedFn=mux->lastLockedFn;
|
|
||||||
int lastLockedLine=mux->lastLockedLine;
|
|
||||||
mux->lastLockedFn=fnName;
|
|
||||||
mux->lastLockedLine=line;
|
|
||||||
uint32_t owner = mux->owner;
|
|
||||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
|
||||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
|
|
||||||
RSR(PRID, coreID);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
if (coreID != mux->owner) {
|
|
||||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
|
|
||||||
ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
|
|
||||||
assert(mux->count > 0); // Indicates memory corruption
|
|
||||||
assert(mux->count < 0x100); // Indicates memory corruption
|
|
||||||
|
|
||||||
mux->count--;
|
|
||||||
if(mux->count == 0) {
|
|
||||||
mux->owner = portMUX_FREE_VAL;
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
|
||||||
else {
|
|
||||||
ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif //!CONFIG_FREERTOS_UNICORE
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||||
void vPortFirstTaskHook(TaskFunction_t function) {
|
void vPortFirstTaskHook(TaskFunction_t function) {
|
||||||
esp_set_breakpoint_if_jtag(function);
|
esp_set_breakpoint_if_jtag(function);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void vPortSetStackWatchpoint( void* pxStackStart ) {
|
void vPortSetStackWatchpoint( void* pxStackStart ) {
|
||||||
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
||||||
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
||||||
|
147
components/freertos/portmux_impl.h
Normal file
147
components/freertos/portmux_impl.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2016-2017 Espressif Shanghai PTE LTD
|
||||||
|
Copyright (C) 2015 Real Time Engineers Ltd.
|
||||||
|
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License (version 2) as published by the
|
||||||
|
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||||
|
|
||||||
|
***************************************************************************
|
||||||
|
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||||
|
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||||
|
>>! obliged to provide the source code for proprietary components !<<
|
||||||
|
>>! outside of the FreeRTOS kernel. !<<
|
||||||
|
***************************************************************************
|
||||||
|
|
||||||
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||||
|
link: http://www.freertos.org/a00114.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This header exists for performance reasons, in order to inline the
|
||||||
|
implementation of vPortCPUAcquireMutexIntsDisabled and
|
||||||
|
vPortCPUReleaseMutexIntsDisabled into the
|
||||||
|
vTaskEnterCritical/vTaskExitCritical functions as well as the
|
||||||
|
vPortCPUAcquireMutex/vPortCPUReleaseMutex implementations.
|
||||||
|
|
||||||
|
Normally this kind of performance hack is over the top, but these
|
||||||
|
functions get used a great deal by FreeRTOS internals.
|
||||||
|
|
||||||
|
It should be #included by freertos port.c or tasks.c, in esp-idf.
|
||||||
|
*/
|
||||||
|
#include "soc/cpu.h"
|
||||||
|
|
||||||
|
/* XOR one core ID with this value to get the other core ID */
|
||||||
|
#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
|
||||||
|
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
static inline void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
|
||||||
|
#else
|
||||||
|
static inline void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux) {
|
||||||
|
#endif
|
||||||
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
|
uint32_t res;
|
||||||
|
portBASE_TYPE coreID, otherCoreID;
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
uint32_t timeout=(1<<16);
|
||||||
|
uint32_t owner = mux->owner;
|
||||||
|
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
||||||
|
ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
|
||||||
|
mux->owner=portMUX_FREE_VAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Spin until we own the core */
|
||||||
|
|
||||||
|
RSR(PRID, coreID);
|
||||||
|
/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
|
||||||
|
not the 0/1 value returned by xPortGetCoreID()
|
||||||
|
*/
|
||||||
|
otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
|
||||||
|
do {
|
||||||
|
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
|
||||||
|
CORE_ID_APP:
|
||||||
|
|
||||||
|
- If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
|
||||||
|
- If "our" coreID, we can drop through immediately.
|
||||||
|
- If "otherCoreID", we spin here.
|
||||||
|
*/
|
||||||
|
res = coreID;
|
||||||
|
uxPortCompareSet(&mux->owner, portMUX_FREE_VAL, &res);
|
||||||
|
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
timeout--;
|
||||||
|
if (timeout == 0) {
|
||||||
|
ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
||||||
|
ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} while (res == otherCoreID);
|
||||||
|
|
||||||
|
assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */
|
||||||
|
assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */
|
||||||
|
assert(mux->count < 0xFF); /* Bad count value implies memory corruption */
|
||||||
|
|
||||||
|
/* now we own it, we can increment the refcount */
|
||||||
|
mux->count++;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
if (res==portMUX_FREE_VAL) { //initial lock
|
||||||
|
mux->lastLockedFn=fnName;
|
||||||
|
mux->lastLockedLine=line;
|
||||||
|
} else {
|
||||||
|
ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1,
|
||||||
|
mux->lastLockedFn, mux->lastLockedLine, fnName, line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
static inline void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
|
||||||
|
#else
|
||||||
|
static inline void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux) {
|
||||||
|
#endif
|
||||||
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
|
portBASE_TYPE coreID;
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
const char *lastLockedFn=mux->lastLockedFn;
|
||||||
|
int lastLockedLine=mux->lastLockedLine;
|
||||||
|
mux->lastLockedFn=fnName;
|
||||||
|
mux->lastLockedLine=line;
|
||||||
|
uint32_t owner = mux->owner;
|
||||||
|
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
||||||
|
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
|
||||||
|
RSR(PRID, coreID);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
if (coreID != mux->owner) {
|
||||||
|
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
|
||||||
|
ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
|
||||||
|
assert(mux->count > 0); // Indicates memory corruption
|
||||||
|
assert(mux->count < 0x100); // Indicates memory corruption
|
||||||
|
|
||||||
|
mux->count--;
|
||||||
|
if(mux->count == 0) {
|
||||||
|
mux->owner = portMUX_FREE_VAL;
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
||||||
|
else {
|
||||||
|
ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif //!CONFIG_FREERTOS_UNICORE
|
||||||
|
}
|
@@ -4103,6 +4103,7 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
|
|||||||
|
|
||||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
|
||||||
|
#include "portmux_impl.h"
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line )
|
void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line )
|
||||||
|
Reference in New Issue
Block a user