Add uxTaskCallForEachTask, and refactor uxTaskGetSystemState to use it (take 2).

This commit is contained in:
Dave Nadler 2026-06-28 17:59:28 -06:00
parent 49cec3e9b2
commit 815951a708
2 changed files with 136 additions and 75 deletions

View file

@ -184,6 +184,15 @@ typedef struct xTASK_STATUS
#endif
} TaskStatus_t;
#if ( configUSE_TRACE_FACILITY == 1 )
/* 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 );
#endif
/* Possible return values for eTaskConfirmSleepModeStatus(). */
typedef enum
{
@ -2186,6 +2195,32 @@ 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;
/**
* 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.
*
* @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 of TaskStatus_t snapshots provided to the callback.
*/
UBaseType_t uxTaskCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction,
void * pvCallbackContext,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION;
#endif
/**

176
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.
@ -3694,9 +3678,9 @@ STATIC BaseType_t prvCreateIdleTasks( void )
#if ( ( configIDLE_AFFINITY == 1 ) && ( configUSE_CORE_AFFINITY == 1 ) )
{
xIdleTaskHandles[ xCoreID ]->uxCoreAffinityMask = ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID );
}
#endif
}
#endif
}
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
}
}
@ -4457,11 +4441,100 @@ 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: write position into TaskStatusArray */
typedef struct xTASK_STATUS_ARRAY_WRITER_CONTEXT
{
TaskStatus_t * pxTaskStatusArray;
UBaseType_t uxIndex;
} TaskStatusArrayWriterContext_t;
/* callback for uxTaskGetSystemState: write the task status for one task 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). */
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 );
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 +4543,9 @@ 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 = { pxTaskStatusArray, 0 };
uxTask = prvCallForEachTask( prvTaskStatusArrayWriter, &xContext );
prvGetTotalRunTime( pulTotalRunTime );
}
else
{
@ -6344,9 +6372,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 +6384,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 +6392,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++;
}
}