Skip to content

Commit

Permalink
Add tests for the length caps within xStreamBufferSend(). (FreeRTOS#319)
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardBarry authored Oct 11, 2020
1 parent 00247a7 commit e07d681
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 21 deletions.
11 changes: 11 additions & 0 deletions FreeRTOS/Demo/Common/Minimal/MessageBufferDemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ UBaseType_t uxOriginalPriority;
( void ) xExpectedSpace;
( void ) xNextLength;

/* Try sending more bytes than possible, first using the FromISR version, then
with an infinite block time to ensure this task does not lock up. */
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), NULL );
configASSERT( xReturned == ( size_t ) 0 );
/* In case configASSERT() is not defined. */
( void ) xReturned;
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), portMAX_DELAY );
configASSERT( xReturned == ( size_t ) 0 );
/* In case configASSERT() is not defined. */
( void ) xReturned;

/* The buffer is 50 bytes long. When an item is added to the buffer an
additional 4 bytes are added to hold the item's size. That means adding
6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore,
Expand Down
150 changes: 130 additions & 20 deletions FreeRTOS/Demo/Common/Minimal/StreamBufferDemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ static void prvInterruptTriggerLevelTest( void *pvParameters );
static void prvSenderTask( void *pvParameters );

static StaticStreamBuffer_t xStaticStreamBuffers[ sbNUMBER_OF_ECHO_CLIENTS ];

/* The +1 is to make the test logic easier as the function that calculates the
free space will return one less than the actual free space - adding a 1 to the
actual length makes it appear to the tests as if the free space is returned as
it might logically be expected. Returning 1 less than the actual free space is
fine as it can never result in an overrun. */
static uint8_t ucBufferStorage[ sbNUMBER_OF_SENDER_TASKS ][ sbSTREAM_BUFFER_LENGTH_BYTES + 1 ];
static uint32_t ulSenderLoopCounters[ sbNUMBER_OF_SENDER_TASKS ] = { 0 };
#endif /* configSUPPORT_STATIC_ALLOCATION */
Expand Down Expand Up @@ -221,8 +227,9 @@ static void prvCheckExpectedState( BaseType_t xState )

static void prvSingleTaskTests( StreamBufferHandle_t xStreamBuffer )
{
size_t xReturned, xItem, xExpectedSpace;
size_t xReturned, xItem, xExpected, xExpectedSpaces, xExpectedBytes;
const size_t xMax6ByteMessages = sbSTREAM_BUFFER_LENGTH_BYTES / 6;
const size_t xTrueSize = ( sizeof( ucBufferStorage ) / sbNUMBER_OF_SENDER_TASKS );
const size_t x6ByteLength = 6, x17ByteLength = 17, xFullBufferSize = sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2;
uint8_t *pucFullBuffer, *pucData, *pucReadData;
TickType_t xTimeBeforeCall, xTimeAfterCall;
Expand All @@ -242,14 +249,122 @@ UBaseType_t uxOriginalPriority;
pucReadData = pucData + x17ByteLength;

/* Nothing has been added or removed yet, so expect the free space to be
exactly as created. */
xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );
exactly as created. Head and tail are both at 0. */
xExpectedSpaces = sbSTREAM_BUFFER_LENGTH_BYTES;
xExpectedBytes = 0;
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );

/* Add a single item - number of bytes available should go up by one and spaces
available down by one. Head is in front of tail. */
xExpectedSpaces--;
xExpectedBytes++;
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == sizeof( *pucData ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );

/* Now fill the buffer by adding another 29 bytes. Head is 30 tail is at 0. */
xExpectedSpaces -= 29;
xExpectedBytes += 29;
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, ( sbSTREAM_BUFFER_LENGTH_BYTES - 1 ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == ( sbSTREAM_BUFFER_LENGTH_BYTES - 1 ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );

/* Should not be able to add another byte now. */
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == ( size_t ) 0 );

/* Remove a byte so the tail pointer moves off 0. Head pointer remains at the
end of the buffer. */
xExpectedSpaces += 1;
xExpectedBytes -= 1;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == sizeof( *pucData ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );

/* Should be able to add another byte to fill the buffer again now. */
xExpectedSpaces -= 1;
xExpectedBytes += 1;
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == sizeof( *pucData ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );

/* Now the head pointer is behind the tail pointer. Read another 29 bytes so
the tail pointer moves to the end of the buffer. */
xExpectedSpaces += 29;
xExpectedBytes -= 29;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, ( size_t ) 29, ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == ( size_t ) 29 );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );

/* Read out one more byte to wrap the tail back around to the start, to get back
to where we started. */
xExpectedSpaces += 1;
xExpectedBytes -= 1;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
prvCheckExpectedState( xReturned == sizeof( *pucData ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedBytes );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );

/* Try filling the message buffer in one write, blocking indefinitely. Expect to
have written one byte less. */
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY );
xExpectedSpaces = ( size_t ) 0;
prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == xExpectedSpaces );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );

/* Empty the buffer again ready for the rest of the tests. Again block
indefinitely to ensure reading more than there can possible be won't lock this
task up, so expect to actually receive one byte less than requested. */
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY );
prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == sbSTREAM_BUFFER_LENGTH_BYTES );
xExpected = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == ( size_t ) 0 );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );


/* The buffer is 30 bytes long. 6 5 byte messages should fit before the
buffer is completely full. */
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
{
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
Expand All @@ -270,16 +385,15 @@ UBaseType_t uxOriginalPriority;

/* The space in the buffer will have reduced by the amount of user data
written into the buffer. */
xExpectedSpace -= x6ByteLength;
xExpected -= x6ByteLength;
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpectedSpace );
prvCheckExpectedState( xReturned == xExpected );
xReturned = xStreamBufferBytesAvailable( xStreamBuffer );
/* +1 as it is zero indexed. */
prvCheckExpectedState( xReturned == ( ( xItem + 1 ) * x6ByteLength ) );
}

/* Now the buffer should be full, and attempting to add anything will should
fail. */
/* Now the buffer should be full, and attempting to add anything should fail. */
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), sbDONT_BLOCK );
prvCheckExpectedState( xReturned == 0 );
Expand Down Expand Up @@ -321,17 +435,17 @@ UBaseType_t uxOriginalPriority;

/* The space in the buffer will have increased by the amount of user
data removed from the buffer. */
xExpectedSpace += x6ByteLength;
xExpected += x6ByteLength;
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpectedSpace );
prvCheckExpectedState( xReturned == xExpected );
xReturned = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == ( sbSTREAM_BUFFER_LENGTH_BYTES - xExpectedSpace ) );
prvCheckExpectedState( xReturned == ( sbSTREAM_BUFFER_LENGTH_BYTES - xExpected ) );
}

/* The buffer should be empty again. */
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xExpected == sbSTREAM_BUFFER_LENGTH_BYTES );

/* Reading with a timeout should also fail after the appropriate time. The
priority is temporarily boosted in this part of the test to keep the
Expand All @@ -348,7 +462,7 @@ UBaseType_t uxOriginalPriority;

/* In the next loop 17 bytes are written to then read out on each
iteration. As 30 is not divisible by 17 the data will wrap around. */
xExpectedSpace = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength;
xExpected = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength;

for( xItem = 0; xItem < 100; xItem++ )
{
Expand All @@ -362,7 +476,7 @@ UBaseType_t uxOriginalPriority;
/* The space in the buffer will have reduced by the amount of user data
written into the buffer. */
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpectedSpace );
prvCheckExpectedState( xReturned == xExpected );
xReturned = xStreamBufferBytesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == x17ByteLength );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
Expand Down Expand Up @@ -430,12 +544,8 @@ UBaseType_t uxOriginalPriority;

/* Try writing more bytes than there is space. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xTimeBeforeCall = xTaskGetTickCount();
xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, xMinimalBlockTime );
xTimeAfterCall = xTaskGetTickCount();
vTaskPrioritySet( NULL, uxOriginalPriority );
prvCheckExpectedState( ( xTimeAfterCall - xTimeBeforeCall ) >= xMinimalBlockTime );
prvCheckExpectedState( ( xTimeAfterCall - xTimeBeforeCall ) < ( xMinimalBlockTime + xAllowableMargin ) );
prvCheckExpectedState( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );
Expand Down Expand Up @@ -945,7 +1055,7 @@ BaseType_t xErrorDetected = pdFALSE;
each loop to ensure the interrupt that sends to the stream buffer
detects it needs to start sending from the start of the strin again.. */
vTaskDelay( xCycleBlockTime );

/* Create the stream buffer that will be used from inside the tick
interrupt. */
memset( ucRxData, 0x00, sizeof( ucRxData ) );
Expand Down
2 changes: 1 addition & 1 deletion FreeRTOS/Source
Submodule Source updated 117 files

0 comments on commit e07d681

Please sign in to comment.