Skip to content

Commit 4ee913c

Browse files
Dazza0sudeep-mohanty
authored andcommitted
feat(granular_locks): Add granular locking functions
Added or modify granular locking related API: Added: - vTaskLockDataGroup() - vTaskUnlockDataGroup() - uxTaskLockDataGroupFromISR() - vTaskUnlockDataGroupFromISR() - taskLOCK_DATA_GROUP() - taskUNLOCK_DATA_GROUP() - taskLOCK_DATA_GROUP_FROM_ISR() - taskUNLOCK_DATA_GROUP_FROM_ISR() Updated: - Remove prvCheckForRunStateChange() when granular locks is enabled - 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
1 parent caa4648 commit 4ee913c

File tree

3 files changed

+133
-44
lines changed

3 files changed

+133
-44
lines changed

include/FreeRTOS.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3045,11 +3045,16 @@
30453045
/* Either variables of tick type cannot be read atomically, or
30463046
* portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
30473047
* the tick count is returned to the standard critical section macros. */
3048-
#define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL()
3049-
#define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL()
3048+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
3049+
#define portTICK_TYPE_ENTER_CRITICAL() taskLOCK_DATA_GROUP( &xTaskSpinlock, &xISRSpinlock )
3050+
#define portTICK_TYPE_EXIT_CRITICAL() taskUNLOCK_DATA_GROUP( &xTaskSpinlock, &xISRSpinlock )
3051+
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
3052+
#define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL()
3053+
#define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL()
3054+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
30503055
#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
30513056
#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) )
3052-
#else
3057+
#else /* if ( portTICK_TYPE_IS_ATOMIC == 0 ) */
30533058

30543059
/* The tick type can be read atomically, so critical sections used when the
30553060
* tick count is returned can be defined away. */

include/task.h

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ typedef enum
213213
* \defgroup taskYIELD taskYIELD
214214
* \ingroup SchedulerControl
215215
*/
216-
#define taskYIELD() portYIELD()
216+
#define taskYIELD() portYIELD()
217217

218218
/**
219219
* task. h
@@ -227,12 +227,19 @@ typedef enum
227227
* \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
228228
* \ingroup SchedulerControl
229229
*/
230-
#define taskENTER_CRITICAL() portENTER_CRITICAL()
230+
#define taskENTER_CRITICAL() portENTER_CRITICAL()
231231
#if ( configNUMBER_OF_CORES == 1 )
232-
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
232+
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
233233
#else
234-
#define taskENTER_CRITICAL_FROM_ISR() portENTER_CRITICAL_FROM_ISR()
234+
#define taskENTER_CRITICAL_FROM_ISR() portENTER_CRITICAL_FROM_ISR()
235235
#endif
236+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
237+
#define taskLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) portLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) pxTaskSpinlock, ( portSPINLOCK_TYPE * ) pxISRSpinlock )
238+
#define taskLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock ) portLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock )
239+
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
240+
#define taskLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) taskENTER_CRITICAL()
241+
#define taskLOCK_DATA_GROUP_FROM_ISR( pxISRSpinlock ) taskENTER_CRITICAL_FROM_ISR()
242+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
236243

237244
/**
238245
* task. h
@@ -246,12 +253,19 @@ typedef enum
246253
* \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
247254
* \ingroup SchedulerControl
248255
*/
249-
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
256+
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
250257
#if ( configNUMBER_OF_CORES == 1 )
251-
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
258+
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
252259
#else
253-
#define taskEXIT_CRITICAL_FROM_ISR( x ) portEXIT_CRITICAL_FROM_ISR( x )
260+
#define taskEXIT_CRITICAL_FROM_ISR( x ) portEXIT_CRITICAL_FROM_ISR( x )
254261
#endif
262+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
263+
#define taskUNLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) portUNLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) pxTaskSpinlock, ( portSPINLOCK_TYPE * ) pxISRSpinlock )
264+
#define taskUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock ) portUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock )
265+
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
266+
#define taskUNLOCK_DATA_GROUP( pxTaskSpinlock, pxISRSpinlock ) taskEXIT_CRITICAL()
267+
#define taskUNLOCK_DATA_GROUP_FROM_ISR( x, pxISRSpinlock ) taskEXIT_CRITICAL_FROM_ISR( x )
268+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
255269

256270
/**
257271
* task. h
@@ -3703,7 +3717,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
37033717
* It should be used in the implementation of portENTER_CRITICAL if port is running a
37043718
* multiple core FreeRTOS.
37053719
*/
3706-
#if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) || ( configNUMBER_OF_CORES > 1 ) )
3720+
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
37073721
void vTaskEnterCritical( void );
37083722
#endif
37093723

@@ -3715,7 +3729,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
37153729
* It should be used in the implementation of portEXIT_CRITICAL if port is running a
37163730
* multiple core FreeRTOS.
37173731
*/
3718-
#if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) || ( configNUMBER_OF_CORES > 1 ) )
3732+
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
37193733
void vTaskExitCritical( void );
37203734
#endif
37213735

@@ -3725,7 +3739,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
37253739
* should be used in the implementation of portENTER_CRITICAL_FROM_ISR if port is
37263740
* running a multiple core FreeRTOS.
37273741
*/
3728-
#if ( configNUMBER_OF_CORES > 1 )
3742+
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
37293743
UBaseType_t vTaskEnterCriticalFromISR( void );
37303744
#endif
37313745

@@ -3735,10 +3749,18 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
37353749
* should be used in the implementation of portEXIT_CRITICAL_FROM_ISR if port is
37363750
* running a multiple core FreeRTOS.
37373751
*/
3738-
#if ( configNUMBER_OF_CORES > 1 )
3752+
#if !( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
37393753
void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
37403754
#endif
37413755

3756+
/*
3757+
* Checks whether a yield is required after taskUNLOCK_DATA_GROUP() returns.
3758+
* To be called while data group is locked.
3759+
*/
3760+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
3761+
BaseType_t xTaskUnlockCanYield( void );
3762+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
3763+
37423764
#if ( portUSING_MPU_WRAPPERS == 1 )
37433765

37443766
/*

tasks.c

Lines changed: 92 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINI
488488
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
489489
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
490490
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U;
491-
PRIVILEGED_DATA static volatile BaseType_t xYieldPendings[ configNUMBER_OF_CORES ] = { pdFALSE };
491+
PRIVILEGED_DATA volatile BaseType_t xYieldPendings[ configNUMBER_OF_CORES ] = { pdFALSE };
492492
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
493493
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
494494
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
@@ -522,6 +522,11 @@ PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ conf
522522

523523
#endif
524524

525+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
526+
PRIVILEGED_DATA static portSPINLOCK_TYPE xTaskSpinlock = portINIT_KERNEL_TASK_SPINLOCK_STATIC;
527+
PRIVILEGED_DATA static portSPINLOCK_TYPE xISRSpinlock = portINIT_KERNEL_ISR_SPINLOCK_STATIC;
528+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
529+
525530
/*-----------------------------------------------------------*/
526531

527532
/* File private functions. --------------------------------*/
@@ -531,14 +536,14 @@ PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ conf
531536
*/
532537
static BaseType_t prvCreateIdleTasks( void );
533538

534-
#if ( configNUMBER_OF_CORES > 1 )
539+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
535540

536541
/*
537542
* Checks to see if another task moved the current task out of the ready
538543
* list while it was waiting to enter a critical section and yields, if so.
539544
*/
540545
static void prvCheckForRunStateChange( void );
541-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
546+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
542547

543548
#if ( configNUMBER_OF_CORES > 1 )
544549

@@ -802,7 +807,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
802807
#endif /* #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
803808
/*-----------------------------------------------------------*/
804809

805-
#if ( configNUMBER_OF_CORES > 1 )
810+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
806811
static void prvCheckForRunStateChange( void )
807812
{
808813
UBaseType_t uxPrevCriticalNesting;
@@ -863,7 +868,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
863868
}
864869
}
865870
}
866-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
871+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
867872

868873
/*-----------------------------------------------------------*/
869874

@@ -3871,26 +3876,45 @@ void vTaskSuspendAll( void )
38713876
* do not otherwise exhibit real time behaviour. */
38723877
portSOFTWARE_BARRIER();
38733878

3874-
portGET_TASK_LOCK();
3875-
3876-
/* uxSchedulerSuspended is increased after prvCheckForRunStateChange. The
3877-
* purpose is to prevent altering the variable when fromISR APIs are readying
3878-
* it. */
3879-
if( uxSchedulerSuspended == 0U )
3879+
#if ( portUSING_GRANULAR_LOCKS == 1 )
38803880
{
3881-
prvCheckForRunStateChange();
3881+
portGET_SPINLOCK( &xTaskSpinlock );
3882+
portGET_SPINLOCK( &xISRSpinlock );
3883+
3884+
/* Increment xPreemptionDisable to prevent preemption and also
3885+
* track whether to yield in xTaskResumeAll(). */
3886+
pxCurrentTCBs[ portGET_CORE_ID() ]->xPreemptionDisable++;
3887+
3888+
/* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
3889+
* is used to allow calls to vTaskSuspendAll() to nest. */
3890+
++uxSchedulerSuspended;
3891+
3892+
portRELEASE_SPINLOCK( &xISRSpinlock );
38823893
}
3883-
else
3894+
#else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
38843895
{
3885-
mtCOVERAGE_TEST_MARKER();
3886-
}
3896+
portGET_TASK_LOCK();
38873897

3888-
portGET_ISR_LOCK();
3898+
/* uxSchedulerSuspended is increased after prvCheckForRunStateChange. The
3899+
* purpose is to prevent altering the variable when fromISR APIs are readying
3900+
* it. */
3901+
if( uxSchedulerSuspended == 0U )
3902+
{
3903+
prvCheckForRunStateChange();
3904+
}
3905+
else
3906+
{
3907+
mtCOVERAGE_TEST_MARKER();
3908+
}
38893909

3890-
/* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
3891-
* is used to allow calls to vTaskSuspendAll() to nest. */
3892-
++uxSchedulerSuspended;
3893-
portRELEASE_ISR_LOCK();
3910+
portGET_ISR_LOCK();
3911+
3912+
/* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
3913+
* is used to allow calls to vTaskSuspendAll() to nest. */
3914+
++uxSchedulerSuspended;
3915+
portRELEASE_ISR_LOCK();
3916+
}
3917+
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
38943918

38953919
portCLEAR_INTERRUPT_MASK( ulState );
38963920
}
@@ -3996,7 +4020,24 @@ BaseType_t xTaskResumeAll( void )
39964020
configASSERT( uxSchedulerSuspended != 0U );
39974021

39984022
uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended - 1U );
3999-
portRELEASE_TASK_LOCK();
4023+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
4024+
{
4025+
configASSERT( pxCurrentTCBs[ portGET_CORE_ID() ]->xPreemptionDisable > 0 );
4026+
4027+
/* Decrement xPreemptionDisable. If 0, it means this we are not
4028+
* in a nested suspension scenario, thus this function and yield
4029+
* if necessary. */
4030+
pxCurrentTCBs[ portGET_CORE_ID() ]->xPreemptionDisable--;
4031+
4032+
/* Release the kernel's task spinlock that was held throughout
4033+
* the kernel suspension. */
4034+
portRELEASE_SPINLOCK( &xTaskSpinlock );
4035+
}
4036+
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
4037+
{
4038+
portRELEASE_TASK_LOCK();
4039+
}
4040+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
40004041

40014042
if( uxSchedulerSuspended == ( UBaseType_t ) 0U )
40024043
{
@@ -6968,7 +7009,7 @@ static void prvResetNextTaskUnblockTime( void )
69687009
#endif /* #if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) && ( configNUMBER_OF_CORES == 1 ) ) */
69697010
/*-----------------------------------------------------------*/
69707011

6971-
#if ( configNUMBER_OF_CORES > 1 )
7012+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
69727013

69737014
void vTaskEnterCritical( void )
69747015
{
@@ -7014,11 +7055,10 @@ static void prvResetNextTaskUnblockTime( void )
70147055
traceRETURN_vTaskEnterCritical();
70157056
}
70167057

7017-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
7018-
7058+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
70197059
/*-----------------------------------------------------------*/
70207060

7021-
#if ( configNUMBER_OF_CORES > 1 )
7061+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
70227062

70237063
UBaseType_t vTaskEnterCriticalFromISR( void )
70247064
{
@@ -7047,7 +7087,7 @@ static void prvResetNextTaskUnblockTime( void )
70477087
return uxSavedInterruptStatus;
70487088
}
70497089

7050-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
7090+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
70517091
/*-----------------------------------------------------------*/
70527092

70537093
#if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
@@ -7095,7 +7135,7 @@ static void prvResetNextTaskUnblockTime( void )
70957135
#endif /* #if ( ( portCRITICAL_NESTING_IN_TCB == 1 ) && ( configNUMBER_OF_CORES == 1 ) ) */
70967136
/*-----------------------------------------------------------*/
70977137

7098-
#if ( configNUMBER_OF_CORES > 1 )
7138+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
70997139

71007140
void vTaskExitCritical( void )
71017141
{
@@ -7153,10 +7193,10 @@ static void prvResetNextTaskUnblockTime( void )
71537193
traceRETURN_vTaskExitCritical();
71547194
}
71557195

7156-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
7196+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
71577197
/*-----------------------------------------------------------*/
71587198

7159-
#if ( configNUMBER_OF_CORES > 1 )
7199+
#if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) )
71607200

71617201
void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus )
71627202
{
@@ -7195,7 +7235,29 @@ static void prvResetNextTaskUnblockTime( void )
71957235
traceRETURN_vTaskExitCriticalFromISR();
71967236
}
71977237

7198-
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
7238+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 0 ) && ( configNUMBER_OF_CORES > 1 ) ) */
7239+
/*-----------------------------------------------------------*/
7240+
7241+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
7242+
7243+
BaseType_t xTaskUnlockCanYield( void )
7244+
{
7245+
BaseType_t xReturn;
7246+
BaseType_t xCoreID = portGET_CORE_ID();
7247+
7248+
if( ( xYieldPendings[ xCoreID ] == pdTRUE ) && ( uxSchedulerSuspended == pdFALSE ) && ( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE ) )
7249+
{
7250+
xReturn = pdTRUE;
7251+
}
7252+
else
7253+
{
7254+
xReturn = pdFALSE;
7255+
}
7256+
7257+
return xReturn;
7258+
}
7259+
7260+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
71997261
/*-----------------------------------------------------------*/
72007262

72017263
#if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 )

0 commit comments

Comments
 (0)