Add uxTaskCallForEachTask, and refactor uxTaskGetSystemState to use it. (#1439)

---------

Co-authored-by: Anubhav Rawal <rawalexe@amazon.com>
Co-authored-by: Kody Stribrny <kstribrn@amazon.com>
This commit is contained in:
Dave Nadler
2026-07-23 12:04:42 -04:00
committed by GitHub
parent 78069a79ea
commit 5706e10cb4
2 changed files with 148 additions and 75 deletions

View File

@@ -184,6 +184,13 @@ typedef struct xTASK_STATUS
#endif
} TaskStatus_t;
/* Callback type used by uxTaskCallForEachTask(). The callback receives one
* task handle and state at a time, plus an opaque caller-supplied context
* pointer. The callback may call vTaskGetInfo() if it needs a TaskStatus_t. */
typedef void (* TaskStatusCallbackFunction_t)( TaskHandle_t xTask,
eTaskState eState,
void * pvCallbackContext );
/* Possible return values for eTaskConfirmSleepModeStatus(). */
typedef enum
{
@@ -2210,7 +2217,38 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION;
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION;
#endif
/**
* For each task, call pxCallbackFunction with the task's handle and state,
* and the provided context.
*
* NOTE: This function is intended for debugging use only as it suspends
* the scheduler for an extended period. The callback runs while the
* scheduler is suspended, so it must return quickly and must not perform
* blocking operations.
*
* NOTE: This API is privileged-only (it invokes a user callback from
* privileged context).
*
* @param pxCallbackFunction Callback to invoke once for each task (passing
* the task's handle, state, and the pvCallbackContext).
*
* @param pvCallbackContext Opaque caller-provided context passed through to
* each callback invocation.
*
* @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in
* FreeRTOSConfig.h then *pulTotalRunTime is set to the total run time since
* boot. pulTotalRunTime can be set to NULL to omit the total run time
* information.
*
* @return The number tasks provided to the callback.
*/
UBaseType_t uxTaskCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION;
#endif /* if ( configUSE_TRACE_FACILITY == 1 ) */
/**
* task. h

183
tasks.c
View File

@@ -643,22 +643,6 @@ STATIC void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
STATIC void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION;
/*
* Fills an TaskStatus_t structure with information on each task that is
* referenced from the pxList list (which may be a ready list, a delayed list,
* a suspended list, etc.).
*
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
* NORMAL APPLICATION CODE.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
STATIC UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray,
List_t * pxList,
eTaskState eState ) PRIVILEGED_FUNCTION;
#endif
/*
* Searches pxList for a task with name pcNameToQuery - returning a handle to
* the task if it is found, or NULL if the task is not found.
@@ -3695,7 +3679,7 @@ STATIC BaseType_t prvCreateIdleTasks( void )
{
xIdleTaskHandles[ xCoreID ]->uxCoreAffinityMask = ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID );
}
#endif
#endif /* #if ( ( configIDLE_AFFINITY == 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */
}
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
}
@@ -4457,11 +4441,107 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery )
#if ( configUSE_TRACE_FACILITY == 1 )
STATIC UBaseType_t prvForEachTaskInList( List_t * pxList,
eTaskState eState,
TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext );
/* for uxTaskGetSystemState callback context: current write position into TaskStatusArray */
typedef struct xTASK_STATUS_ARRAY_WRITER_CONTEXT
{
TaskStatus_t * pxTaskStatusArray;
UBaseType_t uxIndex;
} TaskStatusArrayWriterContext_t;
/* callback for uxTaskGetSystemState: write one task's status into TaskStatusArray */
STATIC void prvTaskStatusArrayWriter( TaskHandle_t xTask,
eTaskState eState,
void * pvCallbackContext )
{
TaskStatusArrayWriterContext_t * pxContext = ( TaskStatusArrayWriterContext_t * ) pvCallbackContext;
vTaskGetInfo( xTask, &( pxContext->pxTaskStatusArray[ pxContext->uxIndex++ ] ), pdTRUE, eState );
}
STATIC void prvGetTotalRunTime( configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
{
if( pulTotalRunTime != NULL )
{
#if ( configGENERATE_RUN_TIME_STATS == 1 )
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
#else
*pulTotalRunTime = ( configRUN_TIME_COUNTER_TYPE ) portGET_RUN_TIME_COUNTER_VALUE();
#endif
#else
*pulTotalRunTime = 0;
#endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
}
}
/* For each task, call the provided callback function (passing the provided context). */
/* Caller must suspend the scheduler around use of this function. */
STATIC UBaseType_t prvCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext )
{
UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
/* Visit each task in the Ready state. */
do
{
uxQueue--;
uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &( pxReadyTasksLists[ uxQueue ] ), eReady, pxCallbackFunction, pvCallbackContext ) );
} while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY );
/* Visit each task in the Blocked state. */
uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( ( List_t * ) pxDelayedTaskList, eBlocked, pxCallbackFunction, pvCallbackContext ) );
uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( ( List_t * ) pxOverflowDelayedTaskList, eBlocked, pxCallbackFunction, pvCallbackContext ) );
#if ( INCLUDE_vTaskDelete == 1 )
{
/* Visit each task that has been deleted but not yet cleaned up. */
uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &xTasksWaitingTermination, eDeleted, pxCallbackFunction, pvCallbackContext ) );
}
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
{
/* Visit each task in the Suspended state. */
uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &xSuspendedTaskList, eSuspended, pxCallbackFunction, pvCallbackContext ) );
}
#endif
return uxTask;
}
UBaseType_t uxTaskCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
{
UBaseType_t uxTask;
configASSERT( pxCallbackFunction != NULL );
if( pxCallbackFunction == NULL )
{
return 0;
}
vTaskSuspendAll();
{
uxTask = prvCallForEachTask( pxCallbackFunction, pvCallbackContext );
prvGetTotalRunTime( pulTotalRunTime );
}
( void ) xTaskResumeAll();
return uxTask;
}
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
{
UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
UBaseType_t uxTask = 0;
traceENTER_uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, pulTotalRunTime );
@@ -4470,54 +4550,11 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery )
/* Is there a space in the array for each task in the system? */
if( uxArraySize >= uxCurrentNumberOfTasks )
{
/* Fill in an TaskStatus_t structure with information on each
* task in the Ready state. */
do
{
uxQueue--;
uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ) );
} while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY );
/* Fill in an TaskStatus_t structure with information on each
* task in the Blocked state. */
uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ) );
uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ) );
#if ( INCLUDE_vTaskDelete == 1 )
{
/* Fill in an TaskStatus_t structure with information on
* each task that has been deleted but not yet cleaned up. */
uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ) );
}
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
{
/* Fill in an TaskStatus_t structure with information on
* each task in the Suspended state. */
uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ) );
}
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
if( pulTotalRunTime != NULL )
{
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
#else
*pulTotalRunTime = ( configRUN_TIME_COUNTER_TYPE ) portGET_RUN_TIME_COUNTER_VALUE();
#endif
}
}
#else /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
{
if( pulTotalRunTime != NULL )
{
*pulTotalRunTime = 0;
}
}
#endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
TaskStatusArrayWriterContext_t xContext;
xContext.pxTaskStatusArray = pxTaskStatusArray;
xContext.uxIndex = 0;
uxTask = prvCallForEachTask( prvTaskStatusArrayWriter, &xContext );
prvGetTotalRunTime( pulTotalRunTime );
}
else
{
@@ -6344,9 +6381,10 @@ STATIC void prvCheckTasksWaitingTermination( void )
#if ( configUSE_TRACE_FACILITY == 1 )
STATIC UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray,
List_t * pxList,
eTaskState eState )
STATIC UBaseType_t prvForEachTaskInList( List_t * pxList,
eTaskState eState,
TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext )
{
UBaseType_t uxTask = 0;
const ListItem_t * pxEndMarker = listGET_END_MARKER( pxList );
@@ -6355,10 +6393,7 @@ STATIC void prvCheckTasksWaitingTermination( void )
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
{
/* Populate an TaskStatus_t structure within the
* pxTaskStatusArray array for each task that is referenced from
* pxList. See the definition of TaskStatus_t in task.h for the
* meaning of each TaskStatus_t structure member. */
/* Hand the callback each task handle referenced from pxList. */
for( pxIterator = listGET_HEAD_ENTRY( pxList ); pxIterator != pxEndMarker; pxIterator = listGET_NEXT( pxIterator ) )
{
/* MISRA Ref 11.5.3 [Void pointer assignment] */
@@ -6366,7 +6401,7 @@ STATIC void prvCheckTasksWaitingTermination( void )
/* coverity[misra_c_2012_rule_11_5_violation] */
pxTCB = listGET_LIST_ITEM_OWNER( pxIterator );
vTaskGetInfo( ( TaskHandle_t ) pxTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState );
pxCallbackFunction( ( TaskHandle_t ) pxTCB, eState, pvCallbackContext );
uxTask++;
}
}