diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index d9c2c39d1..1d50a3c6e 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -2966,6 +2966,10 @@ #error configUSE_PORT_OPTIMISED_TASK_SELECTION is not supported in SMP FreeRTOS #endif +#ifndef configLIGHTWEIGHT_CRITICAL_SECTION + #define configLIGHTWEIGHT_CRITICAL_SECTION 0 +#endif + #ifndef configINITIAL_TICK_COUNT #define configINITIAL_TICK_COUNT 0 #endif diff --git a/include/task.h b/include/task.h index e42d7f292..7622cbcb3 100644 --- a/include/task.h +++ b/include/task.h @@ -3933,6 +3933,22 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus ); #endif +/* + * This function is only intended for use when disabling or enabling preemption of a task. + * This function takes only the kernel ISR lock, not the task lock. + */ +#if ( configLIGHTWEIGHT_CRITICAL_SECTION == 1 ) + void vKernelLightWeightEnterCritical( void ); +#endif + +/* + * This function is only intended for use when disabling or enabling preemption of a task. + * This function releases only the kernel ISR lock, not the task lock. + */ +#if ( configLIGHTWEIGHT_CRITICAL_SECTION == 1 ) + void vKernelLightWeightExitCritical( void ); +#endif + #if ( portUSING_MPU_WRAPPERS == 1 ) /* diff --git a/tasks.c b/tasks.c index ed992a5a0..eb2c12c0d 100644 --- a/tasks.c +++ b/tasks.c @@ -854,6 +854,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /* #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ +/* Lightweight critical section helpers (re-introduced) */ +#if ( configLIGHTWEIGHT_CRITICAL_SECTION == 1 ) + +/* Checks to see if another task moved the current task out of the ready + * list while it was waiting to enter a lightweight critical section and yields, if so. */ + static void prvLightWeightCheckForRunStateChange( void ); +#endif + /* * Helper function to enable preemption for a task. */ @@ -7779,6 +7787,112 @@ static void prvResetNextTaskUnblockTime( void ) #endif /* #if ( configNUMBER_OF_CORES > 1 ) */ /*-----------------------------------------------------------*/ +#if ( configLIGHTWEIGHT_CRITICAL_SECTION == 1 ) + + static void prvLightWeightCheckForRunStateChange( void ) + { + const TCB_t * pxThisTCB; + BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); + + /* Must not be called from ISR context. */ + portASSERT_IF_IN_ISR(); + + /* Called with interrupts disabled. Safe to read pxCurrentTCBs. */ + pxThisTCB = pxCurrentTCBs[ xCoreID ]; + + while( pxThisTCB->xTaskRunState == taskTASK_SCHEDULED_TO_YIELD ) + { + UBaseType_t uxPrevCriticalNesting; + + /* Save nesting and temporarily release ISR lock if needed to service pending IPI. */ + uxPrevCriticalNesting = portGET_CRITICAL_NESTING_COUNT( xCoreID ); + + if( uxPrevCriticalNesting > 0U ) + { + portSET_CRITICAL_NESTING_COUNT( xCoreID, 0U ); + kernelRELEASE_ISR_LOCK( xCoreID ); + } + + portMEMORY_BARRIER(); + + /* Allow the core to service pending yield interrupt. */ + portENABLE_INTERRUPTS(); + portDISABLE_INTERRUPTS(); + + /* Reacquire ISR lock and restore nesting; re-evaluate run state. */ + xCoreID = ( BaseType_t ) portGET_CORE_ID(); + kernelGET_ISR_LOCK( xCoreID ); + portSET_CRITICAL_NESTING_COUNT( xCoreID, uxPrevCriticalNesting ); + pxThisTCB = pxCurrentTCBs[ xCoreID ]; + } + } + + void vKernelLightWeightEnterCritical( void ) + { + if( xSchedulerRunning != pdFALSE ) + { + portDISABLE_INTERRUPTS(); + { + const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); + + /* Take only the ISR lock, not the task lock. */ + kernelGET_ISR_LOCK( xCoreID ); + + portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); + + if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 1U ) + { + prvLightWeightCheckForRunStateChange(); + } + } + } + } + + void vKernelLightWeightExitCritical( void ) + { + if( xSchedulerRunning != pdFALSE ) + { + const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); + + if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) > 0U ) + { + BaseType_t xYieldCurrentTask; + + if( ( xYieldPendings[ xCoreID ] == pdTRUE ) && ( uxSchedulerSuspended == pdFALSE ) + #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) + && ( pxCurrentTCBs[ xCoreID ]->uxPreemptionDisable == 0U ) && + ( pxCurrentTCBs[ xCoreID ]->uxDeferredStateChange == 0U ) + #endif + ) + { + xYieldCurrentTask = pdTRUE; + } + else + { + xYieldCurrentTask = pdFALSE; + } + + /* Release only the ISR lock. */ + kernelRELEASE_ISR_LOCK( xCoreID ); + + portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); + + if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0U ) + { + portENABLE_INTERRUPTS(); + + if( xYieldCurrentTask != pdFALSE ) + { + portYIELD(); + } + } + } + } + } + +#endif /* configLIGHTWEIGHT_CRITICAL_SECTION == 1 */ +/*-----------------------------------------------------------*/ + #if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) static char * prvWriteNameToBuffer( char * pcBuffer,