1 /*
2 * FreeRTOS V202212.00
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
24 *
25 */
26
27 /*
28 * Contains sundry tests to exercise code that is not touched by the standard
29 * demo tasks (which are predominantly test tasks). Some tests are included
30 * here because they can only be executed when configASSERT() is not defined.
31 */
32
33 #include <string.h>
34
35 #include "FreeRTOS.h"
36 #include "task.h"
37 #include "timers.h"
38 #include "event_groups.h"
39 #include "semphr.h"
40 #include "stream_buffer.h"
41 #include "message_buffer.h"
42
43 /*-----------------------------------------------------------*/
44
45 /*
46 * Try creating static objects with one of the mandatory parameters set to NULL.
47 * This can't be done in the standard demos as asserts() will get hit.
48 */
49 static BaseType_t prvStaticAllocationsWithNullBuffers( void );
50
51 /*
52 * Code coverage analysis is performed with tracing turned off, so this
53 * function executes the trace specific utility functions that would not
54 * otherwise be executed..
55 */
56 static BaseType_t prvTraceUtils( void );
57
58 /*
59 * The queue peek standard demo does not cover the case where an attempt to peek
60 * times out, so test that case.
61 */
62 static BaseType_t prvPeekTimeout( void );
63
64 /*
65 * Calls various interrupt safe functions designed to query the state of a
66 * queue.
67 */
68 static BaseType_t prvQueueQueryFromISR( void );
69
70 /*
71 * Hits a few paths in tasks state and status query functions not otherwise hit
72 * by standard demo and test files.
73 */
74 static BaseType_t prvTaskQueryFunctions( void );
75
76 /*
77 * None of the standard demo tasks use the task tags - exercise them here.
78 */
79 static BaseType_t prvTaskTags( void );
80
81 /*
82 * Exercises a few of the query functions that are not otherwise exercised in
83 * the standard demo and test functions.
84 */
85 static BaseType_t prvTimerQuery( void );
86
87 /*-----------------------------------------------------------*/
88
prvStaticAllocationsWithNullBuffers(void)89 static BaseType_t prvStaticAllocationsWithNullBuffers( void )
90 {
91 uintptr_t ulReturned = 0;
92 BaseType_t xReturn = pdPASS;
93 UBaseType_t uxDummy = 10;
94
95 /* Don't expect to create any of the objects as a NULL parameter is always
96 * passed in place of a required buffer. Hence if all passes then none of the
97 |= will be against 0, and ulReturned will still be zero at the end of this
98 * function. */
99 ulReturned |= ( uintptr_t ) xEventGroupCreateStatic( NULL );
100
101 /* Try creating a task twice, once with puxStackBuffer NULL, and once with
102 * pxTaskBuffer NULL. */
103 ulReturned |= ( uintptr_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
104 "Dummy", /* Task name. */
105 configMINIMAL_STACK_SIZE,
106 NULL,
107 tskIDLE_PRIORITY,
108 NULL,
109 ( StaticTask_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
110
111 ulReturned |= ( uintptr_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
112 "Dummy", /* Task name. */
113 configMINIMAL_STACK_SIZE,
114 NULL,
115 tskIDLE_PRIORITY,
116 ( StackType_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
117 NULL );
118
119 ulReturned |= ( uintptr_t ) xQueueCreateStatic( uxDummy,
120 uxDummy,
121 ( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
122 NULL );
123
124 /* Try creating a stream buffer twice, once with pucStreamBufferStorageArea
125 * set to NULL, and once with pxStaticStreamBuffer set to NULL. */
126 ulReturned |= ( uintptr_t ) xStreamBufferCreateStatic( uxDummy,
127 uxDummy,
128 NULL,
129 ( StaticStreamBuffer_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
130
131 ulReturned |= ( uintptr_t ) xStreamBufferCreateStatic( uxDummy,
132 uxDummy,
133 ( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
134 NULL );
135
136 if( ulReturned != 0 )
137 {
138 /* Something returned a non-NULL value. */
139 xReturn = pdFAIL;
140 }
141
142 return xReturn;
143 }
144 /*-----------------------------------------------------------*/
145
prvTraceUtils(void)146 static BaseType_t prvTraceUtils( void )
147 {
148 EventGroupHandle_t xEventGroup;
149 QueueHandle_t xQueue;
150 BaseType_t xReturn = pdPASS;
151 const UBaseType_t xNumber = ( UBaseType_t ) 100, xQueueLength = ( UBaseType_t ) 1;
152 UBaseType_t uxValue;
153 TaskHandle_t xTaskHandle;
154 StreamBufferHandle_t xStreamBuffer;
155 MessageBufferHandle_t xMessageBuffer;
156
157 /* Exercise the event group trace utilities. */
158 xEventGroup = xEventGroupCreate();
159
160 if( xEventGroup != NULL )
161 {
162 vEventGroupSetNumber( xEventGroup, xNumber );
163
164 if( uxEventGroupGetNumber( NULL ) != 0 )
165 {
166 xReturn = pdFAIL;
167 }
168
169 if( uxEventGroupGetNumber( xEventGroup ) != xNumber )
170 {
171 xReturn = pdFAIL;
172 }
173
174 vEventGroupDelete( xEventGroup );
175 }
176 else
177 {
178 xReturn = pdFAIL;
179 }
180
181 /* Exercise the queue trace utilities. */
182 xQueue = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( uxValue ) );
183
184 if( xQueue != NULL )
185 {
186 vQueueSetQueueNumber( xQueue, xNumber );
187
188 if( uxQueueGetQueueNumber( xQueue ) != xNumber )
189 {
190 xReturn = pdFAIL;
191 }
192
193 if( ucQueueGetQueueType( xQueue ) != queueQUEUE_TYPE_BASE )
194 {
195 xReturn = pdFAIL;
196 }
197
198 vQueueDelete( xQueue );
199 }
200 else
201 {
202 xReturn = pdFAIL;
203 }
204
205 /* Exercise the task trace utilities. Value of 100 is arbitrary, just want
206 * to check the value that is set is also read back. */
207 uxValue = 100;
208 xTaskHandle = xTaskGetCurrentTaskHandle();
209 vTaskSetTaskNumber( xTaskHandle, uxValue );
210
211 if( uxTaskGetTaskNumber( xTaskHandle ) != uxValue )
212 {
213 xReturn = pdFAIL;
214 }
215
216 if( uxTaskGetTaskNumber( NULL ) != 0 )
217 {
218 xReturn = pdFAIL;
219 }
220
221 /* Timer trace util functions are exercised in prvTimerQuery(). */
222
223
224 /* Exercise the stream buffer utilities. Try creating with a trigger level
225 * of 0, it should then get capped to 1. */
226 xStreamBuffer = xStreamBufferCreate( sizeof( uint32_t ), 0 );
227
228 if( xStreamBuffer != NULL )
229 {
230 vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxValue );
231
232 if( uxStreamBufferGetStreamBufferNumber( xStreamBuffer ) != uxValue )
233 {
234 xReturn = pdFALSE;
235 }
236
237 if( ucStreamBufferGetStreamBufferType( xStreamBuffer ) != 0 )
238 {
239 /* "Is Message Buffer" flag should have been 0. */
240 xReturn = pdFALSE;
241 }
242
243 vStreamBufferDelete( xStreamBuffer );
244 }
245 else
246 {
247 xReturn = pdFALSE;
248 }
249
250 xMessageBuffer = xMessageBufferCreate( sizeof( uint32_t ) );
251
252 if( xMessageBuffer != NULL )
253 {
254 if( ucStreamBufferGetStreamBufferType( xMessageBuffer ) == 0 )
255 {
256 /* "Is Message Buffer" flag should have been 1. */
257 xReturn = pdFALSE;
258 }
259
260 vMessageBufferDelete( xMessageBuffer );
261 }
262 else
263 {
264 xReturn = pdFALSE;
265 }
266
267 return xReturn;
268 }
269 /*-----------------------------------------------------------*/
270
prvPeekTimeout(void)271 static BaseType_t prvPeekTimeout( void )
272 {
273 QueueHandle_t xHandle;
274 const UBaseType_t xQueueLength = 1;
275 BaseType_t xReturn = pdPASS;
276 TickType_t xBlockTime = ( TickType_t ) 2;
277 UBaseType_t uxReceived;
278
279 /* Create the queue just to try peeking it while it is empty. */
280 xHandle = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( xQueueLength ) );
281
282 if( xHandle != NULL )
283 {
284 if( uxQueueMessagesWaiting( xHandle ) != 0 )
285 {
286 xReturn = pdFAIL;
287 }
288
289 /* Ensure peeking from the queue times out as the queue is empty. */
290 if( xQueuePeek( xHandle, &uxReceived, xBlockTime ) != pdFALSE )
291 {
292 xReturn = pdFAIL;
293 }
294
295 vQueueDelete( xHandle );
296 }
297 else
298 {
299 xReturn = pdFAIL;
300 }
301
302 return xReturn;
303 }
304 /*-----------------------------------------------------------*/
305
prvQueueQueryFromISR(void)306 static BaseType_t prvQueueQueryFromISR( void )
307 {
308 BaseType_t xReturn = pdPASS, xValue = 1;
309 const UBaseType_t xISRQueueLength = ( UBaseType_t ) 1;
310 const char * pcISRQueueName = "ISRQueue";
311 QueueHandle_t xISRQueue = NULL;
312
313 xISRQueue = xQueueCreate( xISRQueueLength, ( UBaseType_t ) sizeof( BaseType_t ) );
314
315 if( xISRQueue != NULL )
316 {
317 vQueueAddToRegistry( xISRQueue, pcISRQueueName );
318
319 if( strcmp( pcQueueGetName( xISRQueue ), pcISRQueueName ) )
320 {
321 xReturn = pdFAIL;
322 }
323
324 /* Expect the queue to be empty here. */
325 if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 0 )
326 {
327 xReturn = pdFAIL;
328 }
329
330 if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdTRUE )
331 {
332 xReturn = pdFAIL;
333 }
334
335 if( xQueueIsQueueFullFromISR( xISRQueue ) != pdFALSE )
336 {
337 xReturn = pdFAIL;
338 }
339
340 /* Now fill the queue - it only has one space. */
341 if( xQueueSendFromISR( xISRQueue, &xValue, NULL ) != pdPASS )
342 {
343 xReturn = pdFAIL;
344 }
345
346 /* Check it now reports as full. */
347 if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 1 )
348 {
349 xReturn = pdFAIL;
350 }
351
352 if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdFALSE )
353 {
354 xReturn = pdFAIL;
355 }
356
357 if( xQueueIsQueueFullFromISR( xISRQueue ) != pdTRUE )
358 {
359 xReturn = pdFAIL;
360 }
361
362 vQueueDelete( xISRQueue );
363 }
364 else
365 {
366 xReturn = pdFAIL;
367 }
368
369 return xReturn;
370 }
371 /*-----------------------------------------------------------*/
372
prvTaskQueryFunctions(void)373 static BaseType_t prvTaskQueryFunctions( void )
374 {
375 static TaskStatus_t xStatus, * pxStatusArray;
376 TaskHandle_t xTimerTask, xIdleTask;
377 BaseType_t xReturn = pdPASS;
378 UBaseType_t uxNumberOfTasks, uxReturned, ux;
379 uint32_t ulTotalRunTime1, ulTotalRunTime2;
380 const uint32_t ulRunTimeTolerance = ( uint32_t ) 0xfff;
381
382 /* Obtain task status with the stack high water mark and without the
383 * state. */
384 vTaskGetInfo( NULL, &xStatus, pdTRUE, eRunning );
385
386 if( uxTaskGetStackHighWaterMark( NULL ) != xStatus.usStackHighWaterMark )
387 {
388 xReturn = pdFAIL;
389 }
390
391 if( uxTaskGetStackHighWaterMark2( NULL ) != ( configSTACK_DEPTH_TYPE ) xStatus.usStackHighWaterMark )
392 {
393 xReturn = pdFAIL;
394 }
395
396 /* Now obtain a task status without the high water mark but with the state,
397 * which in the case of the idle task should be Read. */
398 xTimerTask = xTimerGetTimerDaemonTaskHandle();
399 vTaskSuspend( xTimerTask ); /* Should never suspend Timer task normally!. */
400 vTaskGetInfo( xTimerTask, &xStatus, pdFALSE, eInvalid );
401
402 if( xStatus.eCurrentState != eSuspended )
403 {
404 xReturn = pdFAIL;
405 }
406
407 if( xStatus.uxBasePriority != uxTaskPriorityGetFromISR( xTimerTask ) )
408 {
409 xReturn = pdFAIL;
410 }
411
412 if( xStatus.uxBasePriority != ( configMAX_PRIORITIES - 1 ) )
413 {
414 xReturn = pdFAIL;
415 }
416
417 xTaskResumeFromISR( xTimerTask );
418 vTaskGetInfo( xTimerTask, &xStatus, pdTRUE, eInvalid );
419
420 if( ( xStatus.eCurrentState != eReady ) && ( xStatus.eCurrentState != eBlocked ) )
421 {
422 xReturn = pdFAIL;
423 }
424
425 if( uxTaskGetStackHighWaterMark( xTimerTask ) != xStatus.usStackHighWaterMark )
426 {
427 xReturn = pdFAIL;
428 }
429
430 if( uxTaskGetStackHighWaterMark2( xTimerTask ) != ( configSTACK_DEPTH_TYPE ) xStatus.usStackHighWaterMark )
431 {
432 xReturn = pdFAIL;
433 }
434
435 /* Attempting to abort a delay in the idle task should be guaranteed to
436 * fail as the idle task should never block. */
437 xIdleTask = xTaskGetIdleTaskHandle();
438
439 if( xTaskAbortDelay( xIdleTask ) != pdFAIL )
440 {
441 xReturn = pdFAIL;
442 }
443
444 /* Create an array of task status objects large enough to hold information
445 * on the number of tasks at this time - note this may change at any time if
446 * higher priority tasks are executing and creating tasks. */
447 uxNumberOfTasks = uxTaskGetNumberOfTasks();
448 pxStatusArray = ( TaskStatus_t * ) pvPortMalloc( uxNumberOfTasks * sizeof( TaskStatus_t ) );
449
450 if( pxStatusArray != NULL )
451 {
452 /* Pass part of the array into uxTaskGetSystemState() to ensure it doesn't
453 * try using more space than there is available. */
454 uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks / ( UBaseType_t ) 2, NULL );
455
456 if( uxReturned != ( UBaseType_t ) 0 )
457 {
458 xReturn = pdFAIL;
459 }
460
461 /* Now do the same but passing in the complete array size, this is done
462 * twice to check for a difference in the total run time. */
463 uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime1 );
464 memset( ( void * ) pxStatusArray, 0xaa, uxNumberOfTasks * sizeof( TaskStatus_t ) );
465 uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime2 );
466
467 if( ( ulTotalRunTime2 - ulTotalRunTime1 ) > ulRunTimeTolerance )
468 {
469 xReturn = pdFAIL;
470 }
471
472 /* Basic sanity check of array contents. */
473 for( ux = 0; ux < uxReturned; ux++ )
474 {
475 if( pxStatusArray[ ux ].eCurrentState >= ( UBaseType_t ) eInvalid )
476 {
477 xReturn = pdFAIL;
478 }
479
480 if( pxStatusArray[ ux ].uxCurrentPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
481 {
482 xReturn = pdFAIL;
483 }
484 }
485
486 vPortFree( pxStatusArray );
487 }
488 else
489 {
490 xReturn = pdFAIL;
491 }
492
493 return xReturn;
494 }
495 /*-----------------------------------------------------------*/
496
prvDummyTagFunction(void * pvParameter)497 static BaseType_t prvDummyTagFunction( void * pvParameter )
498 {
499 return ( BaseType_t ) pvParameter;
500 }
501 /*-----------------------------------------------------------*/
502
prvTaskTags(void)503 static BaseType_t prvTaskTags( void )
504 {
505 BaseType_t xReturn = pdPASS, xParameter = ( BaseType_t ) 0xDEADBEEF;
506 TaskHandle_t xTask;
507
508 /* First try with the handle of a different task. Use the timer task for
509 * convenience. */
510 xTask = xTimerGetTimerDaemonTaskHandle();
511
512 vTaskSetApplicationTaskTag( xTask, prvDummyTagFunction );
513
514 if( xTaskGetApplicationTaskTag( xTask ) != prvDummyTagFunction )
515 {
516 xReturn = pdFAIL;
517 }
518 else
519 {
520 if( xTaskCallApplicationTaskHook( xTask, ( void * ) xParameter ) != xParameter )
521 {
522 xReturn = pdFAIL;
523 }
524
525 if( xTaskCallApplicationTaskHook( xTask, ( void * ) NULL ) != pdFAIL )
526 {
527 xReturn = pdFAIL;
528 }
529 }
530
531 /* Try FromISR version too. */
532 if( xTaskGetApplicationTaskTagFromISR( xTask ) != prvDummyTagFunction )
533 {
534 xReturn = pdFAIL;
535 }
536
537 /* Now try with a NULL handle, so using this task. */
538 vTaskSetApplicationTaskTag( NULL, NULL );
539
540 if( xTaskGetApplicationTaskTag( NULL ) != NULL )
541 {
542 xReturn = pdFAIL;
543 }
544
545 if( xTaskGetApplicationTaskTagFromISR( NULL ) != NULL )
546 {
547 xReturn = pdFAIL;
548 }
549
550 vTaskSetApplicationTaskTag( NULL, prvDummyTagFunction );
551
552 if( xTaskGetApplicationTaskTag( NULL ) != prvDummyTagFunction )
553 {
554 xReturn = pdFAIL;
555 }
556 else
557 {
558 if( xTaskCallApplicationTaskHook( NULL, ( void * ) xParameter ) != xParameter )
559 {
560 xReturn = pdFAIL;
561 }
562
563 if( xTaskCallApplicationTaskHook( NULL, ( void * ) NULL ) != pdFAIL )
564 {
565 xReturn = pdFAIL;
566 }
567 }
568
569 /* Try FromISR version too. */
570 if( xTaskGetApplicationTaskTagFromISR( NULL ) != prvDummyTagFunction )
571 {
572 xReturn = pdFAIL;
573 }
574
575 vTaskSetApplicationTaskTag( NULL, NULL );
576
577 if( xTaskGetApplicationTaskTag( NULL ) != NULL )
578 {
579 xReturn = pdFAIL;
580 }
581
582 return xReturn;
583 }
584 /*-----------------------------------------------------------*/
585
prvTimerQuery(void)586 static BaseType_t prvTimerQuery( void )
587 {
588 TimerHandle_t xTimer;
589 BaseType_t xReturn = pdPASS;
590 const char * pcTimerName = "TestTimer";
591 const TickType_t xTimerPeriod = ( TickType_t ) 100;
592 const UBaseType_t uxTimerNumber = ( UBaseType_t ) 55;
593
594 xTimer = xTimerCreate( pcTimerName,
595 xTimerPeriod,
596 pdFALSE,
597 ( void * ) xTimerPeriod,
598 NULL ); /* Not actually going to start timer so NULL callback is ok. */
599
600 if( xTimer != NULL )
601 {
602 if( xTimerGetPeriod( xTimer ) != xTimerPeriod )
603 {
604 xReturn = pdFAIL;
605 }
606
607 if( strcmp( pcTimerGetName( xTimer ), pcTimerName ) != 0 )
608 {
609 xReturn = pdFAIL;
610 }
611
612 vTimerSetTimerNumber( xTimer, uxTimerNumber );
613
614 if( uxTimerGetTimerNumber( xTimer ) != uxTimerNumber )
615 {
616 xReturn = pdFAIL;
617 }
618
619 xTimerDelete( xTimer, portMAX_DELAY );
620 }
621 else
622 {
623 xReturn = pdFAIL;
624 }
625
626 return xReturn;
627 }
628 /*-----------------------------------------------------------*/
629
xRunCodeCoverageTestAdditions(void)630 BaseType_t xRunCodeCoverageTestAdditions( void )
631 {
632 BaseType_t xReturn = pdPASS;
633
634 xReturn &= prvStaticAllocationsWithNullBuffers();
635 xReturn &= prvTraceUtils();
636 xReturn &= prvPeekTimeout();
637 xReturn &= prvQueueQueryFromISR();
638 xReturn &= prvTaskQueryFunctions();
639 xReturn &= prvTaskTags();
640 xReturn &= prvTimerQuery();
641
642 return xReturn;
643 }
644 /*-----------------------------------------------------------*/
645