diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 17e6749d1e..9ac34ce96a 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -99,13 +99,9 @@ endif() # Add ESP-additions source files list(APPEND srcs + "esp_additions/freertos_compatibility.c" "esp_additions/idf_additions.c") -if(kernel_impl STREQUAL "FreeRTOS-Kernel") - list(APPEND srcs - "esp_additions/freertos_compatibility.c") -endif() - if(arch STREQUAL "linux") # Check if we need to address the FreeRTOS EINTR coexistence with linux system calls if we're building without # lwIP, we need to use linux system select which will receive EINTR event on every FreeRTOS interrupt, we diff --git a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h index deef64198a..24dbd653df 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h @@ -1393,11 +1393,29 @@ typedef StaticStreamBuffer_t StaticMessageBuffer_t; #endif /* *INDENT-ON* */ -/* IDF API additions have been moved to idf_additions.h when building for - * Amazon SMP FreeRTOS. However, the rest of ESP-IDF has not been updated to - * include this header explicitly when calling this additional API. Thus, we - * include this here as a workaround until the rest of ESP-IDF can be updated - * to include idf_additions.h explicitly. */ -#include "freertos/idf_additions.h" +/*----------------------------------------------------------- +* IDF Compatibility +*----------------------------------------------------------*/ + +#ifdef ESP_PLATFORM + + /* + * Include ESP-IDF API additions implicitly for compatibility reasons. + * + * ESP-IDF API additions were previously added directly to FreeRTOS headers + * (e.g., task.h, queue.h). These APIs have now been moved to + * idf_additions.h. + * + * To ensure there are no breaking changes, we include idf_additions.h + * implicitly here so that those API additions are still accessible. Given + * that FreeRTOS.h must be included first before calling any FreeRTOS API, + * any existing source code can continue using these relocated APIs without + * any additional header inclusions via this implicit inclusion. + * + * Todo: Deprecate this implicit inclusion by ESP-IDF v6.0 (IDF-8126) + */ + #include "freertos/idf_additions.h" + +#endif /* ESP_PLATFORM */ #endif /* INC_FREERTOS_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h index 41d44b5107..7f436bcb0d 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h @@ -3306,25 +3306,6 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC */ void vTaskYieldWithinAPI( void ); -/* ------------------------------------------------ IDF Compatibility -------------------------------------------------- - * - * ------------------------------------------------------------------------------------------------------------------ */ - -#ifdef ESP_PLATFORM - -#if ( configNUM_CORES > 1 ) -/* -Workaround for non-thread safe multi-core OS startup (see IDF-4524) -This function must be called with interrupts disabled on all cores other than -core 0 during startup. -*/ -void vTaskStartSchedulerOtherCores( void ); -#endif // configNUM_CORES > 1 - -#include "freertos/idf_additions.h" - -#endif //ESP_PLATFORM - /* *INDENT-OFF* */ #ifdef __cplusplus } diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index ad5fa3dbd9..cb84e80931 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -18,6 +18,7 @@ #include "xtensa/config/core.h" #include "xtensa/config/core-isa.h" #include "xtensa/xtruntime.h" +#include "esp_private/freertos_idf_additions_priv.h" #include "esp_private/esp_int_wdt.h" #include "esp_private/systimer.h" #include "esp_private/periph_ctrl.h" @@ -328,7 +329,7 @@ BaseType_t xPortStartScheduler( void ) #if configNUM_CORES > 1 // Workaround for non-thread safe multi-core OS startup (see IDF-4524) if (xPortGetCoreID() != 0) { - vTaskStartSchedulerOtherCores(); + prvStartSchedulerOtherCores(); } #endif // configNUM_CORES > 1 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c index b7a8f03253..254fc0a830 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c @@ -6506,14 +6506,3 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, #endif #endif /* if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) */ - -#if ( ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 ) ) -/* -Workaround for non-thread safe multi-core OS startup (see IDF-4524) -*/ -void vTaskStartSchedulerOtherCores( void ) -{ - /* This function is always called with interrupts disabled*/ - xSchedulerRunning = pdTRUE; -} -#endif // ( ESP_PLATFORM == 1 ) && ( configNUM_CORES > 1 diff --git a/components/freertos/FreeRTOS-Kernel/event_groups.c b/components/freertos/FreeRTOS-Kernel/event_groups.c index 8b1b184b17..019b85e3b2 100644 --- a/components/freertos/FreeRTOS-Kernel/event_groups.c +++ b/components/freertos/FreeRTOS-Kernel/event_groups.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* @@ -45,6 +45,8 @@ #include "task.h" #include "timers.h" #include "event_groups.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" /* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined @@ -566,8 +568,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, #if ( configNUM_CORES > 1 ) /* We are about to traverse a task list which is a kernel data structure. - * Thus we need to call vTaskTakeKernelLock() to take the kernel lock. */ - vTaskTakeKernelLock(); + * Thus we need to call prvTakeKernelLock() to take the kernel lock. */ + prvTakeKernelLock(); #endif /* configNUM_CORES > 1 */ { traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); @@ -642,7 +644,7 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, } #if ( configNUM_CORES > 1 ) /* Release the previously taken kernel lock. */ - vTaskReleaseKernelLock(); + prvReleaseKernelLock(); #endif /* configNUM_CORES > 1 */ ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); @@ -659,8 +661,8 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ) #if ( configNUM_CORES > 1 ) /* We are about to traverse a task list which is a kernel data structure. - * Thus we need to call vTaskTakeKernelLock() to take the kernel lock. */ - vTaskTakeKernelLock(); + * Thus we need to call prvTakeKernelLock() to take the kernel lock. */ + prvTakeKernelLock(); #endif /* configNUM_CORES > 1 */ { traceEVENT_GROUP_DELETE( xEventGroup ); @@ -675,7 +677,7 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ) } #if ( configNUM_CORES > 1 ) /* Release the previously taken kernel lock. */ - vTaskReleaseKernelLock(); + prvReleaseKernelLock(); #endif /* configNUM_CORES > 1 */ prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); diff --git a/components/freertos/FreeRTOS-Kernel/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel/include/freertos/FreeRTOS.h index e6b6916ab9..5ddfdafdb7 100644 --- a/components/freertos/FreeRTOS-Kernel/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel/include/freertos/FreeRTOS.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* @@ -1404,4 +1404,29 @@ typedef StaticStreamBuffer_t StaticMessageBuffer_t; #endif /* *INDENT-ON* */ +/*----------------------------------------------------------- +* IDF Compatibility +*----------------------------------------------------------*/ + +#ifdef ESP_PLATFORM + + /* + * Include ESP-IDF API additions implicitly for compatibility reasons. + * + * ESP-IDF API additions were previously added directly to FreeRTOS headers + * (e.g., task.h, queue.h). These APIs have now been moved to + * idf_additions.h. + * + * To ensure there are no breaking changes, we include idf_additions.h + * implicitly here so that those API additions are still accessible. Given + * that FreeRTOS.h must be included first before calling any FreeRTOS API, + * any existing source code can continue using these relocated APIs without + * any additional header inclusions via this implicit inclusion. + * + * Todo: Deprecate this implicit inclusion by ESP-IDF v6.0 (IDF-8126) + */ + #include "freertos/idf_additions.h" + +#endif /* ESP_PLATFORM */ + #endif /* INC_FREERTOS_H */ diff --git a/components/freertos/FreeRTOS-Kernel/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel/include/freertos/task.h index a50fb78d07..22992e565b 100644 --- a/components/freertos/FreeRTOS-Kernel/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel/include/freertos/task.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* @@ -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 */ /** @@ -1950,21 +1800,6 @@ UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTIO */ configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; -/** - * Returns the start of the stack associated with xTask. - * - * INCLUDE_pxTaskGetStackStart must be set to 1 in FreeRTOSConfig.h for - * this function to be available. - * - * Returns the lowest stack memory address, regardless of whether the stack grows up or down. - * - * @param xTask Handle of the task associated with the stack returned. - * Set xTask to NULL to return the stack of the calling task. - * - * @return A pointer to the start of the stack. - */ -uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; - /* When using trace macros it is sometimes necessary to include task.h before * FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined, * so the following two prototypes will cause a compilation error. This can be @@ -2039,7 +1874,6 @@ uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; BaseType_t xIndex, void * pvValue ) PRIVILEGED_FUNCTION; - /** * Get local storage pointer specific to the given task. * @@ -2056,39 +1890,6 @@ uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; void * pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 ) - - /** - * Prototype of local storage pointer deletion callback. - */ - typedef void (*TlsDeleteCallbackFunction_t)( int, void * ); - - /** - * Set local storage pointer and deletion callback. - * - * Each task contains an array of pointers that is dimensioned by the - * configNUM_THREAD_LOCAL_STORAGE_POINTERS setting in FreeRTOSConfig.h. - * The kernel does not use the pointers itself, so the application writer - * can use the pointers for any purpose they wish. - * - * Local storage pointers set for a task can reference dynamically - * allocated resources. This function is similar to - * vTaskSetThreadLocalStoragePointer, but provides a way to release - * these resources when the task gets deleted. For each pointer, - * a callback function can be set. This function will be called - * when task is deleted, with the local storage pointer index - * and value as arguments. - * - * @param xTaskToSet Task to set thread local storage pointer for - * @param xIndex The index of the pointer to set, from 0 to - * configNUM_THREAD_LOCAL_STORAGE_POINTERS - 1. - * @param pvValue Pointer value to set. - * @param pvDelCallback Function to call to dispose of the local - * storage pointer when the task is deleted. - */ - void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue, TlsDeleteCallbackFunction_t pvDelCallback); - #endif - #endif /* if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) */ #if ( configCHECK_FOR_STACK_OVERFLOW > 0 ) @@ -3439,58 +3240,6 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION; *----------------------------------------------------------*/ /** @cond !DOC_EXCLUDE_HEADER_SECTION */ -/* - * Various convenience macros for critical sections and scheduler suspension - * called by other FreeRTOS sources and not meant to be called by the - * application. The behavior of each macro depends on whether FreeRTOS is - * currently configured for SMP or single core. - */ -#if ( configNUM_CORES > 1 ) - #define prvENTER_CRITICAL_OR_SUSPEND_ALL( x ) taskENTER_CRITICAL( ( x ) ) - #define prvEXIT_CRITICAL_OR_RESUME_ALL( x ) ( { taskEXIT_CRITICAL( ( x ) ); pdFALSE; } ) - #define prvENTER_CRITICAL_OR_MASK_ISR( pxLock, uxInterruptStatus ) \ - taskENTER_CRITICAL_ISR( ( pxLock ) ); \ - ( void ) ( uxInterruptStatus ); - #define prvEXIT_CRITICAL_OR_UNMASK_ISR( pxLock, uxInterruptStatus ) \ - taskEXIT_CRITICAL_ISR( ( pxLock ) ); \ - ( void ) ( uxInterruptStatus ); -#else /* configNUM_CORES > 1 */ - #define prvENTER_CRITICAL_OR_SUSPEND_ALL( x ) ( { vTaskSuspendAll(); ( void ) ( x ); } ) - #define prvEXIT_CRITICAL_OR_RESUME_ALL( x ) xTaskResumeAll() - #define prvENTER_CRITICAL_OR_MASK_ISR( pxLock, uxInterruptStatus ) \ - ( uxInterruptStatus ) = portSET_INTERRUPT_MASK_FROM_ISR(); \ - ( void ) ( pxLock ); - #define prvEXIT_CRITICAL_OR_UNMASK_ISR( pxLock, uxInterruptStatus ) \ - portCLEAR_INTERRUPT_MASK_FROM_ISR( ( uxInterruptStatus ) ); \ - ( void ) ( pxLock ); -#endif /* configNUM_CORES > 1 */ - -/* - * Return the handle of the task running on a certain CPU. Because of - * the nature of SMP processing, there is no guarantee that this - * value will still be valid on return and should only be used for - * debugging purposes. - */ -TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid ); - -/** - * Get the handle of idle task for the given CPU. - * - * xTaskGetIdleTaskHandleForCPU() is only available if - * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. - * - * @param cpuid The CPU to get the handle for - * - * @return Idle task handle of a given cpu. It is not valid to call - * xTaskGetIdleTaskHandleForCPU() before the scheduler has been started. - */ -TaskHandle_t xTaskGetIdleTaskHandleForCPU( UBaseType_t cpuid ); - -/* - * Get the current core affinity of a task - */ -BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; - /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS @@ -3511,20 +3260,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; */ BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; -#if ( configNUM_CORES > 1 ) - -/* - * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY - * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS - * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. - * - * Called from all other cores except core 0 when their tick interrupt - * occurs. This function will check if the current core requires time slicing, - * and also call the application tick hook. - */ - BaseType_t xTaskIncrementTickOtherCores( void ) PRIVILEGED_FUNCTION; -#endif /* configNUM_CORES > 1 */ - /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. @@ -3577,26 +3312,6 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; -#if ( configNUM_CORES > 1 ) - -/* - * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN - * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. - * - * This function is a wrapper to take the "xKernelLock" spinlock of tasks.c. - * This lock is taken whenver any of the kernel's data structures are - * accessed/modified, such as when adding/removing tasks to/from the delayed - * task list or various event lists. - * - * This functions is meant to be called by xEventGroupSetBits() and - * vEventGroupDelete() as both those functions will access event lists (instead - * of delegating the entire responsibility to one of vTask...EventList() - * functions). - */ - void vTaskTakeKernelLock( void ); - void vTaskReleaseKernelLock( void ); -#endif /* configNUM_CORES > 1 */ - /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. diff --git a/components/freertos/FreeRTOS-Kernel/queue.c b/components/freertos/FreeRTOS-Kernel/queue.c index 69da28f732..1be5631a0b 100644 --- a/components/freertos/FreeRTOS-Kernel/queue.c +++ b/components/freertos/FreeRTOS-Kernel/queue.c @@ -43,6 +43,8 @@ #include "FreeRTOS.h" #include "task.h" #include "queue.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( configUSE_CO_ROUTINES == 1 ) #include "croutine.h" diff --git a/components/freertos/FreeRTOS-Kernel/stream_buffer.c b/components/freertos/FreeRTOS-Kernel/stream_buffer.c index d67f091cba..0973bdbbf1 100644 --- a/components/freertos/FreeRTOS-Kernel/stream_buffer.c +++ b/components/freertos/FreeRTOS-Kernel/stream_buffer.c @@ -45,6 +45,8 @@ #include "FreeRTOS.h" #include "task.h" #include "stream_buffer.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( configUSE_TASK_NOTIFICATIONS != 1 ) #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 9487213e2a..3459a572a7 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -46,6 +46,8 @@ #include "task.h" #include "timers.h" #include "stack_macros.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #ifdef ESP_PLATFORM #undef _REENT_INIT_PTR @@ -502,28 +504,6 @@ PRIVILEGED_DATA static volatile BaseType_t xSwitchingContext[ configNUM_CORES ] /*-----------------------------------------------------------*/ -/* Callback function prototypes. --------------------------*/ -#if ( configCHECK_FOR_STACK_OVERFLOW > 0 ) - - extern void vApplicationStackOverflowHook( TaskHandle_t xTask, - char * pcTaskName ); - -#endif - -#if ( configUSE_TICK_HOOK > 0 ) - - extern void vApplicationTickHook( void ); /*lint !e526 Symbol not defined as it is an application callback. */ - -#endif - -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - - extern void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - uint32_t * pulIdleTaskStackSize ); /*lint !e526 Symbol not defined as it is an application callback. */ - -#endif - /* File private functions. --------------------------------*/ /** @@ -728,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, @@ -885,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, @@ -1528,15 +1356,6 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /*-----------------------------------------------------------*/ #if ( INCLUDE_xTaskDelayUntil == 1 ) - #ifdef ESP_PLATFORM - /* backward binary compatibility - remove later */ - #undef vTaskDelayUntil - void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, - const TickType_t xTimeIncrement ) - { - xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ); - } - #endif // ESP_PLATFORM BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) @@ -3014,12 +2833,6 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char return xIdleTaskHandle[ xPortGetCoreID() ]; } - TaskHandle_t xTaskGetIdleTaskHandleForCPU( UBaseType_t cpuid ) - { - configASSERT( cpuid < configNUM_CORES ); - configASSERT( ( xIdleTaskHandle[ cpuid ] != NULL ) ); - return xIdleTaskHandle[ cpuid ]; - } #endif /* INCLUDE_xTaskGetIdleTaskHandle */ /*----------------------------------------------------------*/ @@ -3367,90 +3180,6 @@ BaseType_t xTaskIncrementTick( void ) return xSwitchRequired; } - -#if ( configNUM_CORES > 1 ) - BaseType_t xTaskIncrementTickOtherCores( void ) - { - /* Minor optimization. This function can never switch cores mid - * execution */ - BaseType_t xCoreID = xPortGetCoreID(); - BaseType_t xSwitchRequired = pdFALSE; - - /* This function should never be called by Core 0. */ - configASSERT( xCoreID != 0 ); - - /* Called by the portable layer each time a tick interrupt occurs. - * Increments the tick then checks to see if the new tick value will cause any - * tasks to be unblocked. */ - traceTASK_INCREMENT_TICK( xTickCount ); - - if( uxSchedulerSuspended[ xCoreID ] == ( UBaseType_t ) 0U ) - { - /* We need take the kernel lock here as we are about to access - * kernel data structures. */ - taskENTER_CRITICAL_ISR( &xKernelLock ); - - /* A task being unblocked cannot cause an immediate context switch - * if preemption is turned off. */ - #if ( configUSE_PREEMPTION == 1 ) - { - /* Check if core 0 calling xTaskIncrementTick() has - * unblocked a task that can be run. */ - if( uxTopReadyPriority > pxCurrentTCB[ xCoreID ]->uxPriority ) - { - xSwitchRequired = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* if ( configUSE_PREEMPTION == 1 ) */ - - /* Tasks of equal priority to the currently running task will share - * processing time (time slice) if preemption is on, and the application - * writer has not explicitly turned time slicing off. */ - #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) - { - if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB[ xCoreID ]->uxPriority ] ) ) > ( UBaseType_t ) 1 ) - { - xSwitchRequired = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ - - /* Release the previously taken kernel lock as we have finished - * accessing the kernel data structures. */ - taskEXIT_CRITICAL_ISR( &xKernelLock ); - - #if ( configUSE_PREEMPTION == 1 ) - { - if( xYieldPending[ xCoreID ] != pdFALSE ) - { - xSwitchRequired = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* configUSE_PREEMPTION */ - } - - #if ( configUSE_TICK_HOOK == 1 ) - { - vApplicationTickHook(); - } - #endif - - return xSwitchRequired; - } -#endif /* ( configNUM_CORES > 1 ) */ - /*-----------------------------------------------------------*/ #if ( configUSE_APPLICATION_TASK_TAG == 1 ) @@ -4008,20 +3737,6 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) } /*-----------------------------------------------------------*/ -#if ( configNUM_CORES > 1 ) - void vTaskTakeKernelLock( void ) - { - /* We call the tasks.c critical section macro to take xKernelLock */ - taskENTER_CRITICAL( &xKernelLock ); - } - - void vTaskReleaseKernelLock( void ) - { - /* We call the tasks.c critical section macro to release xKernelLock */ - taskEXIT_CRITICAL( &xKernelLock ); - } -#endif /* configNUM_CORES > 1 */ - void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) { @@ -4032,7 +3747,7 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, /* THIS FUNCTION MUST BE CALLED WITH THE KERNEL LOCK ALREADY TAKEN. * It is used by the event flags implementation, thus those functions - * should call vTaskTakeKernelLock() before calling this function. */ + * should call prvTakeKernelLock() before calling this function. */ #else /* configNUM_CORES > 1 */ /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by @@ -4442,79 +4157,42 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 ) - - void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, - BaseType_t xIndex, - void * pvValue, - TlsDeleteCallbackFunction_t xDelCallback ) + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, + BaseType_t xIndex, + void * pvValue ) + { + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 ) + { + /* TLSP Deletion Callbacks are enabled. Call the TLSPDC funciton + * instead with a NULL callback. */ + vTaskSetThreadLocalStoragePointerAndDelCallback( xTaskToSet, xIndex, pvValue, NULL ); + } + #else /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 */ { TCB_t * pxTCB; - /* If TLSP deletion callbacks are enabled, then - * configNUM_THREAD_LOCAL_STORAGE_POINTERS is doubled in size so - * that the latter half of the pvThreadLocalStoragePointers stores - * the deletion callbacks. */ - if( xIndex < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ) - { - #if ( configNUM_CORES > 1 ) + #if ( configNUM_CORES > 1 ) - /* For SMP, we need to take the kernel lock here as we - * another core could also update this task's TLSP at the - * same time. */ - taskENTER_CRITICAL( &xKernelLock ); - #endif /* ( configNUM_CORES > 1 ) */ - - pxTCB = prvGetTCBFromHandle( xTaskToSet ); - /* Store the TLSP by indexing the first half of the array */ - pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; - /* Store the TLSP deletion callback by indexing the second half - * of the array. */ - pxTCB->pvThreadLocalStoragePointers[ ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ) ] = ( void * ) xDelCallback; - - #if ( configNUM_CORES > 1 ) - /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL( &xKernelLock ); - #endif /* configNUM_CORES > 1 */ - } - } - - void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, - BaseType_t xIndex, - void * pvValue ) - { - vTaskSetThreadLocalStoragePointerAndDelCallback( xTaskToSet, xIndex, pvValue, ( TlsDeleteCallbackFunction_t ) NULL ); - } - - - #else /* if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 ) */ - void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, - BaseType_t xIndex, - void * pvValue ) - { - TCB_t * pxTCB; + /* For SMP, we need to take the kernel lock here as we + * another core could also update this task's TLSP at the + * same time. */ + taskENTER_CRITICAL( &xKernelLock ); + #endif /* ( configNUM_CORES > 1 ) */ if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) { - #if ( configNUM_CORES > 1 ) - - /* For SMP, we need to take the kernel lock here as we - * another core could also update this task's TLSP at the - * same time. */ - taskENTER_CRITICAL( &xKernelLock ); - #endif /* ( configNUM_CORES > 1 ) */ - pxTCB = prvGetTCBFromHandle( xTaskToSet ); configASSERT( pxTCB != NULL ); pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; - - #if ( configNUM_CORES > 1 ) - /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL( &xKernelLock ); - #endif /* configNUM_CORES > 1 */ } + + #if ( configNUM_CORES > 1 ) + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL( &xKernelLock ); + #endif /* configNUM_CORES > 1 */ } - #endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 */ + #endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1 */ + } #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ /*-----------------------------------------------------------*/ @@ -4773,16 +4451,6 @@ static void prvCheckTasksWaitingTermination( void ) #endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ -BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) -{ - TCB_t * pxTCB; - - pxTCB = prvGetTCBFromHandle( xTask ); - - return pxTCB->xCoreID; -} -/*-----------------------------------------------------------*/ - #if ( configUSE_TRACE_FACILITY == 1 ) static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray, @@ -4905,20 +4573,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) #endif /* INCLUDE_uxTaskGetStackHighWaterMark */ /*-----------------------------------------------------------*/ -#if ( INCLUDE_pxTaskGetStackStart == 1 ) - - uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) - { - TCB_t * pxTCB; - uint8_t * uxReturn; - - pxTCB = prvGetTCBFromHandle( xTask ); - uxReturn = ( uint8_t * ) pxTCB->pxStack; - - return uxReturn; - } - -#endif /* INCLUDE_pxTaskGetStackStart */ #if ( INCLUDE_vTaskDelete == 1 ) @@ -5006,7 +4660,7 @@ static void prvResetNextTaskUnblockTime( void ) } /*-----------------------------------------------------------*/ -#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) || ( configNUM_CORES > 1 ) ) +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) TaskHandle_t xTaskGetCurrentTaskHandle( void ) { @@ -5020,19 +4674,6 @@ static void prvResetNextTaskUnblockTime( void ) return xReturn; } - TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid ) - { - TaskHandle_t xReturn = NULL; - - /*Xtensa-specific: the pxCurrentPCB pointer is atomic so we shouldn't need a lock. */ - if( cpuid < configNUM_CORES ) - { - xReturn = pxCurrentTCB[ cpuid ]; - } - - return xReturn; - } - #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ /*-----------------------------------------------------------*/ @@ -5772,16 +5413,6 @@ TickType_t uxTaskResetEventItemValue( void ) #if ( configUSE_TASK_NOTIFICATIONS == 1 ) - #ifdef ESP_PLATFORM /* IDF-3851 */ - /* included here for backward binary compatibility */ - #undef ulTaskNotifyTake - uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, - TickType_t xTicksToWait ) - { - return ulTaskGenericNotifyTake( tskDEFAULT_INDEX_TO_NOTIFY, xClearCountOnExit, xTicksToWait ); - } - #endif // ESP-PLATFORM - uint32_t ulTaskGenericNotifyTake( UBaseType_t uxIndexToWait, BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) @@ -5854,18 +5485,6 @@ TickType_t uxTaskResetEventItemValue( void ) #if ( configUSE_TASK_NOTIFICATIONS == 1 ) - #ifdef ESP_PLATFORM /* IDF-3851 */ - /* included for backward compatibility */ - #undef xTaskNotifyWait - BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, - uint32_t ulBitsToClearOnExit, - uint32_t * pulNotificationValue, - TickType_t xTicksToWait ) - { - return xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY, ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ); - } - #endif // ESP-PLATFORM - BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWait, uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, @@ -6533,9 +6152,3 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, #endif #endif /* if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) */ - -/* If timers.c is not referenced anywhere, don't create the timer task to save RAM */ -BaseType_t __attribute__( ( weak ) ) xTimerCreateTimerTask( void ) -{ - return pdPASS; -} diff --git a/components/freertos/FreeRTOS-Kernel/timers.c b/components/freertos/FreeRTOS-Kernel/timers.c index d68ab1e371..7e9db6968d 100644 --- a/components/freertos/FreeRTOS-Kernel/timers.c +++ b/components/freertos/FreeRTOS-Kernel/timers.c @@ -44,6 +44,8 @@ #include "task.h" #include "queue.h" #include "timers.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 ) #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. diff --git a/components/freertos/config/include/freertos/FreeRTOSConfig.h b/components/freertos/config/include/freertos/FreeRTOSConfig.h index 6a7ccf6d19..35faea2145 100644 --- a/components/freertos/config/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/config/include/freertos/FreeRTOSConfig.h @@ -198,8 +198,6 @@ #define INCLUDE_xTaskResumeFromISR 1 #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskGetSchedulerState 1 -/* Unlisted */ -#define INCLUDE_pxTaskGetStackStart 1 /* -------------------- Trace Macros ----------------------- */ diff --git a/components/freertos/esp_additions/freertos_compatibility.c b/components/freertos/esp_additions/freertos_compatibility.c index 66211af185..d56ae4e2d5 100644 --- a/components/freertos/esp_additions/freertos_compatibility.c +++ b/components/freertos/esp_additions/freertos_compatibility.c @@ -35,3 +35,45 @@ BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, return xQueueReceive( xQueue, pvBuffer, xTicksToWait ); } + +/* + * vTaskDelayUntil() was deprecated into a macro and replaced by xTaskDelayUntil(). + * This is added for pre-compiled libraries that depend on ulTaskNotifyTake() + * being a function. + * + * Todo: Remove this in v6.0 (IDF-3851) + */ +#undef vTaskDelayUntil +void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, + const TickType_t xTimeIncrement ) +{ + xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ); +} + +/* + * ulTaskNotifyTake() was turned into a macro. This is added for pre-compiled + * libraries that depend on ulTaskNotifyTake() being a function. + * + * Todo: Remove this in v6.0 (IDF-3851) + */ +#undef ulTaskNotifyTake +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, + TickType_t xTicksToWait ) +{ + return ulTaskGenericNotifyTake( tskDEFAULT_INDEX_TO_NOTIFY, xClearCountOnExit, xTicksToWait ); +} + +/* + * xTaskNotifyWait() was turned into a macro. This is added for pre-compiled + * libraries that depend on xTaskNotifyWait() being a function. + * + * Todo: Remove this in v6.0 (IDF-3851) + */ +#undef xTaskNotifyWait +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, + uint32_t ulBitsToClearOnExit, + uint32_t * pulNotificationValue, + TickType_t xTicksToWait ) +{ + return xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY, ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ); +} diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index 6dbff63ead..f93d36e04a 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -4,9 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#pragma once - #include "sdkconfig.h" +#include "esp_assert.h" #include "freertos/idf_additions.h" #if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT #include "freertos/task_snapshot.h" @@ -23,7 +22,7 @@ /* ------------------------------------------------- Static Asserts ------------------------------------------------- */ -/** +/* * Both StaticTask_t and TCB_t structures are provided by FreeRTOS sources. * This is just an additional check of the consistency of these structures. */ @@ -33,9 +32,139 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt _Static_assert( tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "CONFIG_FREERTOS_NO_AFFINITY must be the same as tskNO_AFFINITY" ); #endif /* CONFIG_FREERTOS_SMP */ +/* ------------------------------------------------- Kernel Control ------------------------------------------------- */ + +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + +/* + * Wrapper function to take "xKerneLock" + */ + void prvTakeKernelLock( void ) + { + /* We call the tasks.c critical section macro to take xKernelLock */ + taskENTER_CRITICAL( &xKernelLock ); + } + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + +/* + * Wrapper function to release "xKerneLock" + */ + void prvReleaseKernelLock( void ) + { + /* We call the tasks.c critical section macro to release xKernelLock */ + taskEXIT_CRITICAL( &xKernelLock ); + } + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + +/* + * Workaround for non-thread safe multi-core OS startup (see IDF-4524) + */ + void prvStartSchedulerOtherCores( void ) + { + /* This function is always called with interrupts disabled*/ + xSchedulerRunning = pdTRUE; + } + +#endif /* ( CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + + BaseType_t xTaskIncrementTickOtherCores( void ) + { + /* Minor optimization. This function can never switch cores mid + * execution */ + BaseType_t xCoreID = xPortGetCoreID(); + BaseType_t xSwitchRequired = pdFALSE; + + /* This function should never be called by Core 0. */ + configASSERT( xCoreID != 0 ); + + /* Called by the portable layer each time a tick interrupt occurs. + * Increments the tick then checks to see if the new tick value will + * cause any tasks to be unblocked. */ + traceTASK_INCREMENT_TICK( xTickCount ); + + if( uxSchedulerSuspended[ xCoreID ] == ( UBaseType_t ) 0U ) + { + /* We need take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_ISR( &xKernelLock ); + + /* A task being unblocked cannot cause an immediate context switch + * if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Check if core 0 calling xTaskIncrementTick() has + * unblocked a task that can be run. */ + if( uxTopReadyPriority > pxCurrentTCB[ xCoreID ]->uxPriority ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* if ( configUSE_PREEMPTION == 1 ) */ + + /* Tasks of equal priority to the currently running task will share + * processing time (time slice) if preemption is on, and the application + * writer has not explicitly turned time slicing off. */ + #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) + { + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB[ xCoreID ]->uxPriority ] ) ) > ( UBaseType_t ) 1 ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ + + /* Release the previously taken kernel lock as we have finished + * accessing the kernel data structures. */ + taskEXIT_CRITICAL_ISR( &xKernelLock ); + + #if ( configUSE_PREEMPTION == 1 ) + { + if( xYieldPending[ xCoreID ] != pdFALSE ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + + #if ( configUSE_TICK_HOOK == 1 ) + { + vApplicationTickHook(); + } + #endif + + return xSwitchRequired; + } + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ +/*----------------------------------------------------------*/ + /* -------------------------------------------------- Task Creation ------------------------------------------------- */ -#if CONFIG_FREERTOS_SMP +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, @@ -45,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, @@ -85,95 +304,202 @@ _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 ) + +/* + * In ESP-IDF, configUSE_TIMERS is always defined as 1 (i.e., not user configurable). + * However, tasks.c: vTaskStartScheduler() will always call xTimerCreateTimerTask() + * if ( configUSE_TIMERS == 1 ), thus causing the linker to link timers.c and + * wasting some memory (due to the timer task being created)/ + * + * If we provide a weak version of xTimerCreateTimerTask(), this version will be + * compiled if the application does not call any other FreeRTOS timer functions. + * Thus we can save some text/RAM as timers.c will not be linked and the timer + * task never created. + */ + BaseType_t __attribute__( ( weak ) ) xTimerCreateTimerTask( void ) + { + return pdPASS; + } + +#endif /* configUSE_TIMERS */ /*----------------------------------------------------------*/ /* ------------------------------------------------- Task Utilities ------------------------------------------------- */ -#if CONFIG_FREERTOS_SMP - - TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) - { - TaskHandle_t xTaskHandleTemp; - - assert( xCoreID >= 0 && xCoreID < configNUM_CORES ); - taskENTER_CRITICAL(); - xTaskHandleTemp = ( TaskHandle_t ) pxCurrentTCBs[ xCoreID ]; - taskEXIT_CRITICAL(); - return xTaskHandleTemp; - } - -#endif /* CONFIG_FREERTOS_SMP */ -/*----------------------------------------------------------*/ - -#if CONFIG_FREERTOS_SMP +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ) { - assert( xCoreID >= 0 && xCoreID < configNUM_CORES ); + configASSERT( xCoreID >= 0 && xCoreID < configNUM_CORES ); + configASSERT( ( xIdleTaskHandle[ xCoreID ] != NULL ) ); return ( TaskHandle_t ) xIdleTaskHandle[ xCoreID ]; } -#endif /* CONFIG_FREERTOS_SMP */ +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ /*----------------------------------------------------------*/ -#if CONFIG_FREERTOS_SMP +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) - BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) + TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) { - taskENTER_CRITICAL(); - UBaseType_t uxCoreAffinityMask; - #if ( configUSE_CORE_AFFINITY == 1 && configNUM_CORES > 1 ) - TCB_t * pxTCB = prvGetTCBFromHandle( xTask ); - uxCoreAffinityMask = pxTCB->uxCoreAffinityMask; - #else - uxCoreAffinityMask = tskNO_AFFINITY; - #endif - taskEXIT_CRITICAL(); - BaseType_t ret; + TaskHandle_t xReturn; - /* If the task is not pinned to a particular core, treat it as tskNO_AFFINITY */ - if( uxCoreAffinityMask & ( uxCoreAffinityMask - 1 ) ) /* If more than one bit set */ + #if CONFIG_FREERTOS_SMP { - ret = tskNO_AFFINITY; + xReturn = xTaskGetCurrentTaskHandleCPU( xCoreID ); } - else + #else /* CONFIG_FREERTOS_SMP */ { - int index_plus_one = __builtin_ffs( uxCoreAffinityMask ); - assert( index_plus_one >= 1 ); - ret = index_plus_one - 1; + if( xCoreID < configNUM_CORES ) + { + xReturn = pxCurrentTCB[ xCoreID ]; + } + else + { + xReturn = NULL; + } } + #endif /* CONFIG_FREERTOS_SMP */ - return ret; + return xReturn; } -#endif /* CONFIG_FREERTOS_SMP */ +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) +{ + BaseType_t xReturn; + + #if ( configNUM_CORES > 1 ) + { + #if CONFIG_FREERTOS_SMP + UBaseType_t uxCoreAffinityMask; + + /* Get the core affinity mask and covert it to an ID */ + uxCoreAffinityMask = vTaskCoreAffinityGet( xTask ); + + /* If the task is not pinned to a particular core, treat it as tskNO_AFFINITY */ + if( uxCoreAffinityMask & ( uxCoreAffinityMask - 1 ) ) /* If more than one bit set */ + { + xReturn = tskNO_AFFINITY; + } + else + { + int iIndexPlusOne = __builtin_ffs( uxCoreAffinityMask ); + assert( iIndexPlusOne >= 1 ); + xReturn = iIndexPlusOne - 1; + } + #else /* CONFIG_FREERTOS_SMP */ + TCB_t * pxTCB; + + pxTCB = prvGetTCBFromHandle( xTask ); + /* Simply read the xCoreID member of the TCB */ + taskENTER_CRITICAL( &xKernelLock ); + xReturn = pxTCB->xCoreID; + taskEXIT_CRITICAL_ISR( &xKernelLock ); + #endif /* CONFIG_FREERTOS_SMP */ + } + #else /* configNUM_CORES > 1 */ + { + /* Single-core. Just return a core ID of 0 */ + xReturn = 0; + } + #endif /* configNUM_CORES > 1 */ + + return xReturn; +} +/*----------------------------------------------------------*/ + +uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) +{ + TCB_t * pxTCB; + uint8_t * uxReturn; + + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = ( uint8_t * ) pxTCB->pxStack; + + return uxReturn; +} /*----------------------------------------------------------*/ #if ( INCLUDE_vTaskPrioritySet == 1 ) @@ -390,26 +716,61 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt /* --------------------------------------------- TLSP Deletion Callbacks -------------------------------------------- */ -#if ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +#if CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void * pvValue, TlsDeleteCallbackFunction_t pvDelCallback ) { - /* Verify that the offsets of pvThreadLocalStoragePointers and pvDummy15 match. */ - /* pvDummy15 is part of the StaticTask_t struct and is used to access the TLSPs */ - /* while deletion. */ - _Static_assert( offsetof( StaticTask_t, pvDummy15 ) == offsetof( TCB_t, pvThreadLocalStoragePointers ), "Offset of pvDummy15 must match the offset of pvThreadLocalStoragePointers" ); + /* If TLSP deletion callbacks are enabled, then configNUM_THREAD_LOCAL_STORAGE_POINTERS + * is doubled in size so that the latter half of the pvThreadLocalStoragePointers + * stores the deletion callbacks. */ + if( xIndex < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ) + { + TCB_t * pxTCB; - /*Set the local storage pointer first */ - vTaskSetThreadLocalStoragePointer( xTaskToSet, xIndex, pvValue ); + #if ( configNUM_CORES > 1 ) + { + /* For SMP, we need a critical section as another core could also + * update this task's TLSP at the same time. */ + #if CONFIG_FREERTOS_SMP + { + taskENTER_CRITICAL(); + } + #else /* CONFIG_FREERTOS_SMP */ + { + taskENTER_CRITICAL( &xKernelLock ); + } + #endif /* CONFIG_FREERTOS_SMP */ + } + #endif /* configNUM_CORES > 1 */ - /*Set the deletion callback at an offset of configNUM_THREAD_LOCAL_STORAGE_POINTERS/2 */ - vTaskSetThreadLocalStoragePointer( xTaskToSet, ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ), pvDelCallback ); + pxTCB = prvGetTCBFromHandle( xTaskToSet ); + /* Store the TLSP by indexing the first half of the array */ + pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; + + /* Store the TLSP deletion callback by indexing the second half + * of the array. */ + pxTCB->pvThreadLocalStoragePointers[ ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ) ] = ( void * ) pvDelCallback; + + #if ( configNUM_CORES > 1 ) + { + #if CONFIG_FREERTOS_SMP + { + taskEXIT_CRITICAL(); + } + #else /* CONFIG_FREERTOS_SMP */ + { + taskEXIT_CRITICAL( &xKernelLock ); + } + #endif /* CONFIG_FREERTOS_SMP */ + } + #endif /* configNUM_CORES > 1 */ + } } -#endif /* CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ +#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ /*----------------------------------------------------------*/ /* ----------------------------------------------------- Newlib ----------------------------------------------------- */ diff --git a/components/freertos/esp_additions/include/esp_private/freertos_idf_additions_priv.h b/components/freertos/esp_additions/include/esp_private/freertos_idf_additions_priv.h index 2670a46ad2..4f38f5ec99 100644 --- a/components/freertos/esp_additions/include/esp_private/freertos_idf_additions_priv.h +++ b/components/freertos/esp_additions/include/esp_private/freertos_idf_additions_priv.h @@ -20,6 +20,111 @@ #endif /* *INDENT-ON* */ +/*------------------------------------------------------------------------------ + * KERNEL CONTROL (PRIVATE) + *----------------------------------------------------------------------------*/ + +/* + * The following macros are convenience macros used to account for different + * thread safety behavior between Vanilla FreeRTOS (i.e., single-core) and ESP-IDF + * FreeRTOS (i.e., multi-core SMP). + * + * For thread saftey... + * + * - Vanilla FreeRTOS will use the following for thread safety (depending on situation) + * - `vTaskSuspendAll()`/`xTaskResumeAll()` for non-deterministic operations + * - Critical sections or disabling interrupts for deterministic operations + * - ESP-IDF FreeRTOS will always use critical sections (determinism is not supported) + * + * [refactor-todo]: Define these locally in each kernel source file (IDF-8161) + */ +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + + #define prvENTER_CRITICAL_OR_SUSPEND_ALL( x ) taskENTER_CRITICAL( ( x ) ) + #define prvEXIT_CRITICAL_OR_RESUME_ALL( x ) ( { taskEXIT_CRITICAL( ( x ) ); pdFALSE; } ) + #define prvENTER_CRITICAL_OR_MASK_ISR( pxLock, uxInterruptStatus ) \ + { \ + taskENTER_CRITICAL_ISR( ( pxLock ) ); \ + ( void ) ( uxInterruptStatus ); \ + } + #define prvEXIT_CRITICAL_OR_UNMASK_ISR( pxLock, uxInterruptStatus ) \ + { \ + taskEXIT_CRITICAL_ISR( ( pxLock ) ); \ + ( void ) ( uxInterruptStatus ); \ + } + +#elif ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES == 1 ) ) + + #define prvENTER_CRITICAL_OR_SUSPEND_ALL( x ) ( { vTaskSuspendAll(); ( void ) ( x ); } ) + #define prvEXIT_CRITICAL_OR_RESUME_ALL( x ) xTaskResumeAll() + #define prvENTER_CRITICAL_OR_MASK_ISR( pxLock, uxInterruptStatus ) \ + { \ + ( uxInterruptStatus ) = portSET_INTERRUPT_MASK_FROM_ISR(); \ + ( void ) ( pxLock ); \ + } + #define prvEXIT_CRITICAL_OR_UNMASK_ISR( pxLock, uxInterruptStatus ) \ + { \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ( uxInterruptStatus ) ); \ + ( void ) ( pxLock ); \ + } + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES == 1 ) ) */ + +/* + * In ESP-IDF FreeRTOS (i.e., multi-core SMP) uses spinlocks to protect different + * groups of data. This function is a wrapper to take the "xKernelLock" spinlock + * of tasks.c. + * + * This lock is taken whenever any of the kernel's data structures are + * accessed/modified, such as when adding/removing tasks to/from the delayed + * task list or various event lists. + * + * In more cases, kernel data structures are not accessed by functions outside + * tasks.c. Thus, all accesses of the kernel data structures inside tasks.c will + * handle the taking/releasing of the "xKerneLock". + * + * This functions is meant to be called by xEventGroupSetBits() and + * vEventGroupDelete() as both those functions will directly access event lists + * (which are kernel data structures). Thus, a wrapper function must be provided + * to take/release the "xKernelLock" from outside tasks.c. + * + * [refactor-todo]: Extern this locally in event groups (IDF-8161) + */ +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + + void prvTakeKernelLock( void ); + void prvReleaseKernelLock( void ); + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ + +#if ( CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + +/** + * @brief Workaround for non-thread safe multi-core OS startup (see IDF-4524) + * + * This function must be called with interrupts disabled on all cores other than + * core 0 during startup. + */ + void prvStartSchedulerOtherCores( void ); + +#endif /* ( CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ + +/* + * In ESP-IDF FreeRTOS (i.e., multi-core SMP), core 0 manages the the FreeRTOS + * tick count. Thus only core 0 calls xTaskIncrementTick(). + * + * However, all other cores also receive a periodic tick interrupt. Thus all + * other cores should call this function instead. + * + * This function will check if the current core requires time slicing, and also + * call the application tick hook. However, the tick count will remain unchanged. + */ +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + + BaseType_t xTaskIncrementTickOtherCores( void ); + +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ + /*------------------------------------------------------------------------------ * TASK UTILITIES (PRIVATE) *----------------------------------------------------------------------------*/ diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index 41ca5ee14a..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,47 +104,37 @@ StaticTask_t * const pxTaskBuffer, const BaseType_t xCoreID ); -#endif /* ( CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ -/* ------------------------------------------------- Task Utilities ---------------------------------------------------- - * Todo: Move IDF FreeRTOS SMP related additions to this header as well (see IDF-7201) - * ------------------------------------------------------------------------------------------------------------------ */ - -#if CONFIG_FREERTOS_SMP +/* ------------------------------------------------- Task Utilities ------------------------------------------------- */ /** - * @brief Get the handle of the task running on a certain core + * @brief Get the handle of idle task for the given core. + * + * [refactor-todo] See if this needs to be deprecated (IDF-8145) + * + * @note If CONFIG_FREERTOS_SMP is enabled, please call xTaskGetIdleTaskHandle() + * instead. + * @param xCoreID The core to query + * @return Handle of the idle task for the queried core + */ +TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ); + +/** + * @brief Get the handle of the task currently running on a certain core * * Because of the nature of SMP processing, there is no guarantee that this * value will still be valid on return and should only be used for debugging * purposes. * - * [refactor-todo] Mark this function as deprecated, call - * xTaskGetCurrentTaskHandleCPU() instead + * [refactor-todo] See if this needs to be deprecated (IDF-8145) * + * @note If CONFIG_FREERTOS_SMP is enabled, please call xTaskGetCurrentTaskHandleCPU() + * instead. * @param xCoreID The core to query * @return Handle of the current task running on the queried core */ - TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ); - -#endif /* CONFIG_FREERTOS_SMP */ - -#if CONFIG_FREERTOS_SMP - -/** - * @brief Get the handle of idle task for the given CPU. - * - * [refactor-todo] Mark this function as deprecated, call - * xTaskGetIdleTaskHandle() instead - * - * @param xCoreID The core to query - * @return Handle of the idle task for the queried core - */ - TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ); - -#endif /* CONFIG_FREERTOS_SMP */ - -#if CONFIG_FREERTOS_SMP +TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ); /** * @brief Get the current core affinity of a particular task @@ -150,35 +143,44 @@ * pinned to a particular core, the core ID is returned. If the task is not * pinned to a particular core, tskNO_AFFINITY is returned. * - * [refactor-todo] Mark this function as deprecated, call vTaskCoreAffinityGet() - * instead + * If CONFIG_FREERTOS_UNICORE is enabled, this function simply returns 0. * + * [refactor-todo] See if this needs to be deprecated (IDF-8145)(IDF-8164) + * + * @note If CONFIG_FREERTOS_SMP is enabled, please call vTaskCoreAffinityGet() + * instead. * @param xTask The task to query * @return The tasks coreID or tskNO_AFFINITY */ - BaseType_t xTaskGetAffinity( TaskHandle_t xTask ); +BaseType_t xTaskGetAffinity( TaskHandle_t xTask ); -#endif /* CONFIG_FREERTOS_SMP */ - -/* --------------------------------------------- TLSP Deletion Callbacks ----------------------------------------------- - * TLSP Deletion Callback API Additions +/** + * Returns the start of the stack associated with xTask. * - * Todo: Move IDF FreeRTOS TLSP Deletion Callback 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. - * ------------------------------------------------------------------------------------------------------------------ */ + * Returns the lowest stack memory address, regardless of whether the stack + * grows up or down. + * + * [refactor-todo] Change return type to StackType_t (IDF-8158) + * + * @param xTask Handle of the task associated with the stack returned. + * Set xTask to NULL to return the stack of the calling task. + * + * @return A pointer to the start of the stack. + */ +uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ); -#if ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +/* --------------------------------------------- TLSP Deletion Callbacks -------------------------------------------- */ + +#if CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS /** * Prototype of local storage pointer deletion callback. */ typedef void (* TlsDeleteCallbackFunction_t)( int, void * ); +#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ -#endif /* ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) */ - - -#if ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +#if CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS /** * Set local storage pointer and deletion callback. @@ -207,7 +209,7 @@ void * pvValue, TlsDeleteCallbackFunction_t pvDelCallback ); -#endif /* ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) */ +#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ /* -------------------------------------------- Creation With Memory Caps ---------------------------------------------- * Helper functions to create various FreeRTOS objects (e.g., queues, semaphores) with specific memory capabilities diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index f23fac8bfe..31a1b39cfb 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -109,12 +109,9 @@ entries: # - "xTaskGetSchedulerState" # - "xTaskGetTickCount" # -------------------------------------------------------------------------------------------------------------- - tasks:xTaskCreateStaticPinnedToCore (default) - tasks:xTaskCreatePinnedToCore (default) tasks:prvInitialiseNewTask (default) tasks:prvAddNewTaskToReadyList (default) tasks:vTaskDelete (default) - tasks:vTaskDelayUntil (default) tasks:xTaskDelayUntil (default) tasks:vTaskDelay (default) tasks:eTaskGetState (default) @@ -133,7 +130,6 @@ entries: tasks:prvSearchForNameWithinSingleList (default) tasks:xTaskGetHandle (default) tasks:xTaskGetIdleTaskHandle (default) - tasks:xTaskGetIdleTaskHandleForCPU (default) tasks:xTaskAbortDelay (default) # IDF-6410 Application tags not supported yet #tasks:vTaskSetApplicationTaskTag (default) @@ -142,30 +138,22 @@ entries: tasks:vTaskPlaceOnEventList (default) tasks:vTaskPlaceOnUnorderedEventList (default) tasks:vTaskPlaceOnEventListRestricted (default) - if FREERTOS_UNICORE = n: - tasks:vTaskTakeKernelLock (default) - tasks:vTaskReleaseKernelLock (default) tasks:vTaskRemoveFromUnorderedEventList (default) tasks:vTaskSetTimeOutState (default) tasks:vTaskInternalSetTimeOutState (default) tasks:xTaskCheckForTimeOut (default) tasks:vTaskMissedYield (default) tasks:prvIdleTask (default) - if FREERTOS_TLSP_DELETION_CALLBACKS = y: - tasks:vTaskSetThreadLocalStoragePointerAndDelCallback (default) if FREERTOS_THREAD_LOCAL_STORAGE_POINTERS != 0: tasks:vTaskSetThreadLocalStoragePointer (default) tasks:pvTaskGetThreadLocalStoragePointer (default) tasks:prvInitialiseTaskLists (default) tasks:prvCheckTasksWaitingTermination (default) - tasks:xTaskGetAffinity (default) tasks:prvTaskCheckFreeStackSpace (default) tasks:uxTaskGetStackHighWaterMark2 (default) tasks:uxTaskGetStackHighWaterMark (default) - tasks:pxTaskGetStackStart (default) tasks:prvDeleteTCB (default) tasks:xTaskGetCurrentTaskHandle (default) - tasks:xTaskGetCurrentTaskHandleForCPU (default) tasks:xTaskPriorityInherit (default) tasks:xTaskPriorityDisinherit (default) tasks:vTaskPriorityDisinheritAfterTimeout (default) @@ -176,9 +164,7 @@ entries: tasks:vTaskGetRunTimeStats (default) tasks:uxTaskResetEventItemValue (default) tasks:pvTaskIncrementMutexHeldCount (default) - tasks:ulTaskNotifyTake (default) tasks:ulTaskGenericNotifyTake (default) - tasks:xTaskNotifyWait (default) tasks:xTaskGenericNotifyWait (default) tasks:xTaskGenericNotify (default) tasks:xTaskGenericNotifyStateClear (default) diff --git a/components/freertos/linker_common.lf b/components/freertos/linker_common.lf index 0756332bbb..d836cf4902 100644 --- a/components/freertos/linker_common.lf +++ b/components/freertos/linker_common.lf @@ -17,14 +17,19 @@ entries: # to always keep it in IRAM # ------------------------------------------------------------------------------------------------------------------ if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y: + # Kernel Control + if FREERTOS_SMP = n && FREERTOS_UNICORE = n: + 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) + tasks:xTaskGetCurrentTaskHandleForCPU (default) tasks:xTaskGetAffinity (default) + tasks:pxTaskGetStackStart (default) tasks:prvTaskPriorityRaise (default) tasks:prvTaskPriorityRestore (default) # TLSP Deletion Callbacks @@ -36,6 +41,12 @@ entries: tasks:pxTaskGetNext (default) tasks:uxTaskGetSnapshotAll (default) + # ------------------------------------------------------------------------------------------------------------------ + # freertos_compatibility.c + # Placement Rules: Functions always in flash as they are never called from an ISR + # ------------------------------------------------------------------------------------------------------------------ + freertos_compatibility (default) + # ------------------------------------------------------------------------------------------------------------------ # idf_additions.c # Placement Rules: Functions always in flash as they are never called from an ISR diff --git a/components/freertos/port_systick.c b/components/freertos/port_systick.c index eedafc750b..73bd161108 100644 --- a/components/freertos/port_systick.c +++ b/components/freertos/port_systick.c @@ -9,6 +9,10 @@ #include #include "FreeRTOS.h" #include "task.h" +#if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) + /* Required for xTaskIncrementTickOtherCores() */ + #include "esp_private/freertos_idf_additions_priv.h" +#endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ #if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT #if CONFIG_FREERTOS_CORETIMER_0 diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c b/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c index 2917f3c0b7..3ca6e90046 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c @@ -115,11 +115,13 @@ static void unpinned_task(void *arg) vTaskSuspendAll(); #endif // Check that the task is unpinned +#if !CONFIG_FREERTOS_UNICORE #if CONFIG_FREERTOS_SMP TEST_ASSERT_EQUAL(tskNO_AFFINITY, vTaskCoreAffinityGet(NULL)); #else TEST_ASSERT_EQUAL(tskNO_AFFINITY, xTaskGetAffinity(NULL)); #endif +#endif // !CONFIG_FREERTOS_UNICORE // Allocate an ISR to use the FPU intr_handle_t isr_handle; @@ -130,11 +132,13 @@ static void unpinned_task(void *arg) esp_intr_free(isr_handle); // Task should remain unpinned after the ISR uses the FPU +#if !CONFIG_FREERTOS_UNICORE #if CONFIG_FREERTOS_SMP TEST_ASSERT_EQUAL(tskNO_AFFINITY, vTaskCoreAffinityGet(NULL)); #else TEST_ASSERT_EQUAL(tskNO_AFFINITY, xTaskGetAffinity(NULL)); #endif +#endif // !CONFIG_FREERTOS_UNICORE // Reenable scheduling/preemption #if CONFIG_FREERTOS_SMP vTaskPreemptionEnable(NULL); diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c index a829ed9adf..6bde01e388 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c @@ -137,11 +137,13 @@ static void unpinned_task(void *arg) #endif BaseType_t cur_core_num = xPortGetCoreID(); // Check that the task is unpinned +#if !CONFIG_FREERTOS_UNICORE #if CONFIG_FREERTOS_SMP TEST_ASSERT_EQUAL(tskNO_AFFINITY, vTaskCoreAffinityGet(NULL)); #else TEST_ASSERT_EQUAL(tskNO_AFFINITY, xTaskGetAffinity(NULL)); #endif +#endif // !CONFIG_FREERTOS_UNICORE /* Use the FPU @@ -156,11 +158,13 @@ static void unpinned_task(void *arg) // We allow a 0.1% delta on the final result in case of any loss of precision from floating point calculations TEST_ASSERT_FLOAT_WITHIN(0.00256f, 2.56f, test_float); +#if !CONFIG_FREERTOS_UNICORE #if CONFIG_FREERTOS_SMP TEST_ASSERT_EQUAL(1 << cur_core_num, vTaskCoreAffinityGet(NULL)); #else TEST_ASSERT_EQUAL(cur_core_num, xTaskGetAffinity(NULL)); #endif +#endif // !CONFIG_FREERTOS_UNICORE // Reenable scheduling/preemption #if CONFIG_FREERTOS_SMP vTaskPreemptionEnable(NULL); 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)