mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-10-09 23:53:04 -04:00
feat(freertos/smp): Add support for TCB locks
This commit is contained in:
parent
9c9487d8c3
commit
c015a48b66
6 changed files with 1255 additions and 464 deletions
|
|
@ -81,6 +81,34 @@
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros used to lock and unlock an event group. When a task locks an,
|
||||||
|
* event group, the task will have thread safe non-deterministic access to
|
||||||
|
* the event group.
|
||||||
|
* - Concurrent access from other tasks will be blocked by the xTaskSpinlock
|
||||||
|
* - Concurrent access from ISRs will be pended
|
||||||
|
*
|
||||||
|
* When the task unlocks the event group, all pended access attempts are handled.
|
||||||
|
*/
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
#define event_groupsLOCK( pxEventBits ) taskDATA_GROUP_LOCK( &( ( pxEventBits )->xTaskSpinlock ) )
|
||||||
|
#define event_groupsUNLOCK( pxEventBits ) taskDATA_GROUP_UNLOCK( &( ( pxEventBits )->xTaskSpinlock ) )
|
||||||
|
#define event_groupsUNLOCK_WITH_YIELD_STATUS( pxEventBits, pxAlreadyYielded ) \
|
||||||
|
do { \
|
||||||
|
*( pxAlreadyYielded ) = taskDATA_GROUP_UNLOCK( &( ( pxEventBits )->xTaskSpinlock ) ); \
|
||||||
|
} while( 0 )
|
||||||
|
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
#define event_groupsLOCK( pxEventBits ) vTaskSuspendAll()
|
||||||
|
#define event_groupsUNLOCK( pxEventBits ) xTaskResumeAll()
|
||||||
|
#define event_groupsUNLOCK_WITH_YIELD_STATUS( pxEventBits, pxAlreadyYielded ) \
|
||||||
|
do { \
|
||||||
|
*( pxAlreadyYielded ) = xTaskResumeAll(); \
|
||||||
|
} while( 0 )
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer )
|
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer )
|
||||||
|
|
@ -245,7 +273,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xAlreadyYielded = xTaskResumeAll();
|
event_groupsUNLOCK_WITH_YIELD_STATUS( pxEventBits, &xAlreadyYielded );
|
||||||
|
|
||||||
if( xTicksToWait != ( TickType_t ) 0 )
|
if( xTicksToWait != ( TickType_t ) 0 )
|
||||||
{
|
{
|
||||||
|
|
@ -401,7 +429,7 @@
|
||||||
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
|
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xAlreadyYielded = xTaskResumeAll();
|
event_groupsUNLOCK_WITH_YIELD_STATUS( pxEventBits, &xAlreadyYielded );
|
||||||
|
|
||||||
if( xTicksToWait != ( TickType_t ) 0 )
|
if( xTicksToWait != ( TickType_t ) 0 )
|
||||||
{
|
{
|
||||||
|
|
@ -568,6 +596,13 @@
|
||||||
{
|
{
|
||||||
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
|
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
|
||||||
|
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
|
||||||
|
/* We are about to access the kernel data group non-deterministically,
|
||||||
|
* thus we suspend the kernel data group.*/
|
||||||
|
vTaskSuspendAll();
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
|
||||||
pxListItem = listGET_HEAD_ENTRY( pxList );
|
pxListItem = listGET_HEAD_ENTRY( pxList );
|
||||||
|
|
||||||
/* Set the bits. */
|
/* Set the bits. */
|
||||||
|
|
@ -638,8 +673,12 @@
|
||||||
|
|
||||||
/* Snapshot resulting bits. */
|
/* Snapshot resulting bits. */
|
||||||
uxReturnBits = pxEventBits->uxEventBits;
|
uxReturnBits = pxEventBits->uxEventBits;
|
||||||
}
|
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
( void ) xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
}
|
||||||
|
event_groupsUNLOCK( pxEventBits );
|
||||||
|
|
||||||
traceRETURN_xEventGroupSetBits( uxReturnBits );
|
traceRETURN_xEventGroupSetBits( uxReturnBits );
|
||||||
|
|
||||||
|
|
@ -662,6 +701,13 @@
|
||||||
{
|
{
|
||||||
traceEVENT_GROUP_DELETE( xEventGroup );
|
traceEVENT_GROUP_DELETE( xEventGroup );
|
||||||
|
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
|
||||||
|
/* We are about to access the kernel data group non-deterministically,
|
||||||
|
* thus we suspend the kernel data group.*/
|
||||||
|
vTaskSuspendAll();
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
|
||||||
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
/* Unblock the task, returning 0 as the event list is being deleted
|
/* Unblock the task, returning 0 as the event list is being deleted
|
||||||
|
|
@ -669,8 +715,12 @@
|
||||||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||||
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
( void ) xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
}
|
||||||
|
event_groupsUNLOCK( pxEventBits );
|
||||||
|
|
||||||
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2950,10 +2950,6 @@
|
||||||
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ( ( configRUN_MULTIPLE_PRIORITIES == 0 ) && ( configUSE_TASK_PREEMPTION_DISABLE != 0 ) )
|
|
||||||
#error configRUN_MULTIPLE_PRIORITIES must be set to 1 to use task preemption disable
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( ( configUSE_PREEMPTION == 0 ) && ( configUSE_TASK_PREEMPTION_DISABLE != 0 ) )
|
#if ( ( configUSE_PREEMPTION == 0 ) && ( configUSE_TASK_PREEMPTION_DISABLE != 0 ) )
|
||||||
#error configUSE_PREEMPTION must be set to 1 to use task preemption disable
|
#error configUSE_PREEMPTION must be set to 1 to use task preemption disable
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3259,6 +3255,9 @@ typedef struct xSTATIC_TCB
|
||||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||||
BaseType_t xDummy26;
|
BaseType_t xDummy26;
|
||||||
#endif
|
#endif
|
||||||
|
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||||
|
portSPINLOCK_TYPE xDummy27;
|
||||||
|
#endif
|
||||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||||
void * pxDummy8;
|
void * pxDummy8;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
335
include/task.h
335
include/task.h
|
|
@ -294,148 +294,6 @@ typedef enum
|
||||||
/* Checks if core ID is valid. */
|
/* Checks if core ID is valid. */
|
||||||
#define taskVALID_CORE_ID( xCoreID ) ( ( ( ( ( BaseType_t ) 0 <= ( xCoreID ) ) && ( ( xCoreID ) < ( BaseType_t ) configNUMBER_OF_CORES ) ) ) ? ( pdTRUE ) : ( pdFALSE ) )
|
#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 */ \
|
|
||||||
prvTaskPreemptionEnable( 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. h
|
|
||||||
*
|
|
||||||
* Macros to lock a data group (task-level lock only).
|
|
||||||
*
|
|
||||||
* \defgroup taskDATA_GROUP_LOCK taskDATA_GROUP_LOCK
|
|
||||||
* \ingroup GranularLocks
|
|
||||||
*/
|
|
||||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
|
||||||
#define taskDATA_GROUP_LOCK( pxTaskSpinlock ) \
|
|
||||||
do { \
|
|
||||||
/* Disable preemption while holding the task spinlock. */ \
|
|
||||||
vTaskPreemptionDisable( NULL ); \
|
|
||||||
{ \
|
|
||||||
portGET_SPINLOCK( portGET_CORE_ID(), ( portSPINLOCK_TYPE * ) ( pxTaskSpinlock ) ); \
|
|
||||||
} \
|
|
||||||
} while( 0 )
|
|
||||||
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* task. h
|
|
||||||
*
|
|
||||||
* Macros to unlock a data group (task-level lock only).
|
|
||||||
*
|
|
||||||
* \defgroup taskDATA_GROUP_UNLOCK taskDATA_GROUP_UNLOCK
|
|
||||||
* \ingroup GranularLocks
|
|
||||||
*/
|
|
||||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
|
||||||
#define taskDATA_GROUP_UNLOCK( pxTaskSpinlock ) \
|
|
||||||
( { \
|
|
||||||
portRELEASE_SPINLOCK( portGET_CORE_ID(), ( portSPINLOCK_TYPE * ) ( pxTaskSpinlock ) ); \
|
|
||||||
/* Re-enable preemption after releasing the task spinlock. */ \
|
|
||||||
prvTaskPreemptionEnable( NULL ); \
|
|
||||||
} )
|
|
||||||
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* TASK CREATION API
|
* TASK CREATION API
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
|
@ -1712,7 +1570,7 @@ BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
|
||||||
* switch, otherwise pdFALSE. This is used by the scheduler to determine if a
|
* switch, otherwise pdFALSE. This is used by the scheduler to determine if a
|
||||||
* context switch may be required following the enable.
|
* context switch may be required following the enable.
|
||||||
*/
|
*/
|
||||||
BaseType_t prvTaskPreemptionEnable( const TaskHandle_t xTask );
|
BaseType_t xTaskPreemptionEnableWithYieldStatus( const TaskHandle_t xTask );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
|
|
@ -3742,6 +3600,173 @@ void vTaskResetState( void ) PRIVILEGED_FUNCTION;
|
||||||
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
|
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 )
|
||||||
|
|
||||||
|
/* Using a function implementation now since the data group entering critical
|
||||||
|
* section needs to check for run state change. */
|
||||||
|
void vTaskDataGroupEnterCritical( portSPINLOCK_TYPE * pxTaskSpinlock,
|
||||||
|
portSPINLOCK_TYPE * pxISRSpinlock );
|
||||||
|
#define taskDATA_GROUP_ENTER_CRITICAL vTaskDataGroupEnterCritical
|
||||||
|
#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 */ \
|
||||||
|
( void ) xTaskPreemptionEnableWithYieldStatus( 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. h
|
||||||
|
*
|
||||||
|
* Macros to lock a data group (task-level lock only).
|
||||||
|
*
|
||||||
|
* \defgroup taskDATA_GROUP_LOCK taskDATA_GROUP_LOCK
|
||||||
|
* \ingroup GranularLocks
|
||||||
|
*/
|
||||||
|
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||||
|
#define taskDATA_GROUP_LOCK( pxTaskSpinlock ) \
|
||||||
|
do { \
|
||||||
|
/* Disable preemption while holding the task spinlock. */ \
|
||||||
|
vTaskPreemptionDisable( NULL ); \
|
||||||
|
{ \
|
||||||
|
portGET_SPINLOCK( portGET_CORE_ID(), ( portSPINLOCK_TYPE * ) ( pxTaskSpinlock ) ); \
|
||||||
|
} \
|
||||||
|
} while( 0 )
|
||||||
|
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* task. h
|
||||||
|
*
|
||||||
|
* Macros to unlock a data group (task-level lock only).
|
||||||
|
*
|
||||||
|
* \defgroup taskDATA_GROUP_UNLOCK taskDATA_GROUP_UNLOCK
|
||||||
|
* \ingroup GranularLocks
|
||||||
|
*/
|
||||||
|
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||||
|
|
||||||
|
/* Release the task spinlock and re-enable preemption.
|
||||||
|
* Returns the yield status reported by xTaskPreemptionEnableWithYieldStatus(). */
|
||||||
|
BaseType_t taskDataGroupUnlock( portSPINLOCK_TYPE * pxTaskSpinlock );
|
||||||
|
#define taskDATA_GROUP_UNLOCK taskDataGroupUnlock
|
||||||
|
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* task. h
|
||||||
|
*
|
||||||
|
* Macros to temporarily promote a held data group lock to a full data group
|
||||||
|
* critical section, and to demote it back again. A data group that is locked
|
||||||
|
* holds the task spinlock with preemption disabled, which keeps other tasks
|
||||||
|
* out but not interrupts. Promoting additionally masks interrupts and takes
|
||||||
|
* the ISR spinlock, so that data shared with an ISR can be updated. The
|
||||||
|
* critical nesting count records whether interrupts were already masked on
|
||||||
|
* entry, so no interrupt state has to be saved by the caller.
|
||||||
|
*
|
||||||
|
* \defgroup taskDATA_GROUP_PROMOTE_LOCK_TO_CRITICAL taskDATA_GROUP_PROMOTE_LOCK_TO_CRITICAL
|
||||||
|
* \ingroup GranularLocks
|
||||||
|
*/
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
#define taskDATA_GROUP_PROMOTE_LOCK_TO_CRITICAL( pxISRSpinlock ) \
|
||||||
|
do { \
|
||||||
|
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
|
||||||
|
portDISABLE_INTERRUPTS(); \
|
||||||
|
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) ( pxISRSpinlock ) ); \
|
||||||
|
} while( 0 )
|
||||||
|
|
||||||
|
#define taskDATA_GROUP_DEMOTE_CRITICAL_TO_LOCK( pxISRSpinlock ) \
|
||||||
|
do { \
|
||||||
|
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
|
||||||
|
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) ( pxISRSpinlock ) ); \
|
||||||
|
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
|
||||||
|
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0U ) \
|
||||||
|
{ \
|
||||||
|
portENABLE_INTERRUPTS(); \
|
||||||
|
} \
|
||||||
|
} while( 0 )
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
|
||||||
|
|
||||||
#if ( configNUMBER_OF_CORES == 1 )
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
#define taskYIELD_WITHIN_API() portYIELD_WITHIN_API()
|
#define taskYIELD_WITHIN_API() portYIELD_WITHIN_API()
|
||||||
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
@ -3826,6 +3851,8 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList,
|
||||||
* Removes a task from both the specified event list and the list of blocked
|
* Removes a task from both the specified event list and the list of blocked
|
||||||
* tasks, and places it on a ready queue.
|
* tasks, and places it on a ready queue.
|
||||||
*
|
*
|
||||||
|
* Do not call this function from an ISR context. Call xTaskRemoveFromEventListFromISR() instead.
|
||||||
|
*
|
||||||
* xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called
|
* xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called
|
||||||
* if either an event occurs to unblock a task, or the block timeout period
|
* if either an event occurs to unblock a task, or the block timeout period
|
||||||
* expires.
|
* expires.
|
||||||
|
|
@ -3842,6 +3869,23 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList,
|
||||||
* making the call, otherwise pdFALSE.
|
* making the call, otherwise pdFALSE.
|
||||||
*/
|
*/
|
||||||
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
|
||||||
|
* INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
|
||||||
|
* AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
|
||||||
|
*
|
||||||
|
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
|
||||||
|
*
|
||||||
|
* Removes a task from both the specified event list and the list of blocked
|
||||||
|
* tasks, and places it on a ready queue. This function is the ISR-safe version
|
||||||
|
* of xTaskRemoveFromEventList().
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the task being removed has a higher priority than the task
|
||||||
|
* making the call, otherwise pdFALSE.
|
||||||
|
*/
|
||||||
|
BaseType_t xTaskRemoveFromEventListFromISR( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,
|
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,
|
||||||
const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
|
const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
@ -4022,11 +4066,12 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks whether a yield is required after portUNLOCK_DATA_GROUP() returns.
|
* Checks whether a yield is required after portUNLOCK_DATA_GROUP() returns.
|
||||||
* To be called while data group is locked.
|
* To be called while data group is locked or after an interrupt invokes
|
||||||
|
* a FreeRTOS API prior to returning to the task.
|
||||||
*/
|
*/
|
||||||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
BaseType_t xTaskUnlockCanYield( void );
|
BaseType_t xTaskUnlockCanYield( void );
|
||||||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
#endif
|
||||||
|
|
||||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
|
||||||
|
|
|
||||||
87
queue.c
87
queue.c
|
|
@ -2500,7 +2500,15 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
|
||||||
* removed from the queue while the queue was locked. When a queue is
|
* removed from the queue while the queue was locked. When a queue is
|
||||||
* locked items can be added or removed, but the event lists cannot be
|
* locked items can be added or removed, but the event lists cannot be
|
||||||
* updated. */
|
* updated. */
|
||||||
taskENTER_CRITICAL();
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
const BaseType_t xCoreID = portGET_CORE_ID();
|
||||||
|
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID );
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->xISRSpinlock ) );
|
||||||
|
#else
|
||||||
|
queueENTER_CRITICAL( pxQueue );
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int8_t cTxLock = pxQueue->cTxLock;
|
int8_t cTxLock = pxQueue->cTxLock;
|
||||||
|
|
||||||
|
|
@ -2578,10 +2586,26 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
|
||||||
|
|
||||||
pxQueue->cTxLock = queueUNLOCKED;
|
pxQueue->cTxLock = queueUNLOCKED;
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->xISRSpinlock ) );
|
||||||
|
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID );
|
||||||
|
|
||||||
|
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0U )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
queueEXIT_CRITICAL( pxQueue );
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Do the same for the Rx lock. */
|
/* Do the same for the Rx lock. */
|
||||||
taskENTER_CRITICAL();
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID );
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->xISRSpinlock ) );
|
||||||
|
#else
|
||||||
|
queueENTER_CRITICAL( pxQueue );
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int8_t cRxLock = pxQueue->cRxLock;
|
int8_t cRxLock = pxQueue->cRxLock;
|
||||||
|
|
||||||
|
|
@ -3336,8 +3360,63 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( configUSE_QUEUE_SETS == 1 )
|
#if ( configUSE_QUEUE_SETS == 1 )
|
||||||
|
|
||||||
static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue )
|
static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue )
|
||||||
|
{
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
/* Call the generic version with xIsISR = pdFALSE to indicate task context */
|
||||||
|
|
||||||
|
#if ( portUSING_GRANULAR_LOCKS == 0 )
|
||||||
|
{
|
||||||
|
xReturn = prvNotifyQueueSetContainerGeneric( pxQueue, pdFALSE );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
const BaseType_t xCoreID = portGET_CORE_ID();
|
||||||
|
|
||||||
|
/* This API must be called in a critical section which already has preemption
|
||||||
|
* and interrupt disabled. */
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xTaskSpinlock ) );
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
|
||||||
|
{
|
||||||
|
xReturn = prvNotifyQueueSetContainerGeneric( pxQueue, pdFALSE );
|
||||||
|
}
|
||||||
|
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
|
||||||
|
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xTaskSpinlock ) );
|
||||||
|
}
|
||||||
|
#endif /* if ( portUSING_GRANULAR_LOCKS == 0 ) */
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BaseType_t prvNotifyQueueSetContainerFromISR( const Queue_t * const pxQueue )
|
||||||
|
{
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
/* Call the generic version with xIsISR = pdTRUE to indicate ISR context */
|
||||||
|
|
||||||
|
#if ( portUSING_GRANULAR_LOCKS == 0 )
|
||||||
|
{
|
||||||
|
xReturn = prvNotifyQueueSetContainerGeneric( pxQueue, pdTRUE );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
const BaseType_t xCoreID = portGET_CORE_ID();
|
||||||
|
|
||||||
|
/* This API must be called in a critical section which already has interrupt disabled. */
|
||||||
|
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
|
||||||
|
{
|
||||||
|
xReturn = prvNotifyQueueSetContainerGeneric( pxQueue, pdTRUE );
|
||||||
|
}
|
||||||
|
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
|
||||||
|
}
|
||||||
|
#endif /* if ( portUSING_GRANULAR_LOCKS == 0 ) */
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BaseType_t prvNotifyQueueSetContainerGeneric( const Queue_t * const pxQueue,
|
||||||
|
const BaseType_t xIsISR )
|
||||||
{
|
{
|
||||||
Queue_t * pxQueueSetContainer = pxQueue->pxQueueSetContainer;
|
Queue_t * pxQueueSetContainer = pxQueue->pxQueueSetContainer;
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn = pdFALSE;
|
||||||
|
|
|
||||||
10
timers.c
10
timers.c
|
|
@ -149,6 +149,16 @@
|
||||||
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
|
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
|
||||||
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
|
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
|
||||||
|
|
||||||
|
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||||
|
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||||
|
PRIVILEGED_DATA portSPINLOCK_TYPE xTimerTaskSpinlock = portINIT_SPINLOCK_STATIC;
|
||||||
|
PRIVILEGED_DATA portSPINLOCK_TYPE xTimerISRSpinlock = portINIT_SPINLOCK_STATIC;
|
||||||
|
#else
|
||||||
|
PRIVILEGED_DATA static portSPINLOCK_TYPE xTimerTaskSpinlock = portINIT_SPINLOCK_STATIC;
|
||||||
|
PRIVILEGED_DATA static portSPINLOCK_TYPE xTimerISRSpinlock = portINIT_SPINLOCK_STATIC;
|
||||||
|
#endif
|
||||||
|
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue