feat(granular_locks): Add granular locking functions

- Updated prvCheckForRunStateChange() for granular locks
- Updated vTaskSuspendAll() and xTaskResumeAll()
    - Now holds the xTaskSpinlock during kernel suspension
    - Increments/decrements xPreemptionDisable. Only yields when 0, thus allowing
    for nested suspensions across different data groups

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
This commit is contained in:
Darian Leung 2024-06-16 00:48:25 +08:00 committed by Sudeep Mohanty
parent 6c5458c5f3
commit 8ceb94dadf
3 changed files with 241 additions and 154 deletions

View file

@ -461,7 +461,7 @@
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) || ( configNUMBER_OF_CORES == 1 ) )
#define portRELEASE_TASK_LOCK( xCoreID )
#else
#error portRELEASE_TASK_LOCK is required in SMP
#error portRELEASE_TASK_LOCK is required in SMP without granular locking feature enabled
#endif
#endif /* portRELEASE_TASK_LOCK */
@ -471,7 +471,7 @@
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) || ( configNUMBER_OF_CORES == 1 ) )
#define portGET_TASK_LOCK( xCoreID )
#else
#error portGET_TASK_LOCK is required in SMP
#error portGET_TASK_LOCK is required in SMP without granular locking feature enabled
#endif
#endif /* portGET_TASK_LOCK */
@ -481,7 +481,7 @@
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) || ( configNUMBER_OF_CORES == 1 ) )
#define portRELEASE_ISR_LOCK( xCoreID )
#else
#error portRELEASE_ISR_LOCK is required in SMP
#error portRELEASE_ISR_LOCK is required in SMP without granular locking feature enabled
#endif
#endif /* portRELEASE_ISR_LOCK */
@ -491,7 +491,7 @@
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) || ( configNUMBER_OF_CORES == 1 ) )
#define portGET_ISR_LOCK( xCoreID )
#else
#error portGET_ISR_LOCK is required in SMP
#error portGET_ISR_LOCK is required in SMP without granular locking feature enabled
#endif
#endif /* portGET_ISR_LOCK */
@ -499,7 +499,7 @@
#ifndef portRELEASE_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portRELEASE_SPINLOCK is required for granular locking
#error portRELEASE_SPINLOCK is required for SMP with granular locking feature enabled
#endif
#endif
@ -507,7 +507,7 @@
#ifndef portGET_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portGET_SPINLOCK is required for granular locking
#error portGET_SPINLOCK is required for SMP with granular locking feature enabled
#endif
#endif
@ -536,38 +536,6 @@
#endif
#ifndef portENTER_CRITICAL_DATA_GROUP
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portENTER_CRITICAL_DATA_GROUP is required for SMP with granular locking feature enabled
#endif
#endif
#ifndef portEXIT_CRITICAL_DATA_GROUP
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portEXIT_CRITICAL_DATA_GROUP is required for SMP with granular locking feature enabled
#endif
#endif
#ifndef portENTER_CRITICAL_DATA_GROUP_FROM_ISR
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portENTER_CRITICAL_DATA_GROUP_FROM_ISR is required for SMP with granular locking feature enabled
#endif
#endif
#ifndef portEXIT_CRITICAL_DATA_GROUP_FROM_ISR
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portEXIT_CRITICAL_DATA_GROUP_FROM_ISR is required for SMP with granular locking feature enabled
#endif
#endif
#ifndef portSPINLOCK_TYPE
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
@ -576,82 +544,18 @@
#endif
#ifndef portINIT_EVENT_GROUP_TASK_SPINLOCK
#ifndef portINIT_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_EVENT_GROUP_TASK_SPINLOCK is required for granular locking
#error portINIT_SPINLOCK is required for SMP with granular locking feature enabled
#endif
#endif
#ifndef portINIT_EVENT_GROUP_ISR_SPINLOCK
#ifndef portINIT_SPINLOCK_STATIC
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_EVENT_GROUP_ISR_SPINLOCK is required for granular locking
#endif
#endif
#ifndef portINIT_QUEUE_TASK_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_QUEUE_TASK_SPINLOCK is required for granular locking
#endif
#endif
#ifndef portINIT_QUEUE_ISR_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_QUEUE_ISR_SPINLOCK is required for granular locking
#endif
#endif
#ifndef portINIT_STREAM_BUFFER_TASK_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_STREAM_BUFFER_TASK_SPINLOCK is required for granular locking
#endif
#endif
#ifndef portINIT_STREAM_BUFFER_ISR_SPINLOCK
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_STREAM_BUFFER_ISR_SPINLOCK is required for granular locking
#endif
#endif
#ifndef portINIT_KERNEL_TASK_SPINLOCK_STATIC
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_KERNEL_TASK_SPINLOCK_STATIC is required for granular locking
#endif
#endif
#ifndef portINIT_KERNEL_ISR_SPINLOCK_STATIC
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_KERNEL_ISR_SPINLOCK_STATIC is required for granular locking
#endif
#endif
#ifndef portINIT_TIMERS_TASK_SPINLOCK_STATIC
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_TIMERS_TASK_SPINLOCK_STATIC is required for granular locking
#endif
#endif
#ifndef portINIT_TIMERS_ISR_SPINLOCK_STATIC
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#error portINIT_TIMERS_ISR_SPINLOCK_STATIC is required for granular locking
#error portINIT_SPINLOCK_STATIC is required for SMP with granular locking feature enabled
#endif
#endif
@ -3072,7 +2976,7 @@
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) )
#else
#else /* if ( portTICK_TYPE_IS_ATOMIC == 0 ) */
/* The tick type can be read atomically, so critical sections used when the
* tick count is returned can be defined away. */

View file

@ -213,7 +213,7 @@ typedef enum
* \defgroup taskYIELD taskYIELD
* \ingroup SchedulerControl
*/
#define taskYIELD() portYIELD()
#define taskYIELD() portYIELD()
/**
* task. h
@ -227,12 +227,19 @@ typedef enum
* \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
* \ingroup SchedulerControl
*/
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#if ( configNUMBER_OF_CORES == 1 )
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#else
#define taskENTER_CRITICAL_FROM_ISR() portENTER_CRITICAL_FROM_ISR()
#define taskENTER_CRITICAL_FROM_ISR() portENTER_CRITICAL_FROM_ISR()
#endif
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#define taskLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) portLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) pxTaskSpinlock, ( portSPINLOCK_TYPE * ) pxISRSpinlock )
#define taskLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock ) portLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock )
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define taskLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) taskENTER_CRITICAL()
#define taskLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock ) taskENTER_CRITICAL_FROM_ISR()
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
/**
* task. h
@ -246,12 +253,19 @@ typedef enum
* \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
* \ingroup SchedulerControl
*/
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#if ( configNUMBER_OF_CORES == 1 )
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#else
#define taskEXIT_CRITICAL_FROM_ISR( x ) portEXIT_CRITICAL_FROM_ISR( x )
#define taskEXIT_CRITICAL_FROM_ISR( x ) portEXIT_CRITICAL_FROM_ISR( x )
#endif
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#define taskUNLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) portUNLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) pxTaskSpinlock, ( portSPINLOCK_TYPE * ) pxISRSpinlock )
#define taskUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock ) portUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock )
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define taskUNLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) taskEXIT_CRITICAL()
#define taskUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock ) taskEXIT_CRITICAL_FROM_ISR( x )
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
/**
* task. h
@ -283,6 +297,110 @@ typedef enum
/* Checks if core ID is valid. */
#define taskVALID_CORE_ID( xCoreID ) ( ( ( ( ( BaseType_t ) 0 <= ( xCoreID ) ) && ( ( xCoreID ) < ( BaseType_t ) configNUMBER_OF_CORES ) ) ) ? ( pdTRUE ) : ( pdFALSE ) )
/**
* task. h
*
* Macro to enter a data group critical section.
*
* \defgroup taskDATA_GROUP_ENTER_CRITICAL taskDATA_GROUP_ENTER_CRITICAL
* \ingroup GranularLocks
*/
#if ( portUSING_GRANULAR_LOCKS == 1 )
#define taskDATA_GROUP_ENTER_CRITICAL( pxTaskSpinlock, pxISRSpinlock ) \
do { \
/* Disable preemption to avoid task state changes during the critical section. */ \
vTaskPreemptionDisable( NULL ); \
{ \
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
/* Task spinlock is always taken first */ \
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxTaskSpinlock ); \
/* Disable interrupts */ \
portDISABLE_INTERRUPTS(); \
/* Take the ISR spinlock next */ \
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxISRSpinlock ); \
/* Increment the critical nesting count */ \
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
} \
} while( 0 )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
/**
* task. h
*
* Macro to enter a data group critical section from an interrupt.
*
* \defgroup taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR
* \ingroup GranularLocks
*/
#if ( portUSING_GRANULAR_LOCKS == 1 )
#define taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR( pxISRSpinlock, puxSavedInterruptStatus ) \
do { \
*( puxSavedInterruptStatus ) = portSET_INTERRUPT_MASK_FROM_ISR(); \
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
/* Take the ISR spinlock */ \
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxISRSpinlock ); \
/* Increment the critical nesting count */ \
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
} while( 0 )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
/**
* task. h
*
* Macro to exit a data group critical section.
*
* \defgroup taskDATA_GROUP_EXIT_CRITICAL taskDATA_GROUP_EXIT_CRITICAL
* \ingroup GranularLocks
*/
#if ( portUSING_GRANULAR_LOCKS == 1 )
#define taskDATA_GROUP_EXIT_CRITICAL( pxTaskSpinlock, pxISRSpinlock ) \
do { \
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) > 0U ); \
/* Release the ISR spinlock */ \
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxISRSpinlock ); \
/* Release the task spinlock */ \
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxTaskSpinlock ); \
/* Decrement the critical nesting count */ \
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
/* Enable interrupts only if the critical nesting count is 0 */ \
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) \
{ \
portENABLE_INTERRUPTS(); \
} \
else \
{ \
mtCOVERAGE_TEST_MARKER(); \
} \
/* Re-enable preemption */ \
vTaskPreemptionEnable( NULL ); \
} while( 0 )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
/**
* task. h
*
* Macro to exit a data group critical section from an interrupt.
*
* \defgroup taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR
* \ingroup GranularLocks
*/
#if ( portUSING_GRANULAR_LOCKS == 1 )
#define taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxISRSpinlock ) \
do { \
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) > 0U ); \
/* Decrement the critical nesting count */ \
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
/* Release the ISR spinlock */ \
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) pxISRSpinlock ); \
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) \
{ \
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
} \
} while( 0 )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
/*-----------------------------------------------------------
* TASK CREATION API
*----------------------------------------------------------*/
@ -3719,7 +3837,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
* It should be used in the implementation of portENTER_CRITICAL if port is running a
* multiple core FreeRTOS.
*/
#if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) || ( configNUMBER_OF_CORES > 1 ) )
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
void vTaskEnterCritical( void );
#endif
@ -3731,7 +3849,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
* It should be used in the implementation of portEXIT_CRITICAL if port is running a
* multiple core FreeRTOS.
*/
#if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) || ( configNUMBER_OF_CORES > 1 ) )
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
void vTaskExitCritical( void );
#endif
@ -3741,7 +3859,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
* should be used in the implementation of portENTER_CRITICAL_FROM_ISR if port is
* running a multiple core FreeRTOS.
*/
#if ( configNUMBER_OF_CORES > 1 )
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
UBaseType_t vTaskEnterCriticalFromISR( void );
#endif
@ -3751,10 +3869,18 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
* should be used in the implementation of portEXIT_CRITICAL_FROM_ISR if port is
* running a multiple core FreeRTOS.
*/
#if ( configNUMBER_OF_CORES > 1 )
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
#endif
/*
* Checks whether a yield is required after taskUNLOCK_DATA_GROUP() returns.
* To be called while data group is locked.
*/
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
BaseType_t xTaskUnlockCanYield( void );
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#if ( portUSING_MPU_WRAPPERS == 1 )
/*