From 29c2e58c75232e9e07d85fb0ae9bc9643d9e68f4 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 24 Aug 2016 13:29:06 +0800 Subject: [PATCH] 'Merge branch 'thread_local_storage_delete_callbacks' into 'master' The thread-local-storage feature in FreeRTOS attaches an application-usable array of pointers to a thread control block. These pointers usually point to a structure the thread allocates. When a thread gets (voluntarily or involuntarily) destroyed, this memory can leak. This merge adds a matching second array of user-settable pointers to destructor routines. As soon as the task gets cleaned up (which happens in the idle thread), the destructors get called and the memory can be freed. See merge request !19 --- components/freertos/Kconfig | 2 +- .../include/freertos/FreeRTOSConfig.h | 1 + components/freertos/include/freertos/task.h | 5 ++ components/freertos/readme_smp.txt | 6 +++ components/freertos/tasks.c | 46 ++++++++++++++++++- components/lwip/Kconfig | 7 +++ 6 files changed, 64 insertions(+), 3 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 8c05199f8..89227a7dd 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -73,7 +73,7 @@ config FREERTOS_CHECK_STACKOVERFLOW_CANARY (configCHECK_FOR_STACK_OVERFLOW=2) endchoice -config CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS +config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS int "Amount of thread local storage pointers" range 0 256 default 0 diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index 78567d548..c0a86efed 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -97,6 +97,7 @@ #endif #define configNUM_THREAD_LOCAL_STORAGE_POINTERS CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS +#define configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS 1 /* TODO: config freq by menuconfig */ #define XT_CLOCK_FREQ 80000000 diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index d4b9d43c8..d771ca653 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -1175,6 +1175,11 @@ constant. */ void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) PRIVILEGED_FUNCTION; void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + typedef void (*TlsDeleteCallbackFunction_t)( int, void * ); + void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue , TlsDeleteCallbackFunction_t xDelCallback); + #endif + #endif /** diff --git a/components/freertos/readme_smp.txt b/components/freertos/readme_smp.txt index 0f7a66d74..38f332416 100644 --- a/components/freertos/readme_smp.txt +++ b/components/freertos/readme_smp.txt @@ -24,3 +24,9 @@ means that when you set a handler for an interrupt, it will get triggered if the interrupt is triggered on both CPU0 as well as on CPU1. This is something we may change in future FreeRTOS-esp32 releases. +- This FreeRTOS version has the task local storage backported from the 8.2.x +versions. It, however, has an addition: you can also set a callback when you +set the pointer. This callback will be called by the idle task, with the +pointer as an argument, when the thread is destroyed. This depends on the idle +task getting CPU time; when a thread is hogging the CPU without yielding, +the idle thread won't be called and the delete callback won't be called either. diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index f0e4fb120..fff7f49f8 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -180,6 +180,9 @@ typedef struct tskTaskControlBlock #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + TlsDeleteCallbackFunction_t pvThreadLocalStoragePointersDelCallback[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -3045,7 +3048,10 @@ UBaseType_t x; { for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) { - pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL; + pxTCB->pvThreadLocalStoragePointers[ x ] = NULL; + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] = (TlsDeleteCallbackFunction_t)NULL; + #endif } } #endif @@ -3068,6 +3074,29 @@ UBaseType_t x; /*-----------------------------------------------------------*/ #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) +#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + + void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue , TlsDeleteCallbackFunction_t xDelCallback) + { + TCB_t *pxTCB; + + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToSet ); + taskENTER_CRITICAL(&xTaskQueueMutex); + pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; + pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback; + taskEXIT_CRITICAL(&xTaskQueueMutex); + } + } + + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) + { + vTaskSetThreadLocalStoragePointerAndDelCallback( xTaskToSet, xIndex, pvValue, (TlsDeleteCallbackFunction_t)NULL ); + } + + +#else void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) { TCB_t *pxTCB; @@ -3078,6 +3107,7 @@ UBaseType_t x; pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; } } +#endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS */ #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ /*-----------------------------------------------------------*/ @@ -3181,7 +3211,19 @@ static void prvCheckTasksWaitingTermination( void ) --uxTasksDeleted; } taskEXIT_CRITICAL(&xTaskQueueMutex); - + + #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + { + int x; + for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) + { + if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL) + { + pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]); + } + } + } + #endif prvDeleteTCB( pxTCB ); } else diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index ee6511e00..8f38ba931 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -9,6 +9,13 @@ config LWIP_MAX_SOCKETS sockets to be open at the same time conserves memory. Specify the maximum amount of sockets here. +config LWIP_THREAD_LOCAL_STORAGE_INDEX + int "Index for thread-local-storage pointer for lwip" + default 0 + help + Specify the thread-local-storage-pointer index for lwip + use. + endmenu