Преглед изворни кода

Merge branch 'refactor/refactor-freertos-tls-del-cb' into 'master'

freertos-smp: refactor thread local storage pointers deletion callbacks

Closes IDF-3330

See merge request espressif/esp-idf!17972
Sudeep Mohanty пре 3 година
родитељ
комит
6fba3fc645

+ 0 - 5
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;

+ 0 - 33
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

+ 10 - 2
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[];

+ 37 - 2
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 );

+ 0 - 34
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) {

+ 11 - 0
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

+ 37 - 0
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__

+ 16 - 0
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