mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
* Style: make freertos.org = FreeRTOS.org also add https * Style: Fix freertos into FreeRTOS * Style: Fix freertos into FreeRTOS Co-authored-by: Alfred Gedeon <gedeonag@amazon.com>
201 lines
8.4 KiB
C
201 lines
8.4 KiB
C
/*
|
|
* 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: https://www.FreeRTOS.org/a00114.html
|
|
*/
|
|
|
|
|
|
/*
|
|
* Warning: funky preprocessor hackery ahead. Including these headers will generate two
|
|
* functions, which names are defined by the preprocessor macros
|
|
* PORTMUX_AQUIRE_MUX_FN_NAME and PORTMUX_RELEASE_MUX_FN_NAME. In order to do the compare
|
|
* and exchange function, they will use whatever PORTMUX_COMPARE_SET_FN_NAME resolves to.
|
|
*
|
|
* In some scenarios, this header is included *twice* in portmux_impl.h: one time
|
|
* for the 'normal' mux code which uses a compare&exchange routine, another time
|
|
* to generate code for a second set of these routines that use a second mux
|
|
* (in internal ram) to fake a compare&exchange on a variable in external memory.
|
|
*/
|
|
|
|
|
|
|
|
static inline bool __attribute__( ( always_inline ) )
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
PORTMUX_AQUIRE_MUX_FN_NAME( portMUX_TYPE * mux,
|
|
int timeout_cycles,
|
|
const char * fnName,
|
|
int line )
|
|
{
|
|
#else
|
|
PORTMUX_AQUIRE_MUX_FN_NAME( portMUX_TYPE * mux, int timeout_cycles )
|
|
{
|
|
#endif
|
|
|
|
|
|
#if !CONFIG_FREERTOS_UNICORE
|
|
uint32_t res;
|
|
portBASE_TYPE coreID, otherCoreID;
|
|
uint32_t ccount_start;
|
|
bool set_timeout = timeout_cycles > portMUX_NO_TIMEOUT;
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
if( !set_timeout )
|
|
{
|
|
timeout_cycles = 10000; /* Always set a timeout in debug mode */
|
|
set_timeout = true;
|
|
}
|
|
#endif
|
|
|
|
if( set_timeout ) /* Timeout */
|
|
{
|
|
RSR( CCOUNT, ccount_start );
|
|
}
|
|
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
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;
|
|
PORTMUX_COMPARE_SET_FN_NAME( &mux->owner, portMUX_FREE_VAL, &res );
|
|
|
|
if( res != otherCoreID )
|
|
{
|
|
break; /* mux->owner is "our" coreID */
|
|
}
|
|
|
|
if( set_timeout )
|
|
{
|
|
uint32_t ccount_now;
|
|
RSR( CCOUNT, ccount_now );
|
|
|
|
if( ccount_now - ccount_start > ( unsigned ) timeout_cycles )
|
|
{
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
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
|
|
return false;
|
|
}
|
|
}
|
|
} while( 1 );
|
|
|
|
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 /* CONFIG_FREERTOS_PORTMUX_DEBUG */
|
|
#endif /* CONFIG_FREERTOS_UNICORE */
|
|
return true;
|
|
}
|
|
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
static inline void PORTMUX_RELEASE_MUX_FN_NAME( portMUX_TYPE * mux,
|
|
const char * fnName,
|
|
int line )
|
|
{
|
|
#else
|
|
static inline void PORTMUX_RELEASE_MUX_FN_NAME( 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 /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
|
|
|
|
#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 */
|
|
|
|
mux->count--;
|
|
|
|
if( mux->count == 0 )
|
|
{
|
|
mux->owner = portMUX_FREE_VAL;
|
|
}
|
|
else
|
|
{
|
|
assert( mux->count < 0x100 ); /* Indicates memory corruption */
|
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
|
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
|
|
}
|