freertos-smp: refactor thread local storage pointers deletion callbacks

This commit updates how the TLS pointers deletion callbacks are called
during task deletion in the FreeRTOS SMP kernel. The callbacks are now
routed through the portCLEAN_UP_TCB() macro. This commit also adds a
new kconfig option CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS to control
the enablement of the TLSP deletion callbacks.
This commit is contained in:
Sudeep Mohanty 2022-05-02 10:59:54 +05:30
parent 62800f8e3b
commit 283f569a03
8 changed files with 111 additions and 76 deletions

View File

@ -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;

View File

@ -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

View File

@ -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[];

View File

@ -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 );

View File

@ -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) {

View File

@ -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

View File

@ -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__

View File

@ -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