diff --git a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h index 7faa8a8344..6aa3b803c0 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h @@ -1229,11 +1229,6 @@ typedef struct xSTATIC_TCB #endif #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) void * pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; - #ifdef ESP_PLATFORM - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - void *pvDummaTLSDelCb[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; - #endif - #endif //ESP_PLATFORM #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) uint32_t ulDummy16; diff --git a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h index 73a37bc44c..2f2e75892a 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/task.h @@ -3279,39 +3279,6 @@ void vTaskYieldWithinAPI( void ); #ifdef ESP_PLATFORM -#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - - /** - * 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 - #include "idf_additions.h" #endif //ESP_PLATFORM diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/FreeRTOSConfig_smp.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/FreeRTOSConfig_smp.h index 4c3a2646fb..d2a89eeb51 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/FreeRTOSConfig_smp.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/FreeRTOSConfig_smp.h @@ -164,7 +164,17 @@ This file get's pulled into assembly sources. Therefore, some includes need to b #define configMAX_TASK_NAME_LEN CONFIG_FREERTOS_MAX_TASK_NAME_LEN +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +/* If thread local storage pointer deletion callbacks are registered + * then we double the storage space reserved for the thread local + * storage pointers in the task TCB. The first half of the storage area + * is used to store the TLS pointers themselves while the second half + * is used to store the respective deletion callbacks. + */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS ( CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS * 2 ) +#else #define configNUM_THREAD_LOCAL_STORAGE_POINTERS CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS +#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS #define configSTACK_DEPTH_TYPE uint32_t #define configUSE_NEWLIB_REENTRANT 1 #define configENABLE_BACKWARD_COMPATIBILITY 0 @@ -276,8 +286,6 @@ Default values for trace macros added by ESP-IDF and are not part of Vanilla Fre #define configTASKLIST_INCLUDE_COREID 1 #endif -#define configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS 1 - #ifndef __ASSEMBLER__ #if CONFIG_APPTRACE_SV_ENABLE extern uint32_t port_switch_flag[]; diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index f43c0e1dd7..1f3d396564 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -579,6 +579,38 @@ void vPortCleanUpCoprocArea( void * pxTCB ) } #endif /* XCHAL_CP_NUM > 0 */ +// ------- Thread Local Storage Pointers Deletion Callbacks ------- + +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +void vPortTLSPointersDelCb( void * pxTCB ) +{ + /* Typecast pxTCB to StaticTask_t type to access TCB struct members. + * pvDummy15 corresponds to pvThreadLocalStoragePointers member of the TCB. + */ + StaticTask_t *tcb = ( StaticTask_t * )pxTCB; + + /* The TLSP deletion callbacks are stored at an offset of (configNUM_THREAD_LOCAL_STORAGE_POINTERS/2) */ + TlsDeleteCallbackFunction_t *pvThreadLocalStoragePointersDelCallback = ( TlsDeleteCallbackFunction_t * )( &( tcb->pvDummy15[ ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ] ) ); + + /* We need to iterate over half the depth of the pvThreadLocalStoragePointers area + * to access all TLS pointers and their respective TLS deletion callbacks. + */ + for( int x = 0; x < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ); x++ ) + { + if ( pvThreadLocalStoragePointersDelCallback[ x ] != NULL ) //If del cb is set + { + /* In case the TLSP deletion callback has been overwritten by a TLS pointer, gracefully abort. */ + if ( !esp_ptr_executable( pvThreadLocalStoragePointersDelCallback[ x ] ) ) { + ESP_LOGE("FreeRTOS", "Fatal error: TLSP deletion callback at index %d overwritten with non-excutable pointer %p", x, pvThreadLocalStoragePointersDelCallback[ x ]); + abort(); + } + + pvThreadLocalStoragePointersDelCallback[ x ]( x, tcb->pvDummy15[ x ] ); //Call del cb + } + } +} +#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS + // -------------------- Tick Handler ----------------------- extern void esp_vApplicationIdleHook(void); @@ -655,11 +687,14 @@ void vApplicationMinimalIdleHook( void ) /* * Hook function called during prvDeleteTCB() to cleanup any * user defined static memory areas in the TCB. - * Currently, this hook function is used by the port to cleanup - * the Co-processor save area for targets that support co-processors. */ void vPortCleanUpTCB ( void *pxTCB ) { +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) + /* Call TLS pointers deletion callbacks */ + vPortTLSPointersDelCb( pxTCB ); +#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ + #if XCHAL_CP_NUM > 0 /* Cleanup coproc save area */ vPortCleanUpCoprocArea( pxTCB ); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c index aafaf3dccc..69becd6756 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c @@ -286,11 +286,6 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; - #ifdef ESP_PLATFORM - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - TlsDeleteCallbackFunction_t pvThreadLocalStoragePointersDelCallback[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; - #endif - #endif //ESP_PLATFORM #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -1544,11 +1539,6 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) { memset( ( void * ) &( pxNewTCB->pvThreadLocalStoragePointers[ 0 ] ), 0x00, sizeof( pxNewTCB->pvThreadLocalStoragePointers ) ); - #ifdef ESP_PLATFORM - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - memset ( (void * ) &( pxNewTCB->pvThreadLocalStoragePointersDelCallback[0] ), 0x00, sizeof( pxNewTCB->pvThreadLocalStoragePointersDelCallback ) ); - #endif - #endif //ESP_PLATFORM } #endif @@ -4928,17 +4918,6 @@ static void prvCheckTasksWaitingTermination( void ) static void prvDeleteTCB( TCB_t * pxTCB ) { - #ifdef ESP_PLATFORM - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - for( int x = 0; x < configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) - { - if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL) //If del cb is set - { - pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]); //Call del cb - } - } - #endif - #endif //ESP_PLATFORM /* This call is required specifically for the TriCore port. It must be * above the vPortFree() calls. The call is also used by ports/demos that @@ -6467,19 +6446,6 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, * ------------------------------------------------------------------------------------------------------------------ */ #ifdef ESP_PLATFORM - -#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue , TlsDeleteCallbackFunction_t xDelCallback) - { - //Set the local storage pointer first - vTaskSetThreadLocalStoragePointer(xTaskToSet, xIndex, pvValue); - //Set the deletion callback - TCB_t * pxTCB; - pxTCB = prvGetTCBFromHandle( xTaskToSet ); - pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback; - } -#endif - #if ( configUSE_NEWLIB_REENTRANT == 1 ) //Return global reent struct if FreeRTOS isn't running, struct _reent* __getreent(void) { diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 07b7057ce6..f2285db299 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -183,6 +183,17 @@ menu "FreeRTOS" This value must be at least 1. Index 0 is reserved for use by the pthreads API thread-local-storage. Other indexes can be used for any desired purpose. + config FREERTOS_TLSP_DELETION_CALLBACKS + bool "Enable thread local storage pointers deletion callbacks" + depends on FREERTOS_SMP && (FREERTOS_THREAD_LOCAL_STORAGE_POINTERS > 0) + default y + help + ESP-IDF provides users with the ability to free TLSP memory by registering TLSP deletion callbacks. + These callbacks are automatically called by FreeRTOS when a task is deleted. + When this option is turned on, the memory reserved for TLSPs in the TCB is doubled + to make space for storing the deletion callbacks. If the user does not wish to use TLSP deletion + callbacks then this option could be turned off to save space in the TCB memory. + config FREERTOS_IDLE_TASK_STACKSIZE int "Idle Task stack size" range 768 32768 diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index bd62facee2..038deb950d 100644 --- a/components/freertos/esp_additions/include/freertos/idf_additions.h +++ b/components/freertos/esp_additions/include/freertos/idf_additions.h @@ -103,4 +103,41 @@ TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ); */ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ); +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) + + /** + * 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 // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS + #endif // CONFIG_FREERTOS_SMP || __DOXYGEN__ diff --git a/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h index 385d5568ea..faa0415813 100644 --- a/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h @@ -342,4 +342,20 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) return ret; } +#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"); + + //Set the local storage pointer first + vTaskSetThreadLocalStoragePointer( xTaskToSet, xIndex, pvValue ); + + //Set the deletion callback at an offset of configNUM_THREAD_LOCAL_STORAGE_POINTERS/2 + vTaskSetThreadLocalStoragePointer( xTaskToSet, ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ), pvDelCallback ); + } +#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS + #endif // CONFIG_FREERTOS_SMP