From 1b14543e7d955ee83821e824a9dbbf926c928f97 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Tue, 19 Aug 2025 15:07:19 +0200 Subject: [PATCH] feat(freertos-smp): Create private function for task preemption enable --- include/task.h | 33 ++++++++++++++++++++++++--------- tasks.c | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/include/task.h b/include/task.h index 8bdb80c19..47b1cb5b1 100644 --- a/include/task.h +++ b/include/task.h @@ -361,7 +361,7 @@ typedef enum mtCOVERAGE_TEST_MARKER(); \ } \ /* Re-enable preemption */ \ - vTaskPreemptionEnable( NULL ); \ + prvTaskPreemptionEnable( NULL ); \ } while( 0 ) #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */ @@ -417,14 +417,12 @@ typedef enum * \ingroup GranularLocks */ #if ( portUSING_GRANULAR_LOCKS == 1 ) - #define taskDATA_GROUP_UNLOCK( pxTaskSpinlock ) \ - do { \ - { \ - portRELEASE_SPINLOCK( portGET_CORE_ID(), ( portSPINLOCK_TYPE * ) ( pxTaskSpinlock ) ); \ - } \ - /* Re-enable preemption after releasing the task spinlock. */ \ - vTaskPreemptionEnable( NULL ); \ - } while( 0 ) + #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 ) */ /*----------------------------------------------------------- @@ -1627,6 +1625,23 @@ BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; void vTaskPreemptionEnable( const TaskHandle_t xTask ); #endif +#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) + +/* + * 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. + * + * @param xTask The handle of the task to enable preemption. Passing NULL + * enables preemption for the calling task. + * + * @return pdTRUE if enabling preemption for the task resulted in a context + * switch, otherwise pdFALSE. This is used by the scheduler to determine if a + * context switch may be required following the enable. + */ + BaseType_t prvTaskPreemptionEnable( const TaskHandle_t xTask ); +#endif + /*----------------------------------------------------------- * SCHEDULER CONTROL *----------------------------------------------------------*/ diff --git a/tasks.c b/tasks.c index a093d37bd..f9180ace1 100644 --- a/tasks.c +++ b/tasks.c @@ -857,6 +857,13 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /* #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ +/* + * Helper function to enable preemption for a task. + */ +#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) + BaseType_t prvTaskPreemptionEnable( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +#endif /* #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ + /* * freertos_tasks_c_additions_init() should only be called if the user definable * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro @@ -1096,7 +1103,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; xYieldPendings[ xCoreID ] = pdTRUE; } } - #else /* if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ + #else /* if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ { xLowestPriorityToPreempt = xCurrentCoreTaskPriority; xLowestPriorityCore = xCoreID; @@ -1413,7 +1420,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; xYieldPendings[ uxCore ] = pdTRUE; } } - #else /* if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ + #else /* if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ { xLowestPriority = xTaskPriority; xLowestPriorityCore = ( BaseType_t ) uxCore; @@ -3367,12 +3374,11 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) - void vTaskPreemptionEnable( const TaskHandle_t xTask ) + BaseType_t prvTaskPreemptionEnable( const TaskHandle_t xTask ) { TCB_t * pxTCB; UBaseType_t uxDeferredAction = 0U; - - traceENTER_vTaskPreemptionEnable( xTask ); + BaseType_t xAlreadyYielded = pdFALSE; #if ( configLIGHTWEIGHT_CRITICAL_SECTION == 1 ) vKernelLightWeightEnterCritical(); @@ -3390,11 +3396,8 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, if( pxTCB->uxPreemptionDisable == 0U ) { - /* Process deferred state changes which were inflicted while - * preemption was disabled. */ if( pxTCB->uxDeferredStateChange != 0U ) { - /* Capture the deferred action to perform outside critical section */ uxDeferredAction = pxTCB->uxDeferredStateChange; } else @@ -3402,6 +3405,7 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, if( ( xYieldPendings[ pxTCB->xTaskRunState ] != pdFALSE ) && ( taskTASK_IS_RUNNING( pxTCB ) != pdFALSE ) ) { prvYieldCore( pxTCB->xTaskRunState ); + xAlreadyYielded = pdTRUE; } else { @@ -3425,7 +3429,6 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, kernelEXIT_CRITICAL(); #endif - /* Handle deferred actions outside critical section */ if( uxDeferredAction != 0U ) { if( uxDeferredAction & tskDEFERRED_DELETION ) @@ -3440,8 +3443,24 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, { mtCOVERAGE_TEST_MARKER(); } + + /* Any deferred action on the task would result in a context switch. */ + xAlreadyYielded = pdTRUE; } + return xAlreadyYielded; + } +#endif /* #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) + + void vTaskPreemptionEnable( const TaskHandle_t xTask ) + { + traceENTER_vTaskPreemptionEnable( xTask ); + + ( void ) prvTaskPreemptionEnable( xTask ); + traceRETURN_vTaskPreemptionEnable(); }