From 815951a708f8a3664ea122cbf3e2a3c9faffdb04 Mon Sep 17 00:00:00 2001 From: Dave Nadler Date: Sun, 28 Jun 2026 17:59:28 -0600 Subject: [PATCH 1/2] Add uxTaskCallForEachTask, and refactor uxTaskGetSystemState to use it (take 2). --- include/task.h | 35 ++++++++++ tasks.c | 176 ++++++++++++++++++++++++++++--------------------- 2 files changed, 136 insertions(+), 75 deletions(-) diff --git a/include/task.h b/include/task.h index 2add58b94e..c1a42e436d 100644 --- a/include/task.h +++ b/include/task.h @@ -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 /** diff --git a/tasks.c b/tasks.c index 461271fcff..f3e6f2d43d 100644 --- a/tasks.c +++ b/tasks.c @@ -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++; } } From 4df509969a37769da7ba17256ccf1c1e40f79d10 Mon Sep 17 00:00:00 2001 From: Dave Nadler Date: Sun, 28 Jun 2026 21:22:39 -0600 Subject: [PATCH 2/2] Indentation and comment correction only. --- tasks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks.c b/tasks.c index f3e6f2d43d..d02e1df17b 100644 --- a/tasks.c +++ b/tasks.c @@ -3678,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 /* #if ( ( configIDLE_AFFINITY == 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ } - #endif - } #endif /* if ( configNUMBER_OF_CORES == 1 ) */ } }