From 035423eb371f3cdd2c9894611777ca573a704e02 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 31 Aug 2023 22:24:06 +0800 Subject: [PATCH] refactor(freertos/idf): Move task creation "PinnedToCore" API to addition headers This commit moves/merges the IDF FreeRTOS "PinnedToCore" task creation functions from tasks.c/task.h to idf_additions.h/freertos_task_c_additions.h. Also updated FreeRTOS Mock component to provide mocks for "idf_additions.h" headers for our mock tests. --- .../FreeRTOS-Kernel/include/freertos/task.h | 260 ++++-------------- components/freertos/FreeRTOS-Kernel/tasks.c | 152 ---------- .../freertos_tasks_c_additions.h | 212 +++++++++++--- .../include/freertos/idf_additions.h | 39 +-- components/freertos/linker.lf | 2 - components/freertos/linker_common.lf | 5 +- tools/mocks/freertos/CMakeLists.txt | 3 + 7 files changed, 257 insertions(+), 416 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel/include/freertos/task.h index 05603c02e9..22992e565b 100644 --- a/components/freertos/FreeRTOS-Kernel/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel/include/freertos/task.h @@ -285,204 +285,6 @@ typedef enum * TASK CREATION API *----------------------------------------------------------*/ -/** - * Create a new task with a specified affinity and add it to the list of tasks - * that are ready to run. - * - * This function is similar to xTaskCreate, but allows setting task affinity - * in SMP system. - * - * @param pxTaskCode Pointer to the task entry function. Tasks - * must be implemented to never return (i.e. continuous loop), or should be - * terminated using vTaskDelete function. - * - * @param pcName A descriptive name for the task. This is mainly used to - * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default - * is 16. - * - * @param usStackDepth The size of the task stack specified as the number of - * bytes. Note that this differs from vanilla FreeRTOS. - * - * @param pvParameters Pointer that will be used as the parameter for the task - * being created. - * - * @param uxPriority The priority at which the task should run. Systems that - * include MPU support can optionally create tasks in a privileged (system) - * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For - * example, to create a privileged task at priority 2 the uxPriority parameter - * should be set to ( 2 | portPRIVILEGE_BIT ). - * - * @param[out] pvCreatedTask Used to pass back a handle by which the created task - * can be referenced. - * - * @param xCoreID If the value is tskNO_AFFINITY, the created task is not - * pinned to any CPU, and the scheduler can run it on any core available. - * Values 0 or 1 indicate the index number of the CPU which the task should - * be pinned to. Specifying values larger than (configNUM_CORES - 1) will - * cause the function to fail. - * - * @return pdPASS if the task was successfully created and added to a ready - * list, otherwise an error code defined in the file projdefs.h - * - * @note If program uses thread local variables (ones specified with "__thread" keyword) - * then storage for them will be allocated on the task's stack. - * - * Example usage: - * @code{c} - * // Task to be created. - * void vTaskCode( void * pvParameters ) - * { - * for( ;; ) - * { - * // Task code goes here. - * } - * } - * - * // Function that creates a task. - * void vOtherFunction( void ) - * { - * static uint8_t ucParameterToPass; - * TaskHandle_t xHandle = NULL; - * - * // Create the task pinned to core 0, storing the handle. Note that the passed parameter ucParameterToPass - * // must exist for the lifetime of the task, so in this case is declared static. If it was just an - * // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time - * // the new task attempts to access it. - * xTaskCreatePinnedToCore( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle, 0 ); - * configASSERT( xHandle ); - * - * // Use the handle to delete the task. - * if( xHandle != NULL ) - * { - * vTaskDelete( xHandle ); - * } - * } - * @endcode - * @cond !DOC_SINGLE_GROUP - * \defgroup xTaskCreatePinnedToCore xTaskCreatePinnedToCore - * @endcond - * \ingroup Tasks - */ -#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, - const char * const pcName, - const configSTACK_DEPTH_TYPE usStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t * const pvCreatedTask, - const BaseType_t xCoreID ); -#endif - -/** - * Create a new task with a specified affinity and add it to the list of tasks - * that are ready to run. - * - * This function is similar to xTaskCreateStatic, but allows specifying - * task affinity in an SMP system. - * - * @param pxTaskCode Pointer to the task entry function. Tasks - * must be implemented to never return (i.e. continuous loop), or should be - * terminated using vTaskDelete function. - * - * @param pcName A descriptive name for the task. This is mainly used to - * facilitate debugging. The maximum length of the string is defined by - * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. - * - * @param ulStackDepth The size of the task stack specified as the number of - * bytes. Note that this differs from vanilla FreeRTOS. - * - * @param pvParameters Pointer that will be used as the parameter for the task - * being created. - * - * @param uxPriority The priority at which the task will run. - * - * @param pxStackBuffer Must point to a StackType_t array that has at least - * ulStackDepth indexes - the array will then be used as the task's stack, - * removing the need for the stack to be allocated dynamically. - * - * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will - * then be used to hold the task's data structures, removing the need for the - * memory to be allocated dynamically. - * - * @param xCoreID If the value is tskNO_AFFINITY, the created task is not - * pinned to any CPU, and the scheduler can run it on any core available. - * Values 0 or 1 indicate the index number of the CPU which the task should - * be pinned to. Specifying values larger than (configNUM_CORES - 1) will - * cause the function to fail. - * - * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will - * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer - * are NULL then the task will not be created and - * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. - * - * Example usage: - * @code{c} - * - * // Dimensions the buffer that the task being created will use as its stack. - * // NOTE: This is the number of words the stack will hold, not the number of - * // bytes. For example, if each stack item is 32-bits, and this is set to 100, - * // then 400 bytes (100 * 32-bits) will be allocated. - * #define STACK_SIZE 200 - * - * // Structure that will hold the TCB of the task being created. - * StaticTask_t xTaskBuffer; - * - * // Buffer that the task being created will use as its stack. Note this is - * // an array of StackType_t variables. The size of StackType_t is dependent on - * // the RTOS port. - * StackType_t xStack[ STACK_SIZE ]; - * - * // Function that implements the task being created. - * void vTaskCode( void * pvParameters ) - * { - * // The parameter value is expected to be 1 as 1 is passed in the - * // pvParameters value in the call to xTaskCreateStaticPinnedToCore(). - * configASSERT( ( uint32_t ) pvParameters == 1UL ); - * - * for( ;; ) - * { - * // Task code goes here. - * } - * } - * - * // Function that creates a task. - * void vOtherFunction( void ) - * { - * TaskHandle_t xHandle = NULL; - * - * // Create the task pinned to core 0 without using any dynamic memory allocation. - * xHandle = xTaskCreateStaticPinnedToCore( - * vTaskCode, // Function that implements the task. - * "NAME", // Text name for the task. - * STACK_SIZE, // Stack size in bytes, not words. - * ( void * ) 1, // Parameter passed into the task. - * tskIDLE_PRIORITY,// Priority at which the task is created. - * xStack, // Array to use as the task's stack. - * &xTaskBuffer, // Variable to hold the task's data structure. - * 0 ); // Specify the task's core affinity - * - * // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have - * // been created, and xHandle will be the task's handle. Use the handle - * // to suspend the task. - * vTaskSuspend( xHandle ); - * } - * @endcode - * @cond !DOC_SINGLE_GROUP - * \defgroup xTaskCreateStaticPinnedToCore xTaskCreateStaticPinnedToCore - * @endcond - * \ingroup Tasks - */ -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, - const char * const pcName, - const uint32_t ulStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - StackType_t * const pxStackBuffer, - StaticTask_t * const pxTaskBuffer, - const BaseType_t xCoreID ); -#endif /* configSUPPORT_STATIC_ALLOCATION */ - /** * @cond !DOC_EXCLUDE_HEADER_SECTION * task. h @@ -526,8 +328,8 @@ typedef enum * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default * is 16. * - * @param usStackDepth The size of the task stack specified as the number of - * bytes. Note that this differs from vanilla FreeRTOS. + * @param usStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * * @param pvParameters Pointer that will be used as the parameter for the task * being created. @@ -584,6 +386,7 @@ typedef enum * \ingroup Tasks */ #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + static inline __attribute__( ( always_inline ) ) BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ @@ -592,8 +395,31 @@ typedef enum UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION { - return xTaskCreatePinnedToCore( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, tskNO_AFFINITY ); + /* + * The idf_additions.h has not been included here yet due to inclusion + * order. Thus we manually declare the function here. + */ + extern BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID ); + + /* + * Call the "PinnedToCore" version with tskNO_AFFINITY to create + * an unpinned task. + */ + return xTaskCreatePinnedToCore( pxTaskCode, + pcName, + usStackDepth, + pvParameters, + uxPriority, + pxCreatedTask, + tskNO_AFFINITY ); } + #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ /** @@ -630,8 +456,8 @@ typedef enum * facilitate debugging. The maximum length of the string is defined by * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. * - * @param ulStackDepth The size of the task stack specified as the number of - * bytes. Note that this differs from vanilla FreeRTOS. + * @param ulStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * * @param pvParameters Pointer that will be used as the parameter for the task * being created. @@ -706,8 +532,8 @@ typedef enum * @endcode * \ingroup Tasks */ - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + static inline __attribute__( ( always_inline ) ) TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ @@ -717,8 +543,32 @@ typedef enum StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION { - return xTaskCreateStaticPinnedToCore( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, tskNO_AFFINITY ); + /* + * The idf_additions.h has not been included here yet due to inclusion + * order. Thus we manually declare the function here. + */ + extern TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const pxStackBuffer, + StaticTask_t * const pxTaskBuffer, + const BaseType_t xCoreID ); + /* + * Call the "PinnedToCore" version with tskNO_AFFINITY to create + * an unpinned task. + */ + return xTaskCreateStaticPinnedToCore( pxTaskCode, + pcName, + ulStackDepth, + pvParameters, + uxPriority, + puxStackBuffer, + pxTaskBuffer, + tskNO_AFFINITY ); } + #endif /* configSUPPORT_STATIC_ALLOCATION */ /** diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 592af7071e..3459a572a7 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -708,64 +708,6 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - - TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, - const char * const pcName, - const uint32_t ulStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer, - const BaseType_t xCoreID ) - { - TCB_t * pxNewTCB; - TaskHandle_t xReturn; - - configASSERT( portVALID_STACK_MEM( puxStackBuffer ) ); - configASSERT( portVALID_TCB_MEM( pxTaskBuffer ) ); - configASSERT( ( ( xCoreID >= 0 ) && ( xCoreID < configNUM_CORES ) ) || ( xCoreID == tskNO_AFFINITY ) ); - - #if ( configASSERT_DEFINED == 1 ) - { - /* Sanity check that the size of the structure used to declare a - * variable of type StaticTask_t equals the size of the real task - * structure. */ - volatile size_t xSize = sizeof( StaticTask_t ); - configASSERT( xSize == sizeof( TCB_t ) ); - ( void ) xSize; /* Prevent lint warning when configASSERT() is not used. */ - } - #endif /* configASSERT_DEFINED */ - - if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) - { - /* The memory used for the task's TCB and stack are passed into this - * function - use them. */ - pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ - pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; - - #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ - { - /* Tasks can be created statically or dynamically, so note this - * task was created statically in case the task is later deleted. */ - pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; - } - #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ - - prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL, xCoreID ); - prvAddNewTaskToReadyList( pxNewTCB ); - } - else - { - xReturn = NULL; - } - - return xReturn; - } - -#endif /* SUPPORT_STATIC_ALLOCATION */ -/*-----------------------------------------------------------*/ - #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, @@ -865,100 +807,6 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #endif /* portUSING_MPU_WRAPPERS */ /*-----------------------------------------------------------*/ -#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - - BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const configSTACK_DEPTH_TYPE usStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask, - const BaseType_t xCoreID ) - { - TCB_t * pxNewTCB; - BaseType_t xReturn; - - /* If the stack grows down then allocate the stack then the TCB so the stack - * does not grow into the TCB. Likewise if the stack grows up then allocate - * the TCB then the stack. */ - #if ( portSTACK_GROWTH > 0 ) - { - /* Allocate space for the TCB. Where the memory comes from depends on - * the implementation of the port malloc function and whether or not static - * allocation is being used. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); - - if( pxNewTCB != NULL ) - { - /* 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. */ - - if( pxNewTCB->pxStack == NULL ) - { - /* Could not allocate the stack. Delete the allocated TCB. */ - vPortFree( pxNewTCB ); - pxNewTCB = NULL; - } - } - } - #else /* portSTACK_GROWTH */ - { - 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. */ - - if( pxStack != NULL ) - { - /* Allocate space for the TCB. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */ - - if( pxNewTCB != NULL ) - { - /* Store the stack location in the TCB. */ - pxNewTCB->pxStack = pxStack; - } - else - { - /* The stack cannot be used as the TCB was not created. Free - * it again. */ - vPortFree( pxStack ); - } - } - else - { - pxNewTCB = NULL; - } - } - #endif /* portSTACK_GROWTH */ - - if( pxNewTCB != NULL ) - { - #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */ - { - /* Tasks can be created statically or dynamically, so note this - * task was created dynamically in case it is later deleted. */ - pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; - } - #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ - - prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL, xCoreID ); - prvAddNewTaskToReadyList( pxNewTCB ); - xReturn = pdPASS; - } - else - { - xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - } - - return xReturn; - } - -#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ -/*-----------------------------------------------------------*/ - static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index c9c64b1964..f93d36e04a 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -5,6 +5,7 @@ */ #include "sdkconfig.h" +#include "esp_assert.h" #include "freertos/idf_additions.h" #if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT #include "freertos/task_snapshot.h" @@ -163,7 +164,7 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt /* -------------------------------------------------- Task Creation ------------------------------------------------- */ -#if CONFIG_FREERTOS_SMP +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, @@ -173,36 +174,126 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt TaskHandle_t * const pxCreatedTask, const BaseType_t xCoreID ) { - BaseType_t ret; + BaseType_t xReturn; - #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) + #if CONFIG_FREERTOS_SMP { - /* Convert xCoreID into an affinity mask */ - UBaseType_t uxCoreAffinityMask; - - if( xCoreID == tskNO_AFFINITY ) + /* If using Amazon SMP FreeRTOS. This function is just a wrapper around + * xTaskCreate() or xTaskCreateAffinitySet(). */ + #if ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { - uxCoreAffinityMask = tskNO_AFFINITY; + /* Convert xCoreID into an affinity mask */ + UBaseType_t uxCoreAffinityMask; + + /* Bit shifting << xCoreID is only valid if we have less than + * 32 cores. */ + ESP_STATIC_ASSERT( configNUM_CORES < 32 ); + + if( xCoreID == tskNO_AFFINITY ) + { + uxCoreAffinityMask = tskNO_AFFINITY; + } + else + { + uxCoreAffinityMask = ( 1 << xCoreID ); + } + + xReturn = xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask ); + } + #else /* ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + { + xReturn = xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); + } + #endif /* ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + } + #else /* CONFIG_FREERTOS_SMP */ + { + TCB_t * pxNewTCB; + + /* If the stack grows down then allocate the stack then the TCB so the + * stack does not grow into the TCB. Likewise if the stack grows up + * then allocate the TCB then the stack. */ + #if ( portSTACK_GROWTH > 0 ) + { + /* Allocate space for the TCB. Where the memory comes from depends on + * the implementation of the port malloc function and whether or not static + * allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* 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. */ + + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree( pxNewTCB ); + pxNewTCB = NULL; + } + } + } + #else /* portSTACK_GROWTH */ + { + 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. */ + + if( pxStack != NULL ) + { + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */ + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } + else + { + /* The stack cannot be used as the TCB was not created. Free + * it again. */ + vPortFree( pxStack ); + } + } + else + { + pxNewTCB = NULL; + } + } + #endif /* portSTACK_GROWTH */ + + if( pxNewTCB != NULL ) + { + #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */ + { + /* Tasks can be created statically or dynamically, so note this + * task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL, xCoreID ); + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; } else { - uxCoreAffinityMask = ( 1 << xCoreID ); + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } + } + #endif /* CONFIG_FREERTOS_SMP */ - ret = xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask ); - } - #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ - { - ret = xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); - } - #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ - return ret; + return xReturn; } -#endif /* CONFIG_FREERTOS_SMP */ +#endif /* ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ /*----------------------------------------------------------*/ -#if ( CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, @@ -213,33 +304,82 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt StaticTask_t * const pxTaskBuffer, const BaseType_t xCoreID ) { - TaskHandle_t ret; + TaskHandle_t xReturn; - #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) + #if CONFIG_FREERTOS_SMP { - /* Convert xCoreID into an affinity mask */ - UBaseType_t uxCoreAffinityMask; - - if( xCoreID == tskNO_AFFINITY ) + /* If using Amazon SMP FreeRTOS. This function is just a wrapper around + * xTaskCreateStatic() or xTaskCreateStaticAffinitySet(). */ + #if ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { - uxCoreAffinityMask = tskNO_AFFINITY; + /* Convert xCoreID into an affinity mask */ + UBaseType_t uxCoreAffinityMask; + + if( xCoreID == tskNO_AFFINITY ) + { + uxCoreAffinityMask = tskNO_AFFINITY; + } + else + { + uxCoreAffinityMask = ( 1 << xCoreID ); + } + + xReturn = xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask ); + } + #else /* ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + { + xReturn = xTaskCreateStatic( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer ); + } + #endif /* ( ( configNUM_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + } + #else /* CONFIG_FREERTOS_SMP */ + { + TCB_t * pxNewTCB; + + configASSERT( portVALID_STACK_MEM( puxStackBuffer ) ); + configASSERT( portVALID_TCB_MEM( pxTaskBuffer ) ); + configASSERT( ( ( xCoreID >= 0 ) && ( xCoreID < configNUM_CORES ) ) || ( xCoreID == tskNO_AFFINITY ) ); + + #if ( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + * variable of type StaticTask_t equals the size of the real task + * structure. */ + volatile size_t xSize = sizeof( StaticTask_t ); + configASSERT( xSize == sizeof( TCB_t ) ); + ( void ) xSize; /* Prevent lint warning when configASSERT() is not used. */ + } + #endif /* configASSERT_DEFINED */ + + if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) + { + /* The memory used for the task's TCB and stack are passed into this + * function - use them. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; + + #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ + { + /* Tasks can be created statically or dynamically, so note this + * task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL, xCoreID ); + prvAddNewTaskToReadyList( pxNewTCB ); } else { - uxCoreAffinityMask = ( 1 << xCoreID ); + xReturn = NULL; } + } + #endif /* CONFIG_FREERTOS_SMP */ - ret = xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask ); - } - #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ - { - ret = xTaskCreateStatic( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer ); - } - #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ - return ret; + return xReturn; } -#endif /* CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ +#endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ /*----------------------------------------------------------*/ #if ( configUSE_TIMERS == 1 ) diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index 94fc012a15..5f2e431bcf 100644 --- a/components/freertos/esp_additions/include/freertos/idf_additions.h +++ b/components/freertos/esp_additions/include/freertos/idf_additions.h @@ -31,26 +31,23 @@ #endif /* *INDENT-ON* */ -/* -------------------------------------------------- Task Creation --------------------------------------------------- -* Task Creation APIs added by ESP-IDF -* -* Todo: Move IDF FreeRTOS SMP related additions to this header as well (see IDF-7201) -* Todo: Add these SMP related additions to docs once they are combined with IDF FreeRTOS. -* ------------------------------------------------------------------------------------------------------------------ */ +/* -------------------------------------------------- Task Creation ------------------------------------------------- */ -#if ( CONFIG_FREERTOS_SMP && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) /** * @brief Create a new task that is pinned to a particular core * - * Helper function to create a task that is pinned to a particular core, or has - * no affinity. In other words, the created task will have an affinity mask of: - * - (1 << xCoreID) if it is pinned to a particular core - * - Set to tskNO_AFFINITY if it has no affinity + * This function is similar to xTaskCreate(), but allows the creation of a pinned + * task. The task's pinned core is specified by the xCoreID argument. If xCoreID + * is set to tskNO_AFFINITY, then the task is unpinned and can run on any core. + * + * @note If ( configNUM_CORES == 1 ), xCoreID is ignored. * * @param pxTaskCode Pointer to the task entry function. * @param pcName A descriptive name for the task. - * @param usStackDepth The size of the task stack. + * @param ulStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * @param pvParameters Pointer that will be used as the parameter for the task * being created. * @param uxPriority The priority at which the task should run. @@ -63,24 +60,30 @@ */ BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, - const uint32_t usStackDepth, + const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, const BaseType_t xCoreID ); -#endif /* ( CONFIG_FREERTOS_SMP && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ -#if ( CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) /** * @brief Create a new static task that is pinned to a particular core * - * This funciton is the static equivalent of xTaskCreatePinnedToCore(). + * This function is similar to xTaskCreateStatic(), but allows the creation of a + * pinned task. The task's pinned core is specified by the xCoreID argument. If + * xCoreID is set to tskNO_AFFINITY, then the task is unpinned and can run on any + * core. + * + * @note If ( configNUM_CORES == 1 ), xCoreID is ignored. * * @param pxTaskCode Pointer to the task entry function. * @param pcName A descriptive name for the task. - * @param ulStackDepth The size of the task stack. + * @param ulStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * @param pvParameters Pointer that will be used as the parameter for the task * being created. * @param uxPriority The priority at which the task should run. @@ -101,7 +104,7 @@ StaticTask_t * const pxTaskBuffer, const BaseType_t xCoreID ); -#endif /* ( CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ /* ------------------------------------------------- Task Utilities ------------------------------------------------- */ diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index c0a663b0c5..31a1b39cfb 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -109,8 +109,6 @@ entries: # - "xTaskGetSchedulerState" # - "xTaskGetTickCount" # -------------------------------------------------------------------------------------------------------------- - tasks:xTaskCreateStaticPinnedToCore (default) - tasks:xTaskCreatePinnedToCore (default) tasks:prvInitialiseNewTask (default) tasks:prvAddNewTaskToReadyList (default) tasks:vTaskDelete (default) diff --git a/components/freertos/linker_common.lf b/components/freertos/linker_common.lf index eedac43a07..d836cf4902 100644 --- a/components/freertos/linker_common.lf +++ b/components/freertos/linker_common.lf @@ -22,9 +22,8 @@ entries: tasks:prvTakeKernelLock (default) tasks:prvReleaseKernelLock (default) # Task Creation - if FREERTOS_SMP = y: - tasks:xTaskCreatePinnedToCore (default) - tasks:xTaskCreateStaticPinnedToCore (default) + tasks:xTaskCreatePinnedToCore (default) + tasks:xTaskCreateStaticPinnedToCore (default) # Task Utilities tasks:xTaskGetCurrentTaskHandleForCPU (default) tasks:xTaskGetIdleTaskHandleForCPU (default) diff --git a/tools/mocks/freertos/CMakeLists.txt b/tools/mocks/freertos/CMakeLists.txt index 3e1e9bb68e..ac4c116a44 100644 --- a/tools/mocks/freertos/CMakeLists.txt +++ b/tools/mocks/freertos/CMakeLists.txt @@ -12,6 +12,8 @@ set(include_dirs "${original_freertos_dir}/config/include/freertos" # For "FreeRTOSConfig.h" "${original_freertos_dir}/config/linux/include" # For "freertos/FreeRTOSConfig_arch.h" "${original_freertos_dir}/esp_additions/include" + # Required because CMock tries to include "idf_additions.h" instead of "freertos/idf_additions.h" + "${original_freertos_dir}/esp_additions/include/freertos" "${kernel_dir}/portable/linux/include" # For "freertos/portmacro.h" "${kernel_dir}/include/freertos" # this is due to the way includes are generated in CMock (without freertos prefix) ) @@ -19,6 +21,7 @@ set(include_dirs idf_component_mock(INCLUDE_DIRS ${include_dirs} REQUIRES esp_common MOCK_HEADER_FILES + ${original_freertos_dir}/esp_additions/include/freertos/idf_additions.h ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/task.h ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/event_groups.h ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/queue.h)