diff --git a/include/task.h b/include/task.h index 2a19fa73fc..16b216dd15 100644 --- a/include/task.h +++ b/include/task.h @@ -54,9 +54,9 @@ * The tskKERNEL_VERSION_MAJOR, tskKERNEL_VERSION_MINOR, tskKERNEL_VERSION_BUILD * values will reflect the last released version number. */ -#define tskKERNEL_VERSION_NUMBER "V11.1.0+" +#define tskKERNEL_VERSION_NUMBER "V11.3.0+" #define tskKERNEL_VERSION_MAJOR 11 -#define tskKERNEL_VERSION_MINOR 1 +#define tskKERNEL_VERSION_MINOR 3 #define tskKERNEL_VERSION_BUILD 0 /* MPU region parameters passed in ulParameters @@ -184,6 +184,14 @@ typedef struct xTASK_STATUS #endif } TaskStatus_t; +#if ( configUSE_TRACE_FACILITY == 1 ) + /* Callback type used by uxTaskCallForEachTask(). The callback receives one + * populated TaskStatus_t at a time, plus an opaque caller-supplied context + * pointer. */ + typedef void (* TaskStatusCallbackFunction_t)( const TaskStatus_t * pxTaskStatus, + void * pvCallbackContext ); +#endif + /* Possible return values for eTaskConfirmSleepModeStatus(). */ typedef enum { @@ -2186,6 +2194,30 @@ 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 a filled in TaskStatus_t. + * + * 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. + * + * @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 2523515cd6..654b7ba193 100644 --- a/tasks.c +++ b/tasks.c @@ -639,22 +639,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. @@ -3690,9 +3674,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 ) */ } } @@ -4453,11 +4437,103 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) #if ( configUSE_TRACE_FACILITY == 1 ) + static UBaseType_t prvForEachTaskInList( List_t * pxList, + eTaskState eState, + TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext ); + + typedef struct xTASK_STATUS_ARRAY_WRITER_CONTEXT + { + TaskStatus_t * pxTaskStatusArray; + UBaseType_t uxIndex; + } TaskStatusArrayWriterContext_t; + + static void prvTaskStatusArrayWriter( const TaskStatus_t * pxTaskStatus, + void * pvCallbackContext ) + { + TaskStatusArrayWriterContext_t * pxContext = ( TaskStatusArrayWriterContext_t * ) pvCallbackContext; + + pxContext->pxTaskStatusArray[ pxContext->uxIndex ] = *pxTaskStatus; + pxContext->uxIndex++; + } + + static UBaseType_t prvCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext, + configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) + { + 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 + + #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 ) */ + + 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, 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; + TaskStatusArrayWriterContext_t xContext = { pxTaskStatusArray, 0 }; traceENTER_uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, pulTotalRunTime ); @@ -4466,54 +4542,7 @@ 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 ) */ + uxTask = prvCallForEachTask( prvTaskStatusArrayWriter, &xContext, pulTotalRunTime ); } else { @@ -6338,21 +6367,21 @@ 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 ); ListItem_t * pxIterator; TCB_t * pxTCB = NULL; + TaskStatus_t xTaskStatusBuffer; 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. */ + /* Populate one TaskStatus_t structure for each task referenced + * from pxList, then hand it to the callback. */ for( pxIterator = listGET_HEAD_ENTRY( pxList ); pxIterator != pxEndMarker; pxIterator = listGET_NEXT( pxIterator ) ) { /* MISRA Ref 11.5.3 [Void pointer assignment] */ @@ -6360,7 +6389,8 @@ 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 ); + vTaskGetInfo( ( TaskHandle_t ) pxTCB, &xTaskStatusBuffer, pdTRUE, eState ); + pxCallbackFunction( &xTaskStatusBuffer, pvCallbackContext ); uxTask++; } }