diff --git a/.github/lexicon.txt b/.github/lexicon.txt index d2ac65fe7..800def74d 100644 --- a/.github/lexicon.txt +++ b/.github/lexicon.txt @@ -1529,6 +1529,7 @@ prvinitialisenewstreambuffer prvinitialisenewtimer prvinsertblockintofreelist prvlockqueue +prvnotifyqueuesetcontainer prvportmalloc prvportresetpic prvprocesssimulatedinterrupts @@ -1617,6 +1618,7 @@ pvowner pvparameter pvparameters pvportmalloc +pvportmallocstack pvportrealloc pvreg pvrxdata @@ -1630,7 +1632,6 @@ pvyieldevent pwdtc pwm pwmc -pxtaskcode pxblock pxblocktoinsert pxcallbackfunction @@ -1687,6 +1688,7 @@ pxprevious pxpreviouswaketime pxqueue pxqueuebuffer +pxqueuesetcontainer pxramstack pxreadycoroutinelists pxreadytaskslists @@ -1706,6 +1708,7 @@ pxstreambuffercreatestatic pxtagvalue pxtask pxtaskbuffer +pxtaskcode pxtaskdefinition pxtaskstatus pxtaskstatusarray @@ -2652,7 +2655,6 @@ wu www wwwfreertos wxr -xtasktodelete xa xaa xaaaa @@ -3019,6 +3021,7 @@ xtaskswaitingforbits xtaskswaitingtermination xtaskswaitingtoreceive xtaskswaitingtosend +xtasktodelete xtasktonotify xtasktoquery xtasktoresume diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5ff4eefb..50c1b1871 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,3 +44,4 @@ jobs: - name: URL Checker run: | bash kernel/.github/actions/url_verifier.sh kernel + diff --git a/.github/workflows/git-secrets.yml b/.github/workflows/git-secrets.yml new file mode 100644 index 000000000..b78a79c45 --- /dev/null +++ b/.github/workflows/git-secrets.yml @@ -0,0 +1,24 @@ +name: git-secrets Check +on: + push: + pull_request: + workflow_dispatch: +jobs: + git-secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Checkout awslabs/git-secrets + uses: actions/checkout@v2 + with: + repository: awslabs/git-secrets + ref: master + path: git-secrets + - name: Install git-secrets + run: cd git-secrets && sudo make install && cd .. + - name: Run git-secrets + run: | + git-secrets --register-aws + git-secrets --scan diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 000000000..7c4fa8ffb --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,56 @@ +name: CMock Unit Tests +on: [push] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Checkout Parent Repo + uses: actions/checkout@v2 + with: + ref: master + repository: FreeRTOS/FreeRTOS + submodules: 'recursive' + fetch-depth: 1 + - name: Clone This Repo + uses: actions/checkout@v2 + with: + path: ./FreeRTOS/Source + + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: 3.8 + + - name: Install packages + run: | + sudo apt-get install lcov cflow ruby doxygen build-essential + - name: Run Unit Tests with ENABLE_SANITIZER=1 + run: | + make -C FreeRTOS/Test/CMock clean + make -C FreeRTOS/Test/CMock ENABLE_SANITIZER=1 run_col_formatted + - name: Run Unit Tests for coverage + run: | + make -C FreeRTOS/Test/CMock clean + make -C FreeRTOS/Test/CMock lcovhtml + lcov --config-file FreeRTOS/Test/CMock/lcovrc --summary FreeRTOS/Test/CMock/build/cmock_test.info > FreeRTOS/Test/CMock/build/cmock_test_summary.txt + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + files: FreeRTOS/Test/CMock/build/cmock_test.info + working-directory: . + root_dir: FreeRTOS/Source + flags: unittests + fail_ci_if_error: false + path_to_write_report: coverage/codecov_report.txt + verbose: false + - name: Archive code coverage data + uses: actions/upload-artifact@v2 + with: + name: coverage-data + path: FreeRTOS/Test/CMock/build/cmock_test* + - name: Archive code coverage html report + uses: actions/upload-artifact@v2 + with: + name: coverage-report + path: FreeRTOS/Test/CMock/build/coverage diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index 87c67d736..6c3e82646 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -896,6 +896,11 @@ #define configSUPPORT_DYNAMIC_ALLOCATION 1 #endif +#ifndef configSTACK_ALLOCATION_FROM_SEPARATE_HEAP + /* Defaults to 0 for backward compatibility. */ + #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 +#endif + #ifndef configSTACK_DEPTH_TYPE /* Defaults to uint16_t for backward compatibility, but can be overridden diff --git a/include/mpu_wrappers.h b/include/mpu_wrappers.h index a5c081ff7..6550c1e6a 100644 --- a/include/mpu_wrappers.h +++ b/include/mpu_wrappers.h @@ -29,7 +29,7 @@ /* This file redefines API functions to be called through a wrapper macro, but * only for ports that are using the MPU. */ -#ifdef portUSING_MPU_WRAPPERS +#if ( portUSING_MPU_WRAPPERS == 1 ) /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is * included from queue.c or task.c to prevent it from having an effect within diff --git a/include/portable.h b/include/portable.h index 4f4c1d52a..f836747f8 100644 --- a/include/portable.h +++ b/include/portable.h @@ -179,6 +179,14 @@ void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION; +#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 ) + void *pvPortMallocStack( size_t xSize ) PRIVILEGED_FUNCTION; + void vPortFreeStack( void *pv ) PRIVILEGED_FUNCTION; +#else + #define pvPortMallocStack pvPortMalloc + #define vPortFreeStack vPortFree +#endif + /* * Setup the hardware ready for the scheduler to take control. This generally * sets up a tick interrupt and sets timers for the correct tick frequency. diff --git a/include/task.h b/include/task.h index d2d1a1901..d17bef8e7 100644 --- a/include/task.h +++ b/include/task.h @@ -1795,8 +1795,10 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, * demo applications. Do not consider it to be part of the scheduler. * * vTaskList() calls uxTaskGetSystemState(), then formats part of the - * uxTaskGetSystemState() output into a human readable table that displays task - * names, states and stack usage. + * 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. * * vTaskList() has a dependency on the sprintf() C library function that might * bloat the code size, use a lot of stack, and provide different results on @@ -1932,9 +1934,8 @@ uint32_t ulTaskGetIdleRunTimeCounter( void ) PRIVILEGED_FUNCTION; * that way task notifications can be used to send data to a task, or be used as * light weight and fast binary or counting semaphores. * - * A task can use xTaskNotifyWaitIndexed() to [optionally] block to wait for a - * notification to be pending, or ulTaskNotifyTakeIndexed() to [optionally] block - * to wait for a notification value to have a non-zero value. The task does + * A task can use xTaskNotifyWaitIndexed() or ulTaskNotifyTakeIndexed() to + * [optionally] block to wait for a notification to be pending. The task does * not consume any CPU time while it is in the Blocked state. * * A notification sent to a task will remain pending until it is cleared by the @@ -2520,8 +2521,8 @@ void vTaskGenericNotifyGiveFromISR( TaskHandle_t xTaskToNotify, * value acts like a counting semaphore. * * A task can use ulTaskNotifyTakeIndexed() to [optionally] block to wait for - * the task's notification value to be non-zero. The task does not consume any - * CPU time while it is in the Blocked state. + * a notification. The task does not consume any CPU time while it is in the + * Blocked state. * * Where as xTaskNotifyWaitIndexed() will return when a notification is pending, * ulTaskNotifyTakeIndexed() will return when the task's notification value is diff --git a/list.c b/list.c index 17a4e903e..d1a59649e 100644 --- a/list.c +++ b/list.c @@ -158,6 +158,9 @@ void vListInsert( List_t * const pxList, * 4) Using a queue or semaphore before it has been initialised or * before the scheduler has been started (are interrupts firing * before vTaskStartScheduler() has been called?). + * 5) If the FreeRTOS port supports interrupt nesting then ensure that + * the priority of the tick interrupt is at or below + * configMAX_SYSCALL_INTERRUPT_PRIORITY. **********************************************************************/ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */ diff --git a/portable/GCC/ATMega323/portmacro.h b/portable/GCC/ATMega323/portmacro.h index 482fc8ea6..d02e39ea0 100644 --- a/portable/GCC/ATMega323/portmacro.h +++ b/portable/GCC/ATMega323/portmacro.h @@ -22,7 +22,6 @@ * https://www.FreeRTOS.org * https://github.com/FreeRTOS * - * 1 tab == 4 spaces! */ /* @@ -58,6 +57,8 @@ extern "C" { #define portSTACK_TYPE uint8_t #define portBASE_TYPE char +#define portPOINTER_SIZE_TYPE uint16_t + typedef portSTACK_TYPE StackType_t; typedef signed char BaseType_t; typedef unsigned char UBaseType_t; diff --git a/portable/RVDS/ARM_CM7/r0p1/port.c b/portable/RVDS/ARM_CM7/r0p1/port.c index 25e5f5aad..93c8bd59b 100644 --- a/portable/RVDS/ARM_CM7/r0p1/port.c +++ b/portable/RVDS/ARM_CM7/r0p1/port.c @@ -762,10 +762,10 @@ __asm uint32_t vPortGetIPSR( void ) * be set to a value equal to or numerically *higher* than * configMAX_SYSCALL_INTERRUPT_PRIORITY. * - * Interrupts that use the FreeRTOS API must not be left at their - * default priority of zero as that is the highest possible priority, + * Interrupts that use the FreeRTOS API must not be left at their + * default priority of zero as that is the highest possible priority, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, - * and therefore also guaranteed to be invalid. + * and therefore also guaranteed to be invalid. * * FreeRTOS maintains separate thread and ISR API functions to ensure * interrupt entry is as fast and simple as possible. diff --git a/queue.c b/queue.c index 7ed8e9878..6805cd050 100644 --- a/queue.c +++ b/queue.c @@ -342,8 +342,10 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, * variable of type StaticQueue_t or StaticSemaphore_t equals the size of * the real queue and semaphore structures. */ volatile size_t xSize = sizeof( StaticQueue_t ); - configASSERT( xSize == sizeof( Queue_t ) ); - ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ + + /* This assertion cannot be branch covered in unit tests */ + configASSERT( xSize == sizeof( Queue_t ) ); /* LCOV_EXCL_BR_LINE */ + ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ } #endif /* configASSERT_DEFINED */ @@ -398,7 +400,7 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, configASSERT( ( uxItemSize == 0 ) || ( uxQueueLength == ( xQueueSizeInBytes / uxItemSize ) ) ); /* Check for addition overflow. */ - configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes ); + configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes ); /* Allocate the queue and storage area. Justification for MISRA * deviation as follows: pvPortMalloc() always ensures returned memory @@ -561,6 +563,8 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, TaskHandle_t pxReturn; Queue_t * const pxSemaphore = ( Queue_t * ) xSemaphore; + configASSERT( xSemaphore ); + /* This function is called by xSemaphoreGetMutexHolder(), and should not * be called directly. Note: This is a good way of determining if the * calling task is the mutex holder, but not a good way of determining the @@ -944,15 +948,15 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* Unlocking the queue means queue events can effect the - * event list. It is possible that interrupts occurring now + * event list. It is possible that interrupts occurring now * remove this task from the event list again - but as the * scheduler is suspended the task will go onto the pending - * ready last instead of the actual ready list. */ + * ready list instead of the actual ready list. */ prvUnlockQueue( pxQueue ); /* Resuming the scheduler will move tasks from the pending * ready list into the ready list - so it is feasible that this - * task is already in a ready list before it yields - in which + * task is already in the ready list before it yields - in which * case the yield will not cause a context switch unless there * is also a higher priority task in the pending ready list. */ if( xTaskResumeAll() == pdFALSE ) @@ -1774,7 +1778,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, taskEXIT_CRITICAL(); /* Interrupts and other tasks can send to and receive from the queue - * now the critical section has been exited. */ + * now that the critical section has been exited. */ vTaskSuspendAll(); prvLockQueue( pxQueue ); @@ -2723,6 +2727,9 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { UBaseType_t ux; + configASSERT( xQueue ); + configASSERT( pcQueueName ); + /* See if there is an empty space in the registry. A NULL name denotes * a free slot. */ for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) @@ -2753,6 +2760,8 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) UBaseType_t ux; const char * pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + configASSERT( xQueue ); + /* Note there is nothing here to protect against another task adding or * removing entries from the registry while it is being searched. */ @@ -2781,6 +2790,8 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { UBaseType_t ux; + configASSERT( xQueue ); + /* See if the handle of the queue being unregistered in actually in the * registry. */ for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) @@ -2967,7 +2978,10 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) /* This function must be called form a critical section. */ - configASSERT( pxQueueSetContainer ); + /* The following line is not reachable in unit tests because every call + * to prvNotifyQueueSetContainer is preceded by a check that + * pxQueueSetContainer != NULL */ + configASSERT( pxQueueSetContainer ); /* LCOV_EXCL_BR_LINE */ configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) diff --git a/stream_buffer.c b/stream_buffer.c index 5c6a47e2c..0c4f429ce 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -49,7 +49,7 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ /* If the user has not provided application specific Rx notification macros, - * or #defined the notification macros away, them provide default implementations + * or #defined the notification macros away, then provide default implementations * that uses task notifications. */ /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */ #ifndef sbRECEIVE_COMPLETED @@ -267,7 +267,6 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, { pucAllocatedMemory = NULL; } - if( pucAllocatedMemory != NULL ) { @@ -466,7 +465,7 @@ BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, /* The trigger level is the number of bytes that must be in the stream * buffer before a task that is waiting for data is unblocked. */ - if( xTriggerLevel <= pxStreamBuffer->xLength ) + if( xTriggerLevel < pxStreamBuffer->xLength ) { pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; xReturn = pdPASS; @@ -525,14 +524,15 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, size_t xReturn, xSpace = 0; size_t xRequiredSpace = xDataLengthBytes; TimeOut_t xTimeOut; - - /* The maximum amount of space a stream buffer will ever report is its length - * minus 1. */ - const size_t xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; + size_t xMaxReportedSpace = 0; configASSERT( pvTxData ); configASSERT( pxStreamBuffer ); + /* The maximum amount of space a stream buffer will ever report is its length + * minus 1. */ + xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; + /* This send function is used to write to both message buffers and stream * buffers. If this is a message buffer then the space needed must be * increased by the amount of bytes needed to store the length of the diff --git a/tasks.c b/tasks.c index fc44c817d..988e32bdb 100644 --- a/tasks.c +++ b/tasks.c @@ -748,7 +748,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; /* Allocate space for the stack used by the task being created. * The base of the stack memory stored in the TCB so the task can * be deleted later if required. */ - pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ if( pxNewTCB->pxStack == NULL ) { @@ -763,7 +763,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; StackType_t * pxStack; /* Allocate space for the stack used by the task being created. */ - pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ + pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ if( pxStack != NULL ) { @@ -779,7 +779,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; { /* The stack cannot be used as the TCB was not created. Free * it again. */ - vPortFree( pxStack ); + vPortFreeStack( pxStack ); } } else @@ -2238,8 +2238,8 @@ BaseType_t xTaskResumeAll( void ) ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); - /* If the moved task has a priority higher than the current - * task then a yield must be performed. */ + /* If the moved task has a priority higher than or equal to + * the current task then a yield must be performed. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldPending = pdTRUE; @@ -2694,8 +2694,8 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) #if ( configUSE_PREEMPTION == 1 ) { /* Preemption is on, but a context switch should only be - * performed if the unblocked task has a priority that is - * equal to or higher than the currently executing task. */ + * performed if the unblocked task has a priority that is + * higher than the currently executing task. */ if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) { /* Pend the yield to be performed when the scheduler @@ -3950,7 +3950,7 @@ static void prvCheckTasksWaitingTermination( void ) { /* The task can only have been allocated dynamically - free both * the stack and TCB. */ - vPortFree( pxTCB->pxStack ); + vPortFreeStack( pxTCB->pxStack ); vPortFree( pxTCB ); } #elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ @@ -3962,7 +3962,7 @@ static void prvCheckTasksWaitingTermination( void ) { /* Both the stack and TCB were allocated dynamically, so both * must be freed. */ - vPortFree( pxTCB->pxStack ); + vPortFreeStack( pxTCB->pxStack ); vPortFree( pxTCB ); } else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ) @@ -4434,7 +4434,9 @@ static void prvResetNextTaskUnblockTime( void ) * * vTaskList() calls uxTaskGetSystemState(), then formats part of the * uxTaskGetSystemState() output into a human readable table that - * displays task names, states and stack usage. + * 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. * * vTaskList() has a dependency on the sprintf() C library function that * might bloat the code size, use a lot of stack, and provide different