-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Feature/smp granular locks v4 #1154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
sudeep-mohanty
wants to merge
12
commits into
FreeRTOS:main
Choose a base branch
from
sudeep-mohanty:feature/smp_granular_locks_v4
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
11bc74c
refactor(freertos/smp): Move critical sections inside xTaskPriorityIn…
Dazza0 c4a723e
feat(freertos/smp): Allow vTaskPreemptionEnable() to be nested
Dazza0 6c5458c
feat(freertos/smp): Add granular locking port macros checks
Dazza0 8ceb94d
feat(granular_locks): Add granular locking functions
Dazza0 bf34180
change(freertos/smp): Update tasks.c locking
Dazza0 8b0eb06
change(freertos/smp): Update queue.c locking
Dazza0 463c2a9
change(freertos/smp): Update event_groups.c locking
Dazza0 bc4d600
change(freertos/smp): Update stream_buffer.c locking
Dazza0 c857a36
change(freertos/smp): Update timers.c locking
Dazza0 ec3c41e
feat(freertos/smp): Add Granular Locking V4 proposal documents
Dazza0 40a991d
feat(freertos-smp): Light Weight Preemption Disable Locks
sudeep-mohanty 7df6202
fix(freertos-smp): Stop unconditional yielding in vTaskPreemptionEnable
sudeep-mohanty File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,10 +63,48 @@ | |
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) | ||
uint8_t ucStaticallyAllocated; /**< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ | ||
#endif | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
portSPINLOCK_TYPE xTaskSpinlock; | ||
portSPINLOCK_TYPE xISRSpinlock; | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
} EventGroup_t; | ||
|
||
/*-----------------------------------------------------------*/ | ||
|
||
/* | ||
* Macros to mark the start and end of a critical code region. | ||
*/ | ||
#if ( portUSING_GRANULAR_LOCKS == 1 ) | ||
#define event_groupsENTER_CRITICAL( pxEventBits ) taskDATA_GROUP_ENTER_CRITICAL( &pxEventBits->xTaskSpinlock, &pxEventBits->xISRSpinlock ) | ||
#define event_groupsENTER_CRITICAL_FROM_ISR( pxEventBits, puxSavedInterruptStatus ) taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR( &pxEventBits->xISRSpinlock, puxSavedInterruptStatus ) | ||
#define event_groupsEXIT_CRITICAL( pxEventBits ) taskDATA_GROUP_EXIT_CRITICAL( &pxEventBits->xTaskSpinlock, &pxEventBits->xISRSpinlock ) | ||
#define event_groupsEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxEventBits ) taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, &pxEventBits->xISRSpinlock ) | ||
#else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ | ||
#define event_groupsENTER_CRITICAL( pxEventBits ) taskENTER_CRITICAL(); | ||
#define event_groupsENTER_CRITICAL_FROM_ISR( pxEventBits, puxSavedInterruptStatus ) do { *( puxSavedInterruptStatus ) = taskENTER_CRITICAL_FROM_ISR(); } while( 0 ) | ||
#define event_groupsEXIT_CRITICAL( pxEventBits ) taskEXIT_CRITICAL(); | ||
#define event_groupsEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxEventBits ) taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); | ||
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ | ||
|
||
/* | ||
* Locks an event group for tasks. Prevents other tasks from accessing the event group but allows | ||
* ISRs to pend access to the event group. Caller cannot be preempted by other tasks | ||
* after locking the event group, thus allowing the caller to execute non-deterministic | ||
* operations. | ||
*/ | ||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
static void prvLockEventGroupForTasks( EventGroup_t * pxEventBits ) PRIVILEGED_FUNCTION; | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
|
||
/* | ||
* Unlocks an event group for tasks. Handles all pended access from ISRs, then reenables | ||
* preemption for the caller. | ||
*/ | ||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
static BaseType_t prvUnlockEventGroupForTasks( EventGroup_t * pxEventBits ) PRIVILEGED_FUNCTION; | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
|
||
/* | ||
* Test the bits set in uxCurrentEventBits to see if the wait condition is met. | ||
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is | ||
|
@@ -79,6 +117,25 @@ | |
const EventBits_t uxBitsToWaitFor, | ||
const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; | ||
|
||
/*-----------------------------------------------------------*/ | ||
|
||
/* | ||
* 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 ) prvLockEventGroupForTasks( pxEventBits ) | ||
#define event_groupsUNLOCK( pxEventBits ) prvUnlockEventGroupForTasks( pxEventBits ); | ||
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
#define event_groupsLOCK( pxEventBits ) vTaskSuspendAll() | ||
#define event_groupsUNLOCK( pxEventBits ) xTaskResumeAll() | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
|
||
/*-----------------------------------------------------------*/ | ||
|
||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) | ||
|
@@ -122,6 +179,13 @@ | |
} | ||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
{ | ||
portINIT_SPINLOCK( &( pxEventBits->xTaskSpinlock ) ); | ||
portINIT_SPINLOCK( &( pxEventBits->xISRSpinlock ) ); | ||
} | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
|
||
traceEVENT_GROUP_CREATE( pxEventBits ); | ||
} | ||
else | ||
|
@@ -167,6 +231,13 @@ | |
} | ||
#endif /* configSUPPORT_STATIC_ALLOCATION */ | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
{ | ||
portINIT_SPINLOCK( &( pxEventBits->xTaskSpinlock ) ); | ||
portINIT_SPINLOCK( &( pxEventBits->xISRSpinlock ) ); | ||
} | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
|
||
traceEVENT_GROUP_CREATE( pxEventBits ); | ||
} | ||
else | ||
|
@@ -202,7 +273,7 @@ | |
} | ||
#endif | ||
|
||
vTaskSuspendAll(); | ||
event_groupsLOCK( pxEventBits ); | ||
{ | ||
uxOriginalBitValue = pxEventBits->uxEventBits; | ||
|
||
|
@@ -245,7 +316,7 @@ | |
} | ||
} | ||
} | ||
xAlreadyYielded = xTaskResumeAll(); | ||
xAlreadyYielded = event_groupsUNLOCK( pxEventBits ); | ||
|
||
if( xTicksToWait != ( TickType_t ) 0 ) | ||
{ | ||
|
@@ -267,7 +338,7 @@ | |
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) | ||
{ | ||
/* The task timed out, just return the current event bit value. */ | ||
taskENTER_CRITICAL(); | ||
event_groupsENTER_CRITICAL( pxEventBits ); | ||
{ | ||
uxReturn = pxEventBits->uxEventBits; | ||
|
||
|
@@ -284,7 +355,7 @@ | |
mtCOVERAGE_TEST_MARKER(); | ||
} | ||
} | ||
taskEXIT_CRITICAL(); | ||
event_groupsEXIT_CRITICAL( pxEventBits ); | ||
|
||
xTimeoutOccurred = pdTRUE; | ||
} | ||
|
@@ -333,7 +404,7 @@ | |
} | ||
#endif | ||
|
||
vTaskSuspendAll(); | ||
event_groupsLOCK( pxEventBits ); | ||
{ | ||
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; | ||
|
||
|
@@ -401,7 +472,7 @@ | |
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); | ||
} | ||
} | ||
xAlreadyYielded = xTaskResumeAll(); | ||
xAlreadyYielded = event_groupsUNLOCK( pxEventBits ); | ||
|
||
if( xTicksToWait != ( TickType_t ) 0 ) | ||
{ | ||
|
@@ -422,7 +493,7 @@ | |
|
||
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) | ||
{ | ||
taskENTER_CRITICAL(); | ||
event_groupsENTER_CRITICAL( pxEventBits ); | ||
{ | ||
/* The task timed out, just return the current event bit value. */ | ||
uxReturn = pxEventBits->uxEventBits; | ||
|
@@ -447,7 +518,7 @@ | |
|
||
xTimeoutOccurred = pdTRUE; | ||
} | ||
taskEXIT_CRITICAL(); | ||
event_groupsEXIT_CRITICAL( pxEventBits ); | ||
} | ||
else | ||
{ | ||
|
@@ -482,7 +553,7 @@ | |
configASSERT( xEventGroup ); | ||
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); | ||
|
||
taskENTER_CRITICAL(); | ||
event_groupsENTER_CRITICAL( pxEventBits ); | ||
{ | ||
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); | ||
|
||
|
@@ -493,7 +564,7 @@ | |
/* Clear the bits. */ | ||
pxEventBits->uxEventBits &= ~uxBitsToClear; | ||
} | ||
taskEXIT_CRITICAL(); | ||
event_groupsEXIT_CRITICAL( pxEventBits ); | ||
|
||
traceRETURN_xEventGroupClearBits( uxReturn ); | ||
|
||
|
@@ -524,19 +595,19 @@ | |
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) | ||
{ | ||
UBaseType_t uxSavedInterruptStatus; | ||
EventGroup_t const * const pxEventBits = xEventGroup; | ||
EventGroup_t * const pxEventBits = xEventGroup; | ||
EventBits_t uxReturn; | ||
|
||
traceENTER_xEventGroupGetBitsFromISR( xEventGroup ); | ||
|
||
/* MISRA Ref 4.7.1 [Return value shall be checked] */ | ||
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */ | ||
/* coverity[misra_c_2012_directive_4_7_violation] */ | ||
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); | ||
event_groupsENTER_CRITICAL_FROM_ISR( pxEventBits, &uxSavedInterruptStatus ); | ||
{ | ||
uxReturn = pxEventBits->uxEventBits; | ||
} | ||
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); | ||
event_groupsEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxEventBits ); | ||
|
||
traceRETURN_xEventGroupGetBitsFromISR( uxReturn ); | ||
|
||
|
@@ -564,10 +635,17 @@ | |
|
||
pxList = &( pxEventBits->xTasksWaitingForBits ); | ||
pxListEnd = listGET_END_MARKER( pxList ); | ||
vTaskSuspendAll(); | ||
event_groupsLOCK( pxEventBits ); | ||
{ | ||
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 ); | ||
|
||
/* Set the bits. */ | ||
|
@@ -638,8 +716,12 @@ | |
|
||
/* Snapshot resulting bits. */ | ||
uxReturnBits = pxEventBits->uxEventBits; | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
( void ) xTaskResumeAll(); | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
} | ||
( void ) xTaskResumeAll(); | ||
( void ) event_groupsUNLOCK( pxEventBits ); | ||
|
||
traceRETURN_xEventGroupSetBits( uxReturnBits ); | ||
|
||
|
@@ -658,19 +740,30 @@ | |
|
||
pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); | ||
|
||
vTaskSuspendAll(); | ||
event_groupsLOCK( pxEventBits ); | ||
{ | ||
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 ) | ||
{ | ||
/* Unblock the task, returning 0 as the event list is being deleted | ||
* and cannot therefore have any bits set. */ | ||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); | ||
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); | ||
} | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
( void ) xTaskResumeAll(); | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
} | ||
( void ) xTaskResumeAll(); | ||
( void ) event_groupsUNLOCK( pxEventBits ); | ||
|
||
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) | ||
{ | ||
|
@@ -774,6 +867,48 @@ | |
traceRETURN_vEventGroupClearBitsCallback(); | ||
} | ||
/*-----------------------------------------------------------*/ | ||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
static void prvLockEventGroupForTasks( EventGroup_t * pxEventBits ) | ||
{ | ||
/* Disable preemption so that the current task cannot be preempted by another task */ | ||
vTaskPreemptionDisable( NULL ); | ||
|
||
/* Keep holding xTaskSpinlock to prevent tasks on other cores from accessing | ||
* the event group while it is suspended. */ | ||
portGET_SPINLOCK( portGET_CORE_ID(), &( pxEventBits->xTaskSpinlock ) ); | ||
} | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
/*-----------------------------------------------------------*/ | ||
|
||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) | ||
static BaseType_t prvUnlockEventGroupForTasks( EventGroup_t * pxEventBits ) | ||
{ | ||
BaseType_t xReturn = pdFALSE; | ||
|
||
/* Release the previously held task spinlock */ | ||
portRELEASE_SPINLOCK( portGET_CORE_ID(), &( pxEventBits->xTaskSpinlock ) ); | ||
|
||
/* Re-enable preemption */ | ||
vTaskPreemptionEnable( NULL ); | ||
|
||
/* Yield if preemption was re-enabled*/ | ||
if( xTaskUnlockCanYield() == pdTRUE ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. xTaskUnlockCanYield() should be called in critical section. We may create another internal API to return the already yielded information when preemption enabled. Basetype_t xCurrentTaskPreemptionEnable( void ); |
||
{ | ||
taskYIELD_WITHIN_API(); | ||
|
||
/* Return true as the task was preempted */ | ||
xReturn = pdTRUE; | ||
} | ||
else | ||
{ | ||
/* Return false as the task was not preempted */ | ||
xReturn = pdFALSE; | ||
} | ||
|
||
return xReturn; | ||
} | ||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ | ||
/*-----------------------------------------------------------*/ | ||
|
||
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, | ||
const EventBits_t uxBitsToWaitFor, | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.