This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
FreeRTOS-Kernel/FreeRTOS/Demo/WIN32-MingW/code_coverage_additions.c
Richard Barry aec45f2479 Import the code coverage test additions from the (unpublished) Visual Studio project to the (published) MingW/Eclipse project.
Update the MingW/Eclipse project to add a code coverage build configuration in addition to the existing Debug build configuration.
Update StreamBufferDemo.c so functions are called directly, rather than via configASSERT(), so their code coverage can be measured when configASSERT() is not defined.
In the Win32 port, replace the call to TerminateProcess() in vPortEndScheduler() with exit( 0 ) - which triggers the writing of the code coverage data to the disk.
Fix bug in ucStreamBufferGetStreamBufferType() - which is only used by the Percepio trace tool.
Update the line within vTaskStartScheduler() that was setting xTickCount to 0 to instead set it to configINITIAL_TICK_COUNT.
2018-03-14 15:58:47 +00:00

595 lines
17 KiB
C

/*
* FreeRTOS Kernel V10.0.1
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* Contains sundry tests to exercise code that is not touched by the standard
* demo tasks (which are predominantly test tasks). Some tests are incldued
* here because they can only be executed when configASSERT() is not defined.
*/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "event_groups.h"
#include "semphr.h"
#include "stream_buffer.h"
#include "message_buffer.h"
/*-----------------------------------------------------------*/
/*
* Try creating static objects with one of the mandatory parameters set to NULL.
* This can't be done in the standard demos as asserts() will get hit.
*/
static BaseType_t prvStaticAllocationsWithNullBuffers( void );
/*
* Code coverage analysis is performed with tracing turned off, so this
* function executes the trace specific utility functions that would not
* otherwise be executed..
*/
static BaseType_t prvTraceUtils( void );
/*
* The queue peek standard demo does not cover the case where an attempt to peek
* times out, so test that case.
*/
static BaseType_t prvPeekTimeout( void );
/*
* Calls various interrupt safe functions designed to query the state of a
* queue.
*/
static BaseType_t prvQueueQueryFromISR( void );
/*
* Hits a few paths in tasks state and status query functions not otherwise hit
* by standard demo and test files.
*/
static BaseType_t prvTaskQueryFunctions( void );
/*
* None of the standard demo tasks use the task tags - exercise them here.
*/
static BaseType_t prvTaskTags( void );
/*
* Exercises a few of the query functions that are not otherwise exercised in
* the standard demo and test functions.
*/
static BaseType_t prvTimerQuery( void );
/*-----------------------------------------------------------*/
static BaseType_t prvStaticAllocationsWithNullBuffers( void )
{
uint32_t ulReturned = 0;
BaseType_t xReturn = pdPASS;
UBaseType_t uxDummy = 10;
/* Don't expect to create any of the objects as a NULL parameter is always
passed in place of a required buffer. Hence if all passes then none of the
|= will be against 0, and ulReturned will still be zero at the end of this
function. */
ulReturned |= ( uint32_t ) xEventGroupCreateStatic( NULL );
/* Try creating a task twice, once with puxStackBuffer NULL, and once with
pxTaskBuffer NULL. */
ulReturned |= ( uint32_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
"Dummy", /* Task name. */
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY,
NULL,
( StaticTask_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
ulReturned |= ( uint32_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
"Dummy", /* Task name. */
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY,
( StackType_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
NULL );
ulReturned |= ( uint32_t ) xQueueCreateStatic( uxDummy,
uxDummy,
( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
NULL );
/* Try creating a stream buffer twice, once with pucStreamBufferStorageArea
set to NULL, and once with pxStaticStreamBuffer set to NULL. */
ulReturned |= ( uint32_t ) xStreamBufferCreateStatic( uxDummy,
uxDummy,
NULL,
( StaticStreamBuffer_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
ulReturned |= ( uint32_t ) xStreamBufferCreateStatic( uxDummy,
uxDummy,
( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
NULL );
/* Try to create a task with a stack that is too large to be allocated. */
if( xTaskCreate( NULL, "TooLarge", configTOTAL_HEAP_SIZE, NULL, tskIDLE_PRIORITY, NULL ) != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY )
{
xReturn = pdFAIL;
}
if( ulReturned != 0 )
{
/* Something returned a non-NULL value. */
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvTraceUtils( void )
{
EventGroupHandle_t xEventGroup;
QueueHandle_t xQueue;
BaseType_t xReturn = pdPASS;
const UBaseType_t xNumber = ( UBaseType_t ) 100, xQueueLength = ( UBaseType_t ) 1;
UBaseType_t uxValue;
TaskHandle_t xTaskHandle;
StreamBufferHandle_t xStreamBuffer;
MessageBufferHandle_t xMessageBuffer;
/* Exercise the event group trace utilities. */
xEventGroup = xEventGroupCreate();
if( xEventGroup != NULL )
{
vEventGroupSetNumber( xEventGroup, xNumber );
if( uxEventGroupGetNumber( NULL ) != 0 )
{
xReturn = pdFAIL;
}
if( uxEventGroupGetNumber( xEventGroup ) != xNumber )
{
xReturn = pdFAIL;
}
vEventGroupDelete( xEventGroup );
}
else
{
xReturn = pdFAIL;
}
/* Exercise the queue trace utilities. */
xQueue = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( uxValue ) );
if( xQueue != NULL )
{
vQueueSetQueueNumber( xQueue, xNumber );
if( uxQueueGetQueueNumber( xQueue ) != xNumber )
{
xReturn = pdFAIL;
}
if( ucQueueGetQueueType( xQueue ) != queueQUEUE_TYPE_BASE )
{
xReturn = pdFAIL;
}
vQueueDelete( xQueue );
}
else
{
xReturn = pdFAIL;
}
/* Exercise the task trace utilities. Value of 100 is arbitrary, just want
to check the value that is set is also read back. */
uxValue = 100;
xTaskHandle = xTaskGetCurrentTaskHandle();
vTaskSetTaskNumber( xTaskHandle, uxValue );
if( uxTaskGetTaskNumber( xTaskHandle ) != uxValue )
{
xReturn = pdFAIL;
}
if( uxTaskGetTaskNumber( NULL ) != 0 )
{
xReturn = pdFAIL;
}
/* Timer trace util functions are exercised in prvTimerQuery(). */
/* Exercise the stream buffer utilities. Try creating with a trigger level
of 0, it should then get capped to 1. */
xStreamBuffer = xStreamBufferCreate( sizeof( uint32_t ), 0 );
if( xStreamBuffer != NULL )
{
vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxValue );
if( uxStreamBufferGetStreamBufferNumber( xStreamBuffer ) != uxValue )
{
xReturn = pdFALSE;
}
if( ucStreamBufferGetStreamBufferType( xStreamBuffer ) != 0 )
{
/* "Is Message Buffer" flag should have been 0. */
xReturn = pdFALSE;
}
vStreamBufferDelete( xStreamBuffer );
}
else
{
xReturn = pdFALSE;
}
xMessageBuffer = xMessageBufferCreate( sizeof( uint32_t ) );
if( xMessageBuffer != NULL )
{
if( ucStreamBufferGetStreamBufferType( xMessageBuffer ) == 0 )
{
/* "Is Message Buffer" flag should have been 1. */
xReturn = pdFALSE;
}
vMessageBufferDelete( xMessageBuffer );
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvPeekTimeout( void )
{
QueueHandle_t xHandle;
const UBaseType_t xQueueLength = 1;
BaseType_t xReturn = pdPASS;
TickType_t xBlockTime = ( TickType_t ) 2;
UBaseType_t uxReceived;
/* Create the queue just to try peeking it while it is empty. */
xHandle = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( xQueueLength ) );
if( xHandle != NULL )
{
if( uxQueueMessagesWaiting( xHandle ) != 0 )
{
xReturn = pdFAIL;
}
/* Ensure peeking from the queue times out as the queue is empty. */
if( xQueuePeek( xHandle, &uxReceived, xBlockTime ) != pdFALSE )
{
xReturn = pdFAIL;
}
vQueueDelete( xHandle );
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvQueueQueryFromISR( void )
{
BaseType_t xReturn = pdPASS, xValue = 1;
const UBaseType_t xISRQueueLength = ( UBaseType_t ) 1;
const char *pcISRQueueName = "ISRQueue";
QueueHandle_t xISRQueue = NULL;
xISRQueue = xQueueCreate( xISRQueueLength, ( UBaseType_t ) sizeof( BaseType_t ) );
if( xISRQueue != NULL )
{
vQueueAddToRegistry( xISRQueue, pcISRQueueName );
if( strcmp( pcQueueGetName( xISRQueue ), pcISRQueueName ) )
{
xReturn = pdFAIL;
}
/* Expect the queue to be empty here. */
if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 0 )
{
xReturn = pdFAIL;
}
if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdTRUE )
{
xReturn = pdFAIL;
}
if( xQueueIsQueueFullFromISR( xISRQueue ) != pdFALSE )
{
xReturn = pdFAIL;
}
/* Now fill the queue - it only has one space. */
if( xQueueSendFromISR( xISRQueue, &xValue, NULL ) != pdPASS )
{
xReturn = pdFAIL;
}
/* Check it now reports as full. */
if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 1 )
{
xReturn = pdFAIL;
}
if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdFALSE )
{
xReturn = pdFAIL;
}
if( xQueueIsQueueFullFromISR( xISRQueue ) != pdTRUE )
{
xReturn = pdFAIL;
}
vQueueDelete( xISRQueue );
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvTaskQueryFunctions( void )
{
static TaskStatus_t xStatus, *pxStatusArray;
TaskHandle_t xTimerTask, xIdleTask;
BaseType_t xReturn = pdPASS;
UBaseType_t uxNumberOfTasks, uxReturned, ux;
uint32_t ulTotalRunTime1, ulTotalRunTime2;
const uint32_t ulRunTimeTollerance = ( uint32_t ) 0xfff;
/* Obtain task status with the stack high water mark and without the
state. */
vTaskGetInfo( NULL, &xStatus, pdTRUE, eRunning );
if( uxTaskGetStackHighWaterMark( NULL ) != xStatus.usStackHighWaterMark )
{
xReturn = pdFAIL;
}
/* Now obtain a task status without the high water mark but with the state,
which in the case of the idle task should be Read. */
xTimerTask = xTimerGetTimerDaemonTaskHandle();
vTaskSuspend( xTimerTask ); /* Should never suspend Timer task normally!. */
vTaskGetInfo( xTimerTask, &xStatus, pdFALSE, eInvalid );
if( xStatus.eCurrentState != eSuspended )
{
xReturn = pdFAIL;
}
if( xStatus.uxBasePriority != uxTaskPriorityGetFromISR( xTimerTask ) )
{
xReturn = pdFAIL;
}
if( xStatus.uxBasePriority != ( configMAX_PRIORITIES - 1 ) )
{
xReturn = pdFAIL;
}
xTaskResumeFromISR( xTimerTask );
vTaskGetInfo( xTimerTask, &xStatus, pdTRUE, eInvalid );
if( ( xStatus.eCurrentState != eReady ) && ( xStatus.eCurrentState != eBlocked ) )
{
xReturn = pdFAIL;
}
if( uxTaskGetStackHighWaterMark( xTimerTask ) != xStatus.usStackHighWaterMark )
{
xReturn = pdFAIL;
}
/* Attempting to abort a delay in the idle task should be guaranteed to
fail as the idle task should never block. */
xIdleTask = xTaskGetIdleTaskHandle();
if( xTaskAbortDelay( xIdleTask ) != pdFAIL )
{
xReturn = pdFAIL;
}
/* Create an array of task status objects large enough to hold information
on the number of tasks at this time - note this may change at any time if
higher priority tasks are executing and creating tasks. */
uxNumberOfTasks = uxTaskGetNumberOfTasks();
pxStatusArray = ( TaskStatus_t * ) pvPortMalloc( uxNumberOfTasks * sizeof( TaskStatus_t ) );
if( pxStatusArray != NULL )
{
/* Pass part of the array into uxTaskGetSystemState() to ensure it doesn't
try using more space than there is available. */
uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks / ( UBaseType_t ) 2, NULL );
if( uxReturned != ( UBaseType_t ) 0 )
{
xReturn = pdFAIL;
}
/* Now do the same but passing in the complete array size, this is done
twice to check for a difference in the total run time. */
uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime1 );
memset( ( void * ) pxStatusArray, 0xaa, uxNumberOfTasks * sizeof( TaskStatus_t ) );
uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime2 );
if( ( ulTotalRunTime2 - ulTotalRunTime1 ) > ulRunTimeTollerance )
{
xReturn = pdFAIL;
}
/* Basic santity check of array contents. */
for( ux = 0; ux < uxReturned; ux++ )
{
if( pxStatusArray[ ux ].eCurrentState >= ( UBaseType_t ) eInvalid )
{
xReturn = pdFAIL;
}
if( pxStatusArray[ ux ].uxCurrentPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
xReturn = pdFAIL;
}
}
vPortFree( pxStatusArray );
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvDummyTagFunction( void *pvParameter )
{
return ( BaseType_t ) pvParameter;
}
/*-----------------------------------------------------------*/
static BaseType_t prvTaskTags( void )
{
BaseType_t xReturn = pdPASS, xParameter = ( BaseType_t ) 0xDEADBEEF;
TaskHandle_t xTask;
/* First try with the handle of a different task. Use the timer task for
convenience. */
xTask = xTimerGetTimerDaemonTaskHandle();
vTaskSetApplicationTaskTag( xTask, prvDummyTagFunction );
if( xTaskGetApplicationTaskTag( xTask ) != prvDummyTagFunction )
{
xReturn = pdFAIL;
}
else
{
if( xTaskCallApplicationTaskHook( xTask, ( void * ) xParameter ) != xParameter )
{
xReturn = pdFAIL;
}
if( xTaskCallApplicationTaskHook( xTask, ( void * ) NULL ) != pdFAIL )
{
xReturn = pdFAIL;
}
}
/* Now try with a NULL handle, so using this task. */
vTaskSetApplicationTaskTag( NULL, NULL );
if( xTaskGetApplicationTaskTag( NULL ) != NULL )
{
xReturn = pdFAIL;
}
vTaskSetApplicationTaskTag( NULL, prvDummyTagFunction );
if( xTaskGetApplicationTaskTag( NULL ) != prvDummyTagFunction )
{
xReturn = pdFAIL;
}
else
{
if( xTaskCallApplicationTaskHook( NULL, ( void * ) xParameter ) != xParameter )
{
xReturn = pdFAIL;
}
if( xTaskCallApplicationTaskHook( NULL, ( void * ) NULL ) != pdFAIL )
{
xReturn = pdFAIL;
}
}
vTaskSetApplicationTaskTag( NULL, NULL );
if( xTaskGetApplicationTaskTag( NULL ) != NULL )
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvTimerQuery( void )
{
TimerHandle_t xTimer;
BaseType_t xReturn = pdPASS;
const char *pcTimerName = "TestTimer";
const TickType_t xTimerPeriod = ( TickType_t ) 100;
const UBaseType_t uxTimerNumber = ( UBaseType_t ) 55;
xTimer = xTimerCreate( pcTimerName,
xTimerPeriod,
pdFALSE,
( void * ) xTimerPeriod,
NULL ); /* Not actually going to start timer so NULL callback is ok. */
if( xTimer != NULL )
{
if( xTimerGetPeriod( xTimer ) != xTimerPeriod )
{
xReturn = pdFAIL;
}
if( strcmp( pcTimerGetName( xTimer ), pcTimerName ) != 0 )
{
xReturn = pdFAIL;
}
vTimerSetTimerNumber( xTimer, uxTimerNumber );
if( uxTimerGetTimerNumber( xTimer ) != uxTimerNumber )
{
xReturn = pdFAIL;
}
xTimerDelete( xTimer, portMAX_DELAY );
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xRunCodeCoverageTestAdditions( void )
{
BaseType_t xReturn = pdPASS;
xReturn &= prvStaticAllocationsWithNullBuffers();
xReturn &= prvTraceUtils();
xReturn &= prvPeekTimeout();
xReturn &= prvQueueQueryFromISR();
xReturn &= prvTaskQueryFunctions();
xReturn &= prvTaskTags();
xReturn &= prvTimerQuery();
return xReturn;
}
/*-----------------------------------------------------------*/