Replace sprintf with snprintf (#802)

This change necessitates the introduction of 2 new APIs:

void vTaskListTasks( char * pcWriteBuffer, size_t uxBufferLength );
void vTaskGetRunTimeStatistics( char * pcWriteBuffer, size_t uxBufferLength );

These 2 APIs behave exactly as vTaskList and vTaskGetRunTimeStats
except the fact that they take the length of the pcWriteBuffer as the
second argument to ensure that we do not write past the buffer.

vTaskList and vTaskGetRunTimeStats assume that the length of the
buffer is configSTATS_BUFFER_MAX_LENGTH which defaults to 0xFFFF.
This is done to ensure that the existing applications do not break.
New applications should use the new APIs to avoid memory corruption.
This commit is contained in:
Gaurav-Aggarwal-AWS 2023-09-26 23:07:18 +05:30 committed by GitHub
parent 84bdb05bd2
commit 96d6190b61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 328 additions and 64 deletions

View file

@ -2154,20 +2154,20 @@
#define traceRETURN_vTaskExitCriticalFromISR() #define traceRETURN_vTaskExitCriticalFromISR()
#endif #endif
#ifndef traceENTER_vTaskList #ifndef traceENTER_vTaskListTasks
#define traceENTER_vTaskList( pcWriteBuffer ) #define traceENTER_vTaskListTasks( pcWriteBuffer, uxBufferLength )
#endif #endif
#ifndef traceRETURN_vTaskList #ifndef traceRETURN_vTaskListTasks
#define traceRETURN_vTaskList() #define traceRETURN_vTaskListTasks()
#endif #endif
#ifndef traceENTER_vTaskGetRunTimeStats #ifndef traceENTER_vTaskGetRunTimeStatistics
#define traceENTER_vTaskGetRunTimeStats( pcWriteBuffer ) #define traceENTER_vTaskGetRunTimeStatistics( pcWriteBuffer, uxBufferLength )
#endif #endif
#ifndef traceRETURN_vTaskGetRunTimeStats #ifndef traceRETURN_vTaskGetRunTimeStatistics
#define traceRETURN_vTaskGetRunTimeStats() #define traceRETURN_vTaskGetRunTimeStatistics()
#endif #endif
#ifndef traceENTER_uxTaskResetEventItemValue #ifndef traceENTER_uxTaskResetEventItemValue
@ -2686,6 +2686,10 @@
#endif #endif
#endif #endif
#ifndef configSTATS_BUFFER_MAX_LENGTH
#define configSTATS_BUFFER_MAX_LENGTH 0xFFFF
#endif
#ifndef configSTACK_DEPTH_TYPE #ifndef configSTACK_DEPTH_TYPE
/* Defaults to uint16_t for backward compatibility, but can be overridden /* Defaults to uint16_t for backward compatibility, but can be overridden

View file

@ -2074,6 +2074,60 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize, const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION; configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION;
/**
* task. h
* @code{c}
* void vTaskListTasks( char *pcWriteBuffer, size_t uxBufferLength );
* @endcode
*
* configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS must
* both be defined as 1 for this function to be available. See the
* configuration section of the FreeRTOS.org website for more information.
*
* NOTE 1: This function will disable interrupts for its duration. It is
* not intended for normal application runtime use but as a debug aid.
*
* Lists all the current tasks, along with their current state and stack
* usage high water mark.
*
* Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
* suspended ('S').
*
* PLEASE NOTE:
*
* This function is provided for convenience only, and is used by many of the
* demo applications. Do not consider it to be part of the scheduler.
*
* vTaskListTasks() calls uxTaskGetSystemState(), then formats part of the
* uxTaskGetSystemState() output into a human readable table that displays task:
* names, states, priority, stack usage and task number.
* Stack usage specified as the number of unused StackType_t words stack can hold
* on top of stack - not the number of bytes.
*
* vTaskListTasks() has a dependency on the snprintf() C library function that might
* bloat the code size, use a lot of stack, and provide different results on
* different platforms. An alternative, tiny, third party, and limited
* functionality implementation of snprintf() is provided in many of the
* FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note
* printf-stdarg.c does not provide a full snprintf() implementation!).
*
* It is recommended that production systems call uxTaskGetSystemState()
* directly to get access to raw stats data, rather than indirectly through a
* call to vTaskListTasks().
*
* @param pcWriteBuffer A buffer into which the above mentioned details
* will be written, in ASCII form. This buffer is assumed to be large
* enough to contain the generated report. Approximately 40 bytes per
* task should be sufficient.
*
* @param uxBufferLength Length of the pcWriteBuffer.
*
* \defgroup vTaskListTasks vTaskListTasks
* \ingroup TaskUtils
*/
void vTaskListTasks( char * pcWriteBuffer,
size_t uxBufferLength ) PRIVILEGED_FUNCTION;
/** /**
* task. h * task. h
* @code{c} * @code{c}
@ -2084,6 +2138,11 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
* both be defined as 1 for this function to be available. See the * both be defined as 1 for this function to be available. See the
* configuration section of the FreeRTOS.org website for more information. * configuration section of the FreeRTOS.org website for more information.
* *
* WARN: This function assumes that the pcWriteBuffer is of length
* configSTATS_BUFFER_MAX_LENGTH. This function is there only for
* backward compatibility. New applications are recommended to
* use vTaskListTasks and supply the length of the pcWriteBuffer explicitly.
*
* NOTE 1: This function will disable interrupts for its duration. It is * NOTE 1: This function will disable interrupts for its duration. It is
* not intended for normal application runtime use but as a debug aid. * not intended for normal application runtime use but as a debug aid.
* *
@ -2104,10 +2163,10 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
* Stack usage specified as the number of unused StackType_t words stack can hold * Stack usage specified as the number of unused StackType_t words stack can hold
* on top of stack - not the number of bytes. * on top of stack - not the number of bytes.
* *
* vTaskList() has a dependency on the sprintf() C library function that might * vTaskList() has a dependency on the snprintf() C library function that might
* bloat the code size, use a lot of stack, and provide different results on * bloat the code size, use a lot of stack, and provide different results on
* different platforms. An alternative, tiny, third party, and limited * different platforms. An alternative, tiny, third party, and limited
* functionality implementation of sprintf() is provided in many of the * functionality implementation of snprintf() is provided in many of the
* FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note
* printf-stdarg.c does not provide a full snprintf() implementation!). * printf-stdarg.c does not provide a full snprintf() implementation!).
* *
@ -2123,7 +2182,66 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
* \defgroup vTaskList vTaskList * \defgroup vTaskList vTaskList
* \ingroup TaskUtils * \ingroup TaskUtils
*/ */
void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #define vTaskList( pcWriteBuffer ) vTaskListTasks( pcWriteBuffer, configSTATS_BUFFER_MAX_LENGTH )
/**
* task. h
* @code{c}
* void vTaskGetRunTimeStatistics( char *pcWriteBuffer, size_t uxBufferLength );
* @endcode
*
* configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS
* must both be defined as 1 for this function to be available. The application
* must also then provide definitions for
* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE()
* to configure a peripheral timer/counter and return the timers current count
* value respectively. The counter should be at least 10 times the frequency of
* the tick count.
*
* NOTE 1: This function will disable interrupts for its duration. It is
* not intended for normal application runtime use but as a debug aid.
*
* Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total
* accumulated execution time being stored for each task. The resolution
* of the accumulated time value depends on the frequency of the timer
* configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro.
* Calling vTaskGetRunTimeStatistics() writes the total execution time of each
* task into a buffer, both as an absolute count value and as a percentage
* of the total system execution time.
*
* NOTE 2:
*
* This function is provided for convenience only, and is used by many of the
* demo applications. Do not consider it to be part of the scheduler.
*
* vTaskGetRunTimeStatistics() calls uxTaskGetSystemState(), then formats part of
* the uxTaskGetSystemState() output into a human readable table that displays the
* amount of time each task has spent in the Running state in both absolute and
* percentage terms.
*
* vTaskGetRunTimeStatistics() has a dependency on the snprintf() C library function
* that might bloat the code size, use a lot of stack, and provide different
* results on different platforms. An alternative, tiny, third party, and
* limited functionality implementation of snprintf() is provided in many of the
* FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note
* printf-stdarg.c does not provide a full snprintf() implementation!).
*
* It is recommended that production systems call uxTaskGetSystemState() directly
* to get access to raw stats data, rather than indirectly through a call to
* vTaskGetRunTimeStatistics().
*
* @param pcWriteBuffer A buffer into which the execution times will be
* written, in ASCII form. This buffer is assumed to be large enough to
* contain the generated report. Approximately 40 bytes per task should
* be sufficient.
*
* @param uxBufferLength Length of the pcWriteBuffer.
*
* \defgroup vTaskGetRunTimeStatistics vTaskGetRunTimeStatistics
* \ingroup TaskUtils
*/
void vTaskGetRunTimeStatistics( char * pcWriteBuffer,
size_t uxBufferLength ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
/** /**
* task. h * task. h
@ -2139,6 +2257,12 @@ void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unquali
* value respectively. The counter should be at least 10 times the frequency of * value respectively. The counter should be at least 10 times the frequency of
* the tick count. * the tick count.
* *
* WARN: This function assumes that the pcWriteBuffer is of length
* configSTATS_BUFFER_MAX_LENGTH. This function is there only for
* backward compatiblity. New applications are recommended to use
* vTaskGetRunTimeStatistics and supply the length of the pcWriteBuffer
* explicitly.
*
* NOTE 1: This function will disable interrupts for its duration. It is * NOTE 1: This function will disable interrupts for its duration. It is
* not intended for normal application runtime use but as a debug aid. * not intended for normal application runtime use but as a debug aid.
* *
@ -2160,10 +2284,10 @@ void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unquali
* amount of time each task has spent in the Running state in both absolute and * amount of time each task has spent in the Running state in both absolute and
* percentage terms. * percentage terms.
* *
* vTaskGetRunTimeStats() has a dependency on the sprintf() C library function * vTaskGetRunTimeStats() has a dependency on the snprintf() C library function
* that might bloat the code size, use a lot of stack, and provide different * that might bloat the code size, use a lot of stack, and provide different
* results on different platforms. An alternative, tiny, third party, and * results on different platforms. An alternative, tiny, third party, and
* limited functionality implementation of sprintf() is provided in many of the * limited functionality implementation of snprintf() is provided in many of the
* FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note
* printf-stdarg.c does not provide a full snprintf() implementation!). * printf-stdarg.c does not provide a full snprintf() implementation!).
* *
@ -2179,7 +2303,7 @@ void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unquali
* \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats
* \ingroup TaskUtils * \ingroup TaskUtils
*/ */
void vTaskGetRunTimeStats( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #define vTaskGetRunTimeStats( pcWriteBuffer ) vTaskGetRunTimeStatistics( pcWriteBuffer, configSTATS_BUFFER_MAX_LENGTH )
/** /**
* task. h * task. h

236
tasks.c
View file

@ -719,6 +719,32 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
extern void vApplicationMinimalIdleHook( void ); extern void vApplicationMinimalIdleHook( void );
#endif /* #if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) */ #endif /* #if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) */
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
/*
* Convert the snprintf return value to the number of characters
* written. The following are the possible cases:
*
* 1. The buffer supplied to snprintf is large enough to hold the
* generated string. The return value in this case is the number
* of characters actually written, not counting the terminating
* null character.
* 2. The buffer supplied to snprintf is NOT large enough to hold
* the generated string. The return value in this case is the
* number of characters that would have been written if the
* buffer had been sufficiently large, not counting the
* terminating null character.
* 3. Encoding error. The return value in this case is a negative
* number.
*
* From 1 and 2 above ==> Only when the return value is non-negative
* and less than the supplied buffer length, the string has been
* completely written.
*/
static size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue,
size_t n );
#endif /* #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 ) #if ( configNUMBER_OF_CORES > 1 )
@ -1914,6 +1940,39 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */ #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
static size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue,
size_t n )
{
size_t uxCharsWritten;
if( iSnprintfReturnValue < 0 )
{
/* Encoding error - Return 0 to indicate that nothing
* was written to the buffer. */
uxCharsWritten = 0;
}
else if( iSnprintfReturnValue >= ( int ) n )
{
/* This is the case when the supplied buffer is not
* large to hold the generated string. Return the
* number of characters actually written without
* counting the terminating NULL character. */
uxCharsWritten = n - 1;
}
else
{
/* Complete string was written to the buffer. */
uxCharsWritten = ( size_t ) iSnprintfReturnValue;
}
return uxCharsWritten;
}
#endif /* #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
/*-----------------------------------------------------------*/
#if ( INCLUDE_vTaskDelete == 1 ) #if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete( TaskHandle_t xTaskToDelete ) void vTaskDelete( TaskHandle_t xTaskToDelete )
@ -6812,13 +6871,18 @@ static void prvResetNextTaskUnblockTime( void )
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
void vTaskList( char * pcWriteBuffer ) void vTaskListTasks( char * pcWriteBuffer,
size_t uxBufferLength )
{ {
TaskStatus_t * pxTaskStatusArray; TaskStatus_t * pxTaskStatusArray;
size_t uxConsumedBufferLength = 0;
size_t uxCharsWrittenBySnprintf;
int iSnprintfReturnValue;
BaseType_t xOutputBufferFull = pdFALSE;
UBaseType_t uxArraySize, x; UBaseType_t uxArraySize, x;
char cStatus; char cStatus;
traceENTER_vTaskList( pcWriteBuffer ); traceENTER_vTaskListTasks( pcWriteBuffer, uxBufferLength );
/* /*
* PLEASE NOTE: * PLEASE NOTE:
@ -6827,23 +6891,23 @@ static void prvResetNextTaskUnblockTime( void )
* of the demo applications. Do not consider it to be part of the * of the demo applications. Do not consider it to be part of the
* scheduler. * scheduler.
* *
* vTaskList() calls uxTaskGetSystemState(), then formats part of the * vTaskListTasks() calls uxTaskGetSystemState(), then formats part of the
* uxTaskGetSystemState() output into a human readable table that * uxTaskGetSystemState() output into a human readable table that
* displays task: names, states, priority, stack usage and task number. * displays task: names, states, priority, stack usage and task number.
* Stack usage specified as the number of unused StackType_t words stack can hold * Stack usage specified as the number of unused StackType_t words stack can hold
* on top of stack - not the number of bytes. * on top of stack - not the number of bytes.
* *
* vTaskList() has a dependency on the sprintf() C library function that * vTaskListTasks() has a dependency on the snprintf() C library function that
* might bloat the code size, use a lot of stack, and provide different * might bloat the code size, use a lot of stack, and provide different
* results on different platforms. An alternative, tiny, third party, * results on different platforms. An alternative, tiny, third party,
* and limited functionality implementation of sprintf() is provided in * and limited functionality implementation of snprintf() is provided in
* many of the FreeRTOS/Demo sub-directories in a file called * many of the FreeRTOS/Demo sub-directories in a file called
* printf-stdarg.c (note printf-stdarg.c does not provide a full * printf-stdarg.c (note printf-stdarg.c does not provide a full
* snprintf() implementation!). * snprintf() implementation!).
* *
* It is recommended that production systems call uxTaskGetSystemState() * It is recommended that production systems call uxTaskGetSystemState()
* directly to get access to raw stats data, rather than indirectly * directly to get access to raw stats data, rather than indirectly
* through a call to vTaskList(). * through a call to vTaskListTasks().
*/ */
@ -6865,7 +6929,7 @@ static void prvResetNextTaskUnblockTime( void )
uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
/* Create a human readable table from the binary data. */ /* Create a human readable table from the binary data. */
for( x = 0; x < uxArraySize; x++ ) for( x = 0; ( x < uxArraySize ) && ( xOutputBufferFull == pdFALSE ); x++ )
{ {
switch( pxTaskStatusArray[ x ].eCurrentState ) switch( pxTaskStatusArray[ x ].eCurrentState )
{ {
@ -6896,13 +6960,43 @@ static void prvResetNextTaskUnblockTime( void )
break; break;
} }
/* Write the task name to the string, padding with spaces so it /* Is there enough space in the buffer to hold task name? */
* can be printed in tabular form more easily. */ if( ( uxConsumedBufferLength + configMAX_TASK_NAME_LEN ) <= uxBufferLength )
pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); {
/* Write the task name to the string, padding with spaces so it
* can be printed in tabular form more easily. */
pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
/* Do not count the terminating null character. */
uxConsumedBufferLength = uxConsumedBufferLength + ( configMAX_TASK_NAME_LEN - 1 );
/* Write the rest of the string. */ /* Is there space left in the buffer? -1 is done because snprintf
sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ * writes a terminating null character. So we are essentially
pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */ * checking if the buffer has space to write at least one non-null
* character. */
if( uxConsumedBufferLength < ( uxBufferLength - 1 ) )
{
/* Write the rest of the string. */
iSnprintfReturnValue = snprintf( pcWriteBuffer,
uxBufferLength - uxConsumedBufferLength,
"\t%c\t%u\t%u\t%u\r\n",
cStatus,
( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority,
( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark,
( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
uxCharsWrittenBySnprintf = prvSnprintfReturnValueToCharsWritten( iSnprintfReturnValue, uxBufferLength - uxConsumedBufferLength );
uxConsumedBufferLength += uxCharsWrittenBySnprintf;
pcWriteBuffer += uxCharsWrittenBySnprintf; /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
}
else
{
xOutputBufferFull = pdTRUE;
}
}
else
{
xOutputBufferFull = pdTRUE;
}
} }
/* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
@ -6914,7 +7008,7 @@ static void prvResetNextTaskUnblockTime( void )
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
traceRETURN_vTaskList(); traceRETURN_vTaskListTasks();
} }
#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
@ -6922,13 +7016,18 @@ static void prvResetNextTaskUnblockTime( void )
#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configUSE_TRACE_FACILITY == 1 ) ) #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configUSE_TRACE_FACILITY == 1 ) )
void vTaskGetRunTimeStats( char * pcWriteBuffer ) void vTaskGetRunTimeStatistics( char * pcWriteBuffer,
size_t uxBufferLength )
{ {
TaskStatus_t * pxTaskStatusArray; TaskStatus_t * pxTaskStatusArray;
size_t uxConsumedBufferLength = 0;
size_t uxCharsWrittenBySnprintf;
int iSnprintfReturnValue;
BaseType_t xOutputBufferFull = pdFALSE;
UBaseType_t uxArraySize, x; UBaseType_t uxArraySize, x;
configRUN_TIME_COUNTER_TYPE ulTotalTime, ulStatsAsPercentage; configRUN_TIME_COUNTER_TYPE ulTotalTime, ulStatsAsPercentage;
traceENTER_vTaskGetRunTimeStats( pcWriteBuffer ); traceENTER_vTaskGetRunTimeStatistics( pcWriteBuffer, uxBufferLength );
/* /*
* PLEASE NOTE: * PLEASE NOTE:
@ -6937,22 +7036,22 @@ static void prvResetNextTaskUnblockTime( void )
* of the demo applications. Do not consider it to be part of the * of the demo applications. Do not consider it to be part of the
* scheduler. * scheduler.
* *
* vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part * vTaskGetRunTimeStatistics() calls uxTaskGetSystemState(), then formats part
* of the uxTaskGetSystemState() output into a human readable table that * of the uxTaskGetSystemState() output into a human readable table that
* displays the amount of time each task has spent in the Running state * displays the amount of time each task has spent in the Running state
* in both absolute and percentage terms. * in both absolute and percentage terms.
* *
* vTaskGetRunTimeStats() has a dependency on the sprintf() C library * vTaskGetRunTimeStatistics() has a dependency on the snprintf() C library
* function that might bloat the code size, use a lot of stack, and * function that might bloat the code size, use a lot of stack, and
* provide different results on different platforms. An alternative, * provide different results on different platforms. An alternative,
* tiny, third party, and limited functionality implementation of * tiny, third party, and limited functionality implementation of
* sprintf() is provided in many of the FreeRTOS/Demo sub-directories in * snprintf() is provided in many of the FreeRTOS/Demo sub-directories in
* a file called printf-stdarg.c (note printf-stdarg.c does not provide * a file called printf-stdarg.c (note printf-stdarg.c does not provide
* a full snprintf() implementation!). * a full snprintf() implementation!).
* *
* It is recommended that production systems call uxTaskGetSystemState() * It is recommended that production systems call uxTaskGetSystemState()
* directly to get access to raw stats data, rather than indirectly * directly to get access to raw stats data, rather than indirectly
* through a call to vTaskGetRunTimeStats(). * through a call to vTaskGetRunTimeStatistics().
*/ */
/* Make sure the write buffer does not contain a string. */ /* Make sure the write buffer does not contain a string. */
@ -6979,50 +7078,87 @@ static void prvResetNextTaskUnblockTime( void )
if( ulTotalTime > 0UL ) if( ulTotalTime > 0UL )
{ {
/* Create a human readable table from the binary data. */ /* Create a human readable table from the binary data. */
for( x = 0; x < uxArraySize; x++ ) for( x = 0; ( x < uxArraySize ) && ( xOutputBufferFull == pdFALSE ); x++ )
{ {
/* What percentage of the total run time has the task used? /* What percentage of the total run time has the task used?
* This will always be rounded down to the nearest integer. * This will always be rounded down to the nearest integer.
* ulTotalRunTime has already been divided by 100. */ * ulTotalRunTime has already been divided by 100. */
ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
/* Write the task name to the string, padding with /* Is there enough space in the buffer to hold task name? */
* spaces so it can be printed in tabular form more if( ( uxConsumedBufferLength + configMAX_TASK_NAME_LEN ) <= uxBufferLength )
* easily. */
pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
if( ulStatsAsPercentage > 0UL )
{ {
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED /* Write the task name to the string, padding with
* spaces so it can be printed in tabular form more
* easily. */
pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
/* Do not count the terminating null character. */
uxConsumedBufferLength = uxConsumedBufferLength + ( configMAX_TASK_NAME_LEN - 1 );
/* Is there space left in the buffer? -1 is done because snprintf
* writes a terminating null character. So we are essentially
* checking if the buffer has space to write at least one non-null
* character. */
if( uxConsumedBufferLength < ( uxBufferLength - 1 ) )
{ {
sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); if( ulStatsAsPercentage > 0UL )
{
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
{
iSnprintfReturnValue = snprintf( pcWriteBuffer,
uxBufferLength - uxConsumedBufferLength,
"\t%lu\t\t%lu%%\r\n",
pxTaskStatusArray[ x ].ulRunTimeCounter,
ulStatsAsPercentage );
}
#else
{
/* sizeof( int ) == sizeof( long ) so a smaller
* printf() library can be used. */
iSnprintfReturnValue = snprintf( pcWriteBuffer,
uxBufferLength - uxConsumedBufferLength,
"\t%u\t\t%u%%\r\n",
( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter,
( unsigned int ) ulStatsAsPercentage ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
#endif /* ifdef portLU_PRINTF_SPECIFIER_REQUIRED */
}
else
{
/* If the percentage is zero here then the task has
* consumed less than 1% of the total run time. */
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
{
iSnprintfReturnValue = snprintf( pcWriteBuffer,
uxBufferLength - uxConsumedBufferLength,
"\t%lu\t\t<1%%\r\n",
pxTaskStatusArray[ x ].ulRunTimeCounter );
}
#else
{
/* sizeof( int ) == sizeof( long ) so a smaller
* printf() library can be used. */
iSnprintfReturnValue = snprintf( pcWriteBuffer,
uxBufferLength - uxConsumedBufferLength,
"\t%u\t\t<1%%\r\n",
( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
#endif /* ifdef portLU_PRINTF_SPECIFIER_REQUIRED */
}
uxCharsWrittenBySnprintf = prvSnprintfReturnValueToCharsWritten( iSnprintfReturnValue, uxBufferLength - uxConsumedBufferLength );
uxConsumedBufferLength += uxCharsWrittenBySnprintf;
pcWriteBuffer += uxCharsWrittenBySnprintf; /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
} }
#else else
{ {
/* sizeof( int ) == sizeof( long ) so a smaller xOutputBufferFull = pdTRUE;
* printf() library can be used. */
sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
} }
#endif
} }
else else
{ {
/* If the percentage is zero here then the task has xOutputBufferFull = pdTRUE;
* consumed less than 1% of the total run time. */
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
{
sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter );
}
#else
{
/* sizeof( int ) == sizeof( long ) so a smaller
* printf() library can be used. */
sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
#endif
} }
pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
} }
} }
else else
@ -7039,7 +7175,7 @@ static void prvResetNextTaskUnblockTime( void )
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
traceRETURN_vTaskGetRunTimeStats(); traceRETURN_vTaskGetRunTimeStatistics();
} }
#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ #endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */