Compare commits

..

10 commits

Author SHA1 Message Date
Darian Leung 8eb906d08d feat(freertos/smp): Add Granular Locking V4 proposal documents
Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:27:06 +02:00
Darian Leung 6faa6e2463 change(freertos/smp): Update timers.c locking
Updated timers.c to use granular locking

- Added xTaskSpinlock and xISRSpinlock
- Replaced critical section macros with data group critical section macros
such as taskENTER/EXIT_CRITICAL() with tmrENTER/EXIT_CRITICAL().
- Added vTimerEnterCritical() and vTimerExitCritical() to map to the
  data group critical section macros.

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:26:56 +02:00
Darian Leung 2f2b7e500a change(freertos/smp): Update stream_buffer.c locking
Updated stream_buffer.c to use granular locking

- Added xTaskSpinlock and xISRSpinlock
- Replaced critical section macros with data group critical section macros
such as taskENTER/EXIT_CRITICAL/_FROM_ISR() with sbENTER/EXIT_CRITICAL_FROM_ISR().
- Added vStreambuffersEnterCritical/FromISR() and
  vStreambuffersExitCritical/FromISR() to map to the data group critical
section macros.
- Added prvLockStreamBufferForTasks() and prvUnlockStreamBufferForTasks() to suspend the stream
buffer when executing non-deterministic code.

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:26:48 +02:00
Darian Leung 2f58dd59c3 change(freertos/smp): Update event_groups.c locking
Updated event_groups.c to use granular locking

- Added xTaskSpinlock and xISRSpinlock
- Replaced critical section macros with data group critical section macros
such as taskENTER/EXIT_CRITICAL/_FROM_ISR() with event_groupsENTER/EXIT_CRITICAL/_FROM_ISR().
- Added vEventGroupsEnterCritical/FromISR() and
  vEventGroupsExitCriti/FromISR() functions that map to the data group
critical section macros.
- Added prvLockEventGroupForTasks() and prvUnlockEventGroupForTasks() to suspend the event
group when executing non-deterministic code.
- xEventGroupSetBits() and vEventGroupDelete() accesses the kernel data group
directly. Thus, added vTaskSuspendAll()/xTaskResumeAll() to these fucntions.

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:26:42 +02:00
Darian Leung 3176808c81 change(freertos/smp): Update queue.c locking
Updated queue.c to use granular locking

- Added xTaskSpinlock and xISRSpinlock
- Replaced  critical section macros with data group critical section macros
such as taskENTER/EXIT_CRITICAL/_FROM_ISR() with queueENTER/EXIT_CRITICAL_FROM_ISR().
- Added vQueueEnterCritical/FromISR() and vQueueExitCritical/FromISR()
  which map to the data group critical section macros.
- Added prvLockQueueForTasks() and prvUnlockQueueForTasks() as the granular locking equivalents
to prvLockQueue() and prvUnlockQueue() respectively

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:26:34 +02:00
Darian Leung fd5037e7cc change(freertos/smp): Update tasks.c locking
Updated critical section macros with granular locks.

Some tasks.c API relied on their callers to enter critical sections. This
assumption no longer works under granular locking. Critical sections added to
the following functions:

- `vTaskInternalSetTimeOutState()`
- `xTaskIncrementTick()`
- `vTaskSwitchContext()`
- `xTaskRemoveFromEventList()`
- `vTaskInternalSetTimeOutState()`
- `eTaskConfirmSleepModeStatus()`
- `xTaskPriorityDisinherit()`
- `pvTaskIncrementMutexHeldCount()`

Added missing suspensions to the following functions:

- `vTaskPlaceOnEventList()`
- `vTaskPlaceOnUnorderedEventList()`
- `vTaskPlaceOnEventListRestricted()`

Fixed the locking in vTaskSwitchContext()

vTaskSwitchContext() must aquire both kernel locks, viz., task lock and
ISR lock. This is because, vTaskSwitchContext() can be called from
either task context or ISR context. Also, vTaskSwitchContext() must not
alter the interrupt state prematurely.

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-05-22 15:26:26 +02:00
Darian Leung 7502d940d9 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>
2025-05-22 15:26:17 +02:00
Darian Leung 87094b4dc8 feat(freertos/smp): Add granular locking port macros checks
Adds the required checks for granular locking port macros.

Port Config:

- portUSING_GRANULAR_LOCKS to enable granular locks
- portCRITICAL_NESTING_IN_TCB should be disabled

Granular Locking Port Macros:

- Spinlocks
        - portSPINLOCK_TYPE
        - portINIT_SPINLOCK( pxSpinlock )
        - portINIT_SPINLOCK_STATIC
- Locking
        - portGET_SPINLOCK()
        - portRELEASE_SPINLOCK()

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-03-31 15:26:11 +02:00
Darian Leung ad7e48a7d5 feat(freertos/smp): Allow vTaskPreemptionEnable() to be nested
Changed xPreemptionDisable to be a count rather than a pdTRUE/pdFALSE. This
allows nested calls to vTaskPreemptionEnable(), where a yield only occurs when
xPreemptionDisable is 0.

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-03-31 15:26:11 +02:00
Darian Leung a6d6d1220f refactor(freertos/smp): Move critical sections inside xTaskPriorityInherit()
xTaskPriorityInherit() is called inside a critical section from queue.c. This
commit moves the critical section into xTaskPriorityInherit().

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2025-03-31 15:26:11 +02:00
13 changed files with 42 additions and 48 deletions

View file

@ -7,7 +7,7 @@ on:
workflow_dispatch:
jobs:
formatting:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4.1.1
- name: Check Formatting of FreeRTOS-Kernel Files

25
.github/workflows/formatting.yml vendored Normal file
View file

@ -0,0 +1,25 @@
name: Format Pull Request Files
on:
issue_comment:
types: [created]
env:
bashPass: \033[32;1mPASSED -
bashInfo: \033[33;1mINFO -
bashFail: \033[31;1mFAILED -
bashEnd: \033[0m
jobs:
Formatting:
name: Run Formatting Check
if: ${{ github.event.issue.pull_request &&
( ( github.event.comment.body == '/bot run uncrustify' ) ||
( github.event.comment.body == '/bot run formatting' ) ) }}
runs-on: ubuntu-20.04
steps:
- name: Apply Formatting Fix
id: check-formatting
uses: FreeRTOS/CI-CD-Github-Actions/formatting-bot@main
with:
exclude-dirs: portable

View file

@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
kernel-checker:
name: FreeRTOS Kernel Header Checks
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
# Install python 3
- name: Tool Setup

View file

@ -3,7 +3,7 @@ on: [push, pull_request]
jobs:
run:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Checkout Parent Repository
uses: actions/checkout@v4.1.1

View file

@ -415,8 +415,6 @@
* number of the failing assert (for example, "vAssertCalled( __FILE__, __LINE__
* )" or it can simple disable interrupts and sit in a loop to halt all
* execution on the failing line for viewing in a debugger. */
/* *INDENT-OFF* */
#define configASSERT( x ) \
if( ( x ) == 0 ) \
{ \
@ -424,7 +422,6 @@
for( ; ; ) \
; \
}
/* *INDENT-ON* */
/******************************************************************************/
/* FreeRTOS MPU specific definitions. *****************************************/

View file

@ -246,10 +246,7 @@ void vCoRoutineSchedule( void );
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
/* *INDENT-OFF* */
#define crEND() }
/* *INDENT-ON* */
/*
* These macros are intended for internal use by the co-routine implementation

View file

@ -333,7 +333,6 @@ typedef enum
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( ( pxDataGroup )->xISRSpinlock ) ); \
/* Increment the critical nesting count */ \
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
/* Return the previous interrupt status */ \
uxSavedInterruptStatus; \
} )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
@ -351,7 +350,6 @@ typedef enum
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 ); \
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) \
{ \
@ -384,9 +382,7 @@ typedef enum
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 * ) &( pxDataGroup->xISRSpinlock ) ); \
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) \
{ \

View file

@ -1059,8 +1059,8 @@
configRUN_TIME_COUNTER_TYPE * pulTotalRunTime ) /* PRIVILEGED_FUNCTION */
{
UBaseType_t uxReturn = 0;
BaseType_t xIsTaskStatusArrayWriteable = pdFALSE;
BaseType_t xIsTotalRunTimeWriteable = pdFALSE;
UBaseType_t xIsTaskStatusArrayWriteable = pdFALSE;
UBaseType_t xIsTotalRunTimeWriteable = pdFALSE;
uint32_t ulArraySize = ( uint32_t ) uxArraySize;
uint32_t ulTaskStatusSize = ( uint32_t ) sizeof( TaskStatus_t );

View file

@ -234,11 +234,6 @@ __attribute__(( weak )) void vApplicationSetupTickTimerInterrupt( void )
{
const uint32_t ulCompareMatch = ( (configPERIPHERAL_CLOCK_HZ / portTIMER_PRESCALE) / configTICK_RATE_HZ ) - 1UL;
/* PR1 is 16-bit. Ensure that the configPERIPHERAL_CLOCK_HZ and
* configTICK_RATE_HZ are defined such that ulCompareMatch value would fit
* in 16-bits. */
configASSERT( ( ulCompareMatch & 0xFFFF0000 ) == 0 );
T1CON = 0x0000;
T1CONbits.TCKPS = portPRESCALE_BITS;
PR1 = ulCompareMatch;

View file

@ -324,23 +324,17 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void )
{
Thread_t * pxCurrentThread;
BaseType_t xIsFreeRTOSThread;
/* Stop the timer tick thread. */
xTimerTickThreadShouldRun = false;
pthread_join( hTimerTickThread, NULL );
/* Check whether the current thread is a FreeRTOS thread.
* This has to happen before the scheduler is signaled to exit
* its loop to prevent data races on the thread key. */
xIsFreeRTOSThread = prvIsFreeRTOSThread();
/* Signal the scheduler to exit its loop. */
xSchedulerEnd = pdTRUE;
( void ) pthread_kill( hMainThread, SIG_RESUME );
/* Waiting to be deleted here. */
if( xIsFreeRTOSThread == pdTRUE )
if( prvIsFreeRTOSThread() == pdTRUE )
{
pxCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
event_wait( pxCurrentThread->ev );

View file

@ -339,14 +339,6 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
prvUnlockQueue( ( pxQueue ) ); \
portRELEASE_SPINLOCK( portGET_CORE_ID(), &( pxQueue->xTaskSpinlock ) ); \
vTaskPreemptionEnable( NULL ); \
if( ( xYieldAPI ) == pdTRUE ) \
{ \
taskYIELD_WITHIN_API(); \
} \
else \
{ \
mtCOVERAGE_TEST_MARKER(); \
} \
} while( 0 )
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define queueLOCK( pxQueue ) \

12
tasks.c
View file

@ -5406,13 +5406,11 @@ BaseType_t xTaskIncrementTick( void )
* SMP port. */
configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 );
/* vTaskSwitchContext() must not be called with a task that has
* preemption disabled. */
if( uxSchedulerSuspended != ( UBaseType_t ) 0U
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
configASSERT( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == 0U );
|| ( ( taskTASK_IS_RUNNING( pxCurrentTCBs[ xCoreID ] ) ) && ( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable > 0U ) )
#endif
if( uxSchedulerSuspended != ( UBaseType_t ) 0U )
)
{
/* The scheduler is currently suspended or the task
* has requested to not be preempted - do not allow
@ -7500,11 +7498,11 @@ static void prvResetNextTaskUnblockTime( void )
BaseType_t xYieldCurrentTask;
/* Get the xYieldPending stats inside the critical section. */
#if ( portUSING_GRANULAR_LOCKS == 1 )
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
xYieldCurrentTask = xTaskUnlockCanYield();
#else
xYieldCurrentTask = xYieldPendings[ xCoreID ];
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
#endif /* configUSE_TASK_PREEMPTION_DISABLE */
kernelRELEASE_ISR_LOCK( xCoreID );
kernelRELEASE_TASK_LOCK( xCoreID );