adding a minimal idle hook to the SMP port (#329)

* adjusting the kernel checks repo

* Added a minimal idle hook for all idle tasks
This commit is contained in:
Joseph Julicher 2021-05-19 16:19:57 -07:00 committed by GitHub
parent 0c1381311b
commit b515641e0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 174 additions and 139 deletions

View file

@ -21,7 +21,7 @@ jobs:
uses: actions/checkout@v2
with:
repository: FreeRTOS/FreeRTOS
ref: master
ref: smp
path: tools
# Checkout user pull request changes

309
tasks.c
View file

@ -150,7 +150,7 @@
/* A port optimised version is provided. Call the port defined macros. */
#define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
/* A port optimised version is provided, call it only if the TCB being reset
* is being referenced from a ready list. If it is referenced from a delayed
@ -255,7 +255,7 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to
#endif
#if ( configUSE_CORE_AFFINITY == 1 && configNUM_CORES > 1 )
UBaseType_t uxCoreAffinityMask; /*< Used to link the task to certain cores. UBaseType_t must have >= the same number of bits as SMP confNUM_CORES */
UBaseType_t uxCoreAffinityMask; /*< Used to link the task to certain cores. UBaseType_t must have >= the same number of bits as SMP confNUM_CORES */
#endif
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
@ -467,7 +467,7 @@ static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
*/
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
#if ( configNUM_CORES > 1 )
static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
#endif
/*
@ -632,13 +632,13 @@ static void prvCheckForRunStateChange( void )
while( pxThisTCB->xTaskRunState == taskTASK_YIELDING )
{
/* We are only here if we just entered a critical section
* or if we just suspended the scheduler, and another task
* has requested that we yield.
*
* This is slightly complicated since we need to save and restore
* the suspension and critical nesting counts, as well as release
* and reacquire the correct locks. And then do it all over again
* if our state changed again during the reacquisition. */
* or if we just suspended the scheduler, and another task
* has requested that we yield.
*
* This is slightly complicated since we need to save and restore
* the suspension and critical nesting counts, as well as release
* and reacquire the correct locks. And then do it all over again
* if our state changed again during the reacquisition. */
uxPrevCriticalNesting = pxThisTCB->uxCriticalNesting;
uxPrevSchedulerSuspended = uxSchedulerSuspended;
@ -981,58 +981,57 @@ static void prvYieldForTask( TCB_t * pxTCB,
#if ( configNUM_CORES > 1 )
#if ( configUSE_CORE_AFFINITY == 1 )
if( ( pxPreviousTCB != NULL ) && ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxPreviousTCB->uxPriority ] ), &( pxPreviousTCB->xStateListItem ) ) != pdFALSE ) )
{
if( ( pxPreviousTCB != NULL ) && ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxPreviousTCB->uxPriority ] ), &( pxPreviousTCB->xStateListItem ) ) != pdFALSE ) )
{
/* A ready task was just bumped off this core. Look at the cores it can run from
* from to see if it is able to run on any of them */
* from to see if it is able to run on any of them */
UBaseType_t uxCoreMap = pxPreviousTCB->uxCoreAffinityMask;
BaseType_t xLowestPriority = pxPreviousTCB->uxPriority - pxPreviousTCB->xIsIdle;
BaseType_t xLowestPriorityCore = -1;
BaseType_t xLowestPriority = pxPreviousTCB->uxPriority - pxPreviousTCB->xIsIdle;
BaseType_t xLowestPriorityCore = -1;
if( ( uxCoreMap & ( 1 << xCoreID ) ) != 0 )
{
/* The ready task that was removed from this core is not excluded from it.
* Only look at the intersection of the cores the removed task is allowed to run
* on with the cores that the new task is excluded from. It is possible that the
* new task was only placed onto this core because it is excluded from another.
* Check to see if the previous task could run on one of those cores. */
uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
}
else
{
/* The ready task that was removed from this core is excluded from it.
* @todo See if we can schedule it on any of the cores where it is not excluded from. */
}
uxCoreMap &= ( ( 1 << configNUM_CORES ) - 1 );
while( uxCoreMap != 0 )
{
int uxCore = 31UL - ( uint32_t ) __builtin_clz( uxCoreMap );
xassert( taskVALID_CORE_ID( uxCore ) );
uxCoreMap &= ~( 1 << uxCore );
BaseType_t xTaskPriority = ( BaseType_t ) pxCurrentTCBs[ uxCore ]->uxPriority - pxCurrentTCBs[ uxCore ]->xIsIdle;
if( ( xTaskPriority < xLowestPriority ) && ( taskTASK_IS_RUNNING( pxCurrentTCBs[ uxCore ]->xTaskRunState ) != pdFALSE ) && ( xYieldPendings[ uxCore ] == pdFALSE ) )
if( ( uxCoreMap & ( 1 << xCoreID ) ) != 0 )
{
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
if( pxCurrentTCBs[ uxCore ]->xPreemptionDisable == pdFALSE )
#endif
/* The ready task that was removed from this core is not excluded from it.
* Only look at the intersection of the cores the removed task is allowed to run
* on with the cores that the new task is excluded from. It is possible that the
* new task was only placed onto this core because it is excluded from another.
* Check to see if the previous task could run on one of those cores. */
uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
}
else
{
/* The ready task that was removed from this core is excluded from it. */
}
uxCoreMap &= ( ( 1 << configNUM_CORES ) - 1 );
while( uxCoreMap != 0 )
{
int uxCore = 31UL - ( uint32_t ) __builtin_clz( uxCoreMap );
xassert( taskVALID_CORE_ID( uxCore ) );
uxCoreMap &= ~( 1 << uxCore );
BaseType_t xTaskPriority = ( BaseType_t ) pxCurrentTCBs[ uxCore ]->uxPriority - pxCurrentTCBs[ uxCore ]->xIsIdle;
if( ( xTaskPriority < xLowestPriority ) && ( taskTASK_IS_RUNNING( pxCurrentTCBs[ uxCore ]->xTaskRunState ) != pdFALSE ) && ( xYieldPendings[ uxCore ] == pdFALSE ) )
{
xLowestPriority = xTaskPriority;
xLowestPriorityCore = uxCore;
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
if( pxCurrentTCBs[ uxCore ]->xPreemptionDisable == pdFALSE )
#endif
{
xLowestPriority = xTaskPriority;
xLowestPriorityCore = uxCore;
}
}
}
}
if( taskVALID_CORE_ID( xLowestPriorityCore ) )
{
prvYieldCore( xLowestPriorityCore );
if( taskVALID_CORE_ID( xLowestPriorityCore ) )
{
prvYieldCore( xLowestPriorityCore );
}
}
}
#endif /* if ( configUSE_CORE_AFFINITY == 1 ) */
#endif /* if ( configNUM_CORES > 1 ) */
@ -1488,9 +1487,9 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
#if ( configNUM_CORES > 1 )
#if ( configUSE_CORE_AFFINITY == 1 )
{
{
pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY;
}
}
#endif
#endif
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
@ -1555,16 +1554,16 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING;
/* Is this an idle task? */
if(pxTaskCode == prvIdleTask)
if( pxTaskCode == prvIdleTask )
{
pxNewTCB->xIsIdle = pdTRUE;
}
#if ( configNUM_CORES > 1 )
else if( pxTaskCode == prvMinimalIdleTask )
{
pxNewTCB->xIsIdle = pdTRUE;
}
{
pxNewTCB->xIsIdle = pdTRUE;
}
#endif
else
{
@ -2226,31 +2225,31 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
void vTaskCoreAffinitySet( const TaskHandle_t xTask,
UBaseType_t uxCoreAffinityMask )
{
TCB_t * pxTCB;
BaseType_t xCoreID;
taskENTER_CRITICAL();
{
pxTCB = prvGetTCBFromHandle( xTask );
TCB_t * pxTCB;
BaseType_t xCoreID;
taskENTER_CRITICAL();
{
pxTCB = prvGetTCBFromHandle( xTask );
pxTCB->uxCoreAffinityMask = uxCoreAffinityMask;
if( xSchedulerRunning != pdFALSE )
{
if( taskTASK_IS_RUNNING( pxTCB->xTaskRunState ) )
if( xSchedulerRunning != pdFALSE )
{
xCoreID = ( BaseType_t ) pxTCB->xTaskRunState;
if( ( uxCoreAffinityMask & ( 1 << xCoreID ) ) != 0 )
if( taskTASK_IS_RUNNING( pxTCB->xTaskRunState ) )
{
prvYieldCore( xCoreID );
xCoreID = ( BaseType_t ) pxTCB->xTaskRunState;
if( ( uxCoreAffinityMask & ( 1 << xCoreID ) ) == 0 )
{
prvYieldCore( xCoreID );
}
}
}
}
taskEXIT_CRITICAL();
}
taskEXIT_CRITICAL();
}
#endif /* configUSE_CORE_AFFINITY */
#endif /* if ( configNUM_CORES > 1 ) */
@ -2260,19 +2259,19 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
#if ( configUSE_CORE_AFFINITY == 1 )
UBaseType_t vTaskCoreAffinityGet( const TaskHandle_t xTask )
{
TCB_t * pxTCB;
{
TCB_t * pxTCB;
UBaseType_t uxCoreAffinityMask;
taskENTER_CRITICAL();
{
pxTCB = prvGetTCBFromHandle( xTask );
taskENTER_CRITICAL();
{
pxTCB = prvGetTCBFromHandle( xTask );
uxCoreAffinityMask = pxTCB->uxCoreAffinityMask;
}
taskEXIT_CRITICAL();
}
taskEXIT_CRITICAL();
return uxCoreAffinityMask;
}
}
#endif /* configUSE_CORE_AFFINITY */
#endif /* if ( configNUM_CORES > 1 ) */
@ -2625,7 +2624,7 @@ static BaseType_t prvCreateIdleTasks( void )
BaseType_t xCoreID;
char cIdleName[ configMAX_TASK_NAME_LEN ];
/* Add each idle task at the lowest priority. */
/* Add each idle task at the lowest priority. */
for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUM_CORES; xCoreID++ )
{
BaseType_t x;
@ -2685,7 +2684,7 @@ static BaseType_t prvCreateIdleTasks( void )
uint32_t ulIdleTaskStackSize;
/* The Idle task is created using user provided RAM - obtain the
* address of the RAM then create the idle task. */
* address of the RAM then create the idle task. */
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvIdleTask,
cIdleName,
@ -2695,20 +2694,21 @@ static BaseType_t prvCreateIdleTasks( void )
pxIdleTaskStackBuffer,
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#if ( configNUM_CORES > 1 )
else
{
else
{
static StaticTask_t xIdleTCBBuffers[ configNUM_CORES - 1 ];
static StackType_t xIdleTaskStackBuffers[ configNUM_CORES - 1 ][ configMINIMAL_STACK_SIZE ];
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvMinimalIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvMinimalIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
xIdleTaskStackBuffers[ xCoreID - 1 ],
&xIdleTCBBuffers[ xCoreID - 1 ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
}
#endif /* if ( configNUM_CORES > 1 ) */
if( xIdleTaskHandle[ xCoreID ] != NULL )
@ -2724,29 +2724,30 @@ static BaseType_t prvCreateIdleTasks( void )
{
if( xCoreID == 0 )
{
/* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreate( prvIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
/* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreate( prvIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#if ( configNUM_CORES > 1 )
else
{
xReturn = xTaskCreate( prvMinimalIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
else
{
xReturn = xTaskCreate( prvMinimalIdleTask,
cIdleName,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#endif
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
}
return xReturn;
}
@ -4219,45 +4220,62 @@ void vTaskMissedYield( void )
*/
#if ( configNUM_CORES > 1 )
static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters )
{
taskYIELD();
for( ; ; )
static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters )
{
#if ( configUSE_PREEMPTION == 0 )
{
/* If we are not using preemption we keep forcing a task switch to
* see if any other task has become available. If we are using
* preemption we don't need to do this as any task becoming available
* will automatically get the processor anyway. */
taskYIELD();
}
#endif /* configUSE_PREEMPTION */
taskYIELD();
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
/* When using preemption tasks of equal priority will be
* timesliced. If a task that is sharing the idle priority is ready
* to run then the idle task should yield before the end of the
* timeslice.
*
* A critical region is not required here as we are just reading from
* the list, and an occasional incorrect value will not matter. If
* the ready list at the idle priority contains one more task than the
* number of idle tasks, which is equal to the configured numbers of cores
* then a task other than the idle task is ready to execute. */
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) configNUM_CORES )
for( ; ; )
{
#if ( configUSE_PREEMPTION == 0 )
{
/* If we are not using preemption we keep forcing a task switch to
* see if any other task has become available. If we are using
* preemption we don't need to do this as any task becoming available
* will automatically get the processor anyway. */
taskYIELD();
}
else
#endif /* configUSE_PREEMPTION */
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
mtCOVERAGE_TEST_MARKER();
/* When using preemption tasks of equal priority will be
* timesliced. If a task that is sharing the idle priority is ready
* to run then the idle task should yield before the end of the
* timeslice.
*
* A critical region is not required here as we are just reading from
* the list, and an occasional incorrect value will not matter. If
* the ready list at the idle priority contains one more task than the
* number of idle tasks, which is equal to the configured numbers of cores
* then a task other than the idle task is ready to execute. */
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) configNUM_CORES )
{
taskYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
#if ( configUSE_MINIMAL_IDLE_HOOK == 1 )
{
extern void vApplicationMinimalIdleHook( void );
/* Call the user defined function from within the idle task. This
* allows the application designer to add background functionality
* without the overhead of a separate task.
*
* This hook is intended to manage core activity such as disabling cores that go idle.
*
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
* CALL A FUNCTION THAT MIGHT BLOCK. */
vApplicationMinimalIdleHook();
}
#endif /* configUSE_MINIMAL_IDLE_HOOK */
}
}
}
#endif /* if ( configNUM_CORES > 1 ) */
/*
@ -4330,6 +4348,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
/* Call the user defined function from within the idle task. This
* allows the application designer to add background functionality
* without the overhead of a separate task.
*
* NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
* CALL A FUNCTION THAT MIGHT BLOCK. */
vApplicationIdleHook();
@ -4385,6 +4404,22 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
}
}
#endif /* configUSE_TICKLESS_IDLE */
#if ( configUSE_MINIMAL_IDLE_HOOK == 1 )
{
extern void vApplicationMinimalIdleHook( void );
/* Call the user defined function from within the idle task. This
* allows the application designer to add background functionality
* without the overhead of a separate task.
*
* This hook is intended to manage core activity such as disabling cores that go idle.
*
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
* CALL A FUNCTION THAT MIGHT BLOCK. */
vApplicationMinimalIdleHook();
}
#endif /* configUSE_MINIMAL_IDLE_HOOK */
}
}
/*-----------------------------------------------------------*/