Explorar el Código

Merge branch 'feature/freertos_update_task_snapshot_implementation' into 'master'

FreeRTOS: Update Task Snapshot Implementation

Closes IDF-3334

See merge request espressif/esp-idf!17496
Darian hace 3 años
padre
commit
82e9afeade

+ 2 - 3
components/freertos/CMakeLists.txt

@@ -31,7 +31,6 @@ if(CONFIG_FREERTOS_SMP)
     endif()
 
     list(APPEND srcs
-        "esp_additions/task_snapshot.c"
         "FreeRTOS-Kernel-SMP/croutine.c"
         "FreeRTOS-Kernel-SMP/event_groups.c"
         "FreeRTOS-Kernel-SMP/list.c"
@@ -92,7 +91,6 @@ else()
     endif()
 
     list(APPEND srcs
-        "esp_additions/task_snapshot.c"
         "FreeRTOS-Kernel/portable/port_common.c"
         "FreeRTOS-Kernel/portable/port_systick.c"
         "FreeRTOS-Kernel/croutine.c"
@@ -106,7 +104,8 @@ else()
         "esp_additions/freertos_v8_compat.c")
 
     list(APPEND private_include_dirs
-        "FreeRTOS-Kernel/include/freertos")
+        "FreeRTOS-Kernel/include/freertos"
+        "esp_additions/private_include")    # For #include "tasks_test_access_functions.h
 
     if(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
         list(APPEND srcs "FreeRTOS-Kernel/portable/xtensa/xtensa_loadstore_handler.S")

+ 0 - 6
components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/FreeRTOSConfig_smp.h

@@ -285,12 +285,6 @@ extern uint32_t port_switch_flag[];
 
 // ---------------------- Features -------------------------
 
-#ifdef CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
-#define configENABLE_TASK_SNAPSHOT                      1
-#else
-#define configENABLE_TASK_SNAPSHOT                      0
-#endif
-
 /* These currently aren't required, but could be useful additions in the future */
 #if 0
 #ifndef configIDLE_TASK_STACK_SIZE

+ 1 - 1
components/freertos/Kconfig

@@ -462,7 +462,7 @@ menu "FreeRTOS"
         default y
         help
             When enabled, the functions related to snapshots, such as vTaskGetSnapshot or uxTaskGetSnapshotAll,
-            are compiled and linked.
+            are compiled and linked. Task snapshots are primarily used by GDB Stub and Core dump.
 
     config FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH
         bool "Place task snapshot functions into flash"

+ 1 - 6
components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h

@@ -246,12 +246,7 @@ Note: Include trace macros here and not above as trace macros are dependent on s
 #ifndef configIDLE_TASK_STACK_SIZE
 #define configIDLE_TASK_STACK_SIZE                      CONFIG_FREERTOS_IDLE_TASK_STACKSIZE
 #endif
-#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
-#define configENABLE_TASK_SNAPSHOT                      1
-#endif
-#ifndef configENABLE_TASK_SNAPSHOT
-#define configENABLE_TASK_SNAPSHOT                      0
-#endif
+
 #if CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER
 #define configCHECK_MUTEX_GIVEN_BY_OWNER                1
 #else

+ 49 - 52
components/freertos/esp_additions/include/freertos/task_snapshot.h

@@ -6,77 +6,74 @@
 
 #pragma once
 
+#include "sdkconfig.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 
-#if ( configENABLE_TASK_SNAPSHOT == 1 )
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT || defined __DOXYGEN__
 /**
- * Check `freertos_tasks_c_additions.h` file for more info
- * about these functions declaration.
- */
-UBaseType_t pxTCBGetSize ( void );
-ListItem_t*	pxTCBGetStateListItem ( void *pxTCB );
-StackType_t* pxTCBGetStartOfStack ( void *pxTCB );
-StackType_t* pxTCBGetTopOfStack ( void *pxTCB );
-StackType_t* pxTCBGetEndOfStack ( void *pxTCB );
-List_t* pxListGetReadyTask ( UBaseType_t idx );
-List_t* pxListGetReadyPendingTask ( UBaseType_t idx );
-List_t* pxGetDelayedTaskList ( void );
-List_t* pxGetOverflowDelayedTaskList ( void );
-List_t* pxGetTasksWaitingTermination ( void );
-List_t* pxGetSuspendedTaskList ( void );
-
-/**
- * Used with the uxTaskGetSnapshotAll() function to save memory snapshot of each task in the system.
- * We need this struct because TCB_t is defined (hidden) in tasks.c.
+ * @brief Task Snapshot structure
+ *
+ * - Used with the uxTaskGetSnapshotAll() function to save memory snapshot of each task in the system.
+ * - We need this structure because TCB_t is defined (hidden) in tasks.c.
  */
 typedef struct xTASK_SNAPSHOT
 {
-	void        *pxTCB;         /*!< Address of task control block. */
-	StackType_t *pxTopOfStack;  /*!< Points to the location of the last item placed on the tasks stack. */
-	StackType_t *pxEndOfStack;  /*!< Points to the end of the stack. pxTopOfStack < pxEndOfStack, stack grows hi2lo
-									pxTopOfStack > pxEndOfStack, stack grows lo2hi*/
+    void        *pxTCB;         /*!< Address of the task control block. */
+    StackType_t *pxTopOfStack;  /*!< Points to the location of the last item placed on the tasks stack. */
+    StackType_t *pxEndOfStack;  /*!< Points to the end of the stack. pxTopOfStack < pxEndOfStack, stack grows hi2lo
+                                    pxTopOfStack > pxEndOfStack, stack grows lo2hi*/
 } TaskSnapshot_t;
 
-
-/*
- * This function fills array with TaskSnapshot_t structures for every task in the system.
- * Used by panic handling code to get snapshots of all tasks in the system.
- * Only available when configENABLE_TASK_SNAPSHOT is set to 1.
- * @param pxTaskSnapshotArray Pointer to array of TaskSnapshot_t structures to store tasks snapshot data.
- * @param uxArraySize Size of tasks snapshots array.
- * @param pxTcbSz Pointer to store size of TCB.
- * @return Number of elements stored in array.
- */
-UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz );
-
-/*
- * This function iterates over all tasks in the system.
- * Used by panic handling code to iterate over tasks in the system.
- * Only available when configENABLE_TASK_SNAPSHOT is set to 1.
- * @note This function should not be used while FreeRTOS is running (as it doesn't acquire any locks).
- * @param pxTask task handle.
- * @return Handle for the next task. If pxTask is NULL, returns hadnle for the first task.
+/**
+ * @brief Iterate over all tasks in the system
+ *
+ * - This function can be used to iterate over every task in the system
+ * - The first call to this function must set pxTask to NULL
+ * - When all functions have been iterated, this function will return NULL.
+ * - This function is only available when CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is set to 1.
+ *
+ * @note This function should only be called when FreeRTOS is no longer running (e.g., during a panic) as this function
+ * 		 does not acquire any locks.
+ * @param pxTask Handle of the previous task (or NULL on the first call of this function)
+ * @return TaskHandle_t Handle of the next task (or NULL when all tasks have been iterated over)
  */
 TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask );
 
-/*
- * This function fills TaskSnapshot_t structure for specified task.
- * Used by panic handling code to get snapshot of a task.
- * Only available when configENABLE_TASK_SNAPSHOT is set to 1.
- * @note This function should not be used while FreeRTOS is running (as it doesn't acquire any locks).
- * @param pxTask task handle.
- * @param pxTaskSnapshot address of TaskSnapshot_t structure to fill.
+/**
+ * @brief Fill a TaskSnapshot_t structure for specified task.
+ *
+ * - This function is used by the panic handler to get the snapshot of a particular task.
+ * - This function is only available when CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is set to 1.
+ *
+ * @note This function should only be called when FreeRTOS is no longer running (e.g., during a panic) as this function
+ * 		 does not acquire any locks.
+ * @param[in] pxTask Task's handle
+ * @param[out] pxTaskSnapshot Snapshot of the task
  */
 void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot );
 
+/**
+ * @brief Fill an array of TaskSnapshot_t structures for every task in the system
+ *
+ * - This function is used by the panic handler to get a snapshot of all tasks in the system
+ * - This function is only available when CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is set to 1.
+ *
+ * @note This function should only be called when FreeRTOS is no longer running (e.g., during a panic) as this function
+ * 		 does not acquire any locks.
+ * @param[out] pxTaskSnapshotArray Array of TaskSnapshot_t structures filled by this function
+ * @param[in] uxArrayLength Length of the provided array
+ * @param[out] pxTCBSize Size of the a task's TCB structure
+ * @return UBaseType_t
+ */
+UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArrayLength, UBaseType_t * const pxTCBSize );
+
+#endif // CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT || defined __DOXYGEN__
+
 #ifdef __cplusplus
 }
 #endif
-
-#endif

+ 0 - 108
components/freertos/esp_additions/include/freertos_tasks_c_additions.h

@@ -1,108 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#pragma once
-
-/**
- * This file will be included in `tasks.c` file, thus, it must NOT be included
- * by any (other) file.
- * The functions below only consist in getters for the static variables in
- * `tasks.c` file.
- * The only source files that should call these functions are the ones in
- * `/additions` directory.
- */
-
-#if ( configENABLE_TASK_SNAPSHOT == 1 )
-
-	UBaseType_t pxTCBGetSize ( void )
-	{
-		return sizeof(TCB_t);
-	}
-
-	ListItem_t*	pxTCBGetStateListItem ( void *pxTCB )
-	{
-		return &(((TCB_t*)pxTCB)->xStateListItem);
-	}
-
-	StackType_t* pxTCBGetStartOfStack ( void *pxTCB )
-	{
-		return (StackType_t*) ((TCB_t*)pxTCB)->pxStack;
-	}
-
-	StackType_t* pxTCBGetTopOfStack ( void *pxTCB )
-	{
-		return (StackType_t*) ((TCB_t*)pxTCB)->pxTopOfStack;
-	}
-
-	StackType_t* pxTCBGetEndOfStack ( void *pxTCB )
-	{
-		return (StackType_t*) ((TCB_t*)pxTCB)->pxEndOfStack;
-	}
-
-
-	List_t* pxListGetReadyTask ( UBaseType_t idx )
-	{
-		return &( pxReadyTasksLists[idx] );
-	}
-
-	List_t* pxListGetReadyPendingTask ( UBaseType_t idx )
-	{
-#ifdef CONFIG_FREERTOS_SMP
-		return &( xPendingReadyList );
-#else
-		return &( xPendingReadyList[idx] );
-#endif
-	}
-
-	List_t* pxGetDelayedTaskList ( void ) {
-		return pxDelayedTaskList;
-	}
-
-	List_t* pxGetOverflowDelayedTaskList ( void ) {
-		return pxOverflowDelayedTaskList;
-	}
-
-	List_t* pxGetTasksWaitingTermination ( void ) {
-		return &xTasksWaitingTermination;
-	}
-
-	List_t* pxGetSuspendedTaskList ( void ) {
-		return &xSuspendedTaskList;
-	}
-
-#endif
-
-#if ( configENABLE_FREERTOS_DEBUG_OCDAWARE == 1 )
-
-/**
- * Debug param indexes. DO NOT change the order. OpenOCD uses the same indexes
- * Entries in FreeRTOS_openocd_params must match the order of these indexes
- */
-enum {
-	ESP_FREERTOS_DEBUG_TABLE_SIZE = 0,
-	ESP_FREERTOS_DEBUG_TABLE_VERSION,
-	ESP_FREERTOS_DEBUG_KERNEL_VER_MAJOR,
-	ESP_FREERTOS_DEBUG_KERNEL_VER_MINOR,
-	ESP_FREERTOS_DEBUG_KERNEL_VER_BUILD,
-	ESP_FREERTOS_DEBUG_UX_TOP_USED_PIORITY,
-	ESP_FREERTOS_DEBUG_PX_TOP_OF_STACK,
-	ESP_FREERTOS_DEBUG_PC_TASK_NAME,
-	/* New entries must be inserted here */
-	ESP_FREERTOS_DEBUG_TABLE_END,
-};
-
-const DRAM_ATTR uint8_t FreeRTOS_openocd_params[ESP_FREERTOS_DEBUG_TABLE_END]  = {
-	ESP_FREERTOS_DEBUG_TABLE_END,	 /* table size */
-	1,								 /* table version */
-	tskKERNEL_VERSION_MAJOR,
-	tskKERNEL_VERSION_MINOR,
-	tskKERNEL_VERSION_BUILD,
-	configMAX_PRIORITIES - 1, 		 /* uxTopUsedPriority */
-	offsetof(TCB_t, pxTopOfStack),	 /* thread_stack_offset; */
-	offsetof(TCB_t, pcTaskName),	 /* thread_name_offset; */
-};
-
-#endif

+ 239 - 0
components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h

@@ -0,0 +1,239 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "sdkconfig.h"
+
+/**
+ * This file will be included in `tasks.c` file, thus, it must NOT be included
+ * by any (other) file.
+ * The functions below only consist in getters for the static variables in
+ * `tasks.c` file.
+ * The only source files that should call these functions are the ones in
+ * `/additions` directory.
+ */
+
+/* -------------------------------------------------- Task Snapshot ----------------------------------------------------
+ *
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
+
+#include "task_snapshot.h"
+
+/**
+ * @brief List of all task lists in FreeRTOS
+ *
+ * @note There are currently differing number of task list between SMP FreeRTOS and ESP-IDF FreeRTOS
+ */
+static List_t *non_ready_task_lists[] = {
+    #ifdef CONFIG_FREERTOS_SMP
+        &xPendingReadyList,
+    #else
+        &xPendingReadyList[0],
+        #ifndef CONFIG_FREERTOS_UNICORE
+            &xPendingReadyList[1],
+        #endif // CONFIG_FREERTOS_UNICORE
+    #endif //CONFIG_FREERTOS_SMP
+    &xDelayedTaskList1,
+    &xDelayedTaskList2,
+    #if( INCLUDE_vTaskDelete == 1 )
+        &xTasksWaitingTermination,
+    #endif
+    #if( INCLUDE_vTaskSuspend == 1 )
+        &xSuspendedTaskList,
+    #endif
+};
+
+/**
+ * @brief Get the next task list to traverse
+ *
+ * - Given a particular task list, this function returns the next task to traverse.
+ * - The task lists are returned in the following precedence
+ *      - Ready lists (highest to lowers priority)
+ *      - Pending ready list(s)
+ *      - Delayed list 1
+ *      - Delayed list 2
+ *      - Waiting termination list
+ *      - Suspended list
+ *
+ * @param pxCurTaskList Previously traversed task list (or NULL if obtaining the first task list)
+ * @return List_t* The next task list to traverse (or NULL of all task lists have been traversed)
+ */
+static List_t *pxGetNextTaskList(List_t *pxCurTaskList)
+{
+    List_t *pxNextTaskList = NULL;
+
+    // No Current List. Start from the highest priority ready task list
+    if (pxCurTaskList == NULL)
+    {
+        pxNextTaskList = &pxReadyTasksLists[configMAX_PRIORITIES - 1];
+    }
+    // Current list is one of the ready task lists. Find the current priority, and return the next lower priority ready task list
+    else if (pxCurTaskList >= &pxReadyTasksLists[0] && pxCurTaskList <= &pxReadyTasksLists[configMAX_PRIORITIES - 1] )
+    {
+        // Find the current priority
+        int cur_priority;
+        for (cur_priority = configMAX_PRIORITIES - 1; cur_priority >= 0; cur_priority--) {
+            if (pxCurTaskList == &pxReadyTasksLists[cur_priority]) {
+                break;
+            }
+        }
+        // Return the ready task list at (cur_priority - 1), or the pending ready task list
+        if (cur_priority > 0)
+        {
+            pxNextTaskList = &pxReadyTasksLists[cur_priority - 1];
+        }
+        // We've reached the end of the Ready Task Lists.  We get the next list from the non-ready task lists
+        else if (cur_priority == 0)
+        {
+            pxNextTaskList = non_ready_task_lists[0];
+        }
+        else
+        {
+            abort();    // This should never occur
+        }
+    }
+
+    // Current list is one of the non-ready task lists. Fetch the next non-ready task list
+    if (pxNextTaskList == NULL) {
+        int cur_list_idx;
+        const int num_non_ready_task_lists = (sizeof(non_ready_task_lists) / sizeof(List_t *));
+        // Note: - 1 so that if the current list is the last on non_ready_task_lists[], the next list will return NULL
+        for (cur_list_idx = 0; cur_list_idx < num_non_ready_task_lists - 1; cur_list_idx++) {
+            if (pxCurTaskList == non_ready_task_lists[cur_list_idx]) {
+                pxNextTaskList = non_ready_task_lists[cur_list_idx + 1];
+                break;
+            }
+        }
+    }
+
+    return pxNextTaskList;
+}
+
+TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
+{
+    TCB_t *pxTCB = (TCB_t *)pxTask;
+    // Check current task is valid
+    if (pxTCB != NULL && !portVALID_TCB_MEM(pxTCB)) {
+        return NULL;
+    }
+
+    List_t *pxCurTaskList;
+    const ListItem_t *pxCurListItem;
+    if (pxTCB == NULL) {
+        // Starting traversal for the first time
+        pxCurTaskList = pxGetNextTaskList(NULL);
+        pxCurListItem = listGET_END_MARKER(pxCurTaskList);
+    } else {
+        // Continuing traversal
+        pxCurTaskList = listLIST_ITEM_CONTAINER(&pxTCB->xStateListItem);
+        pxCurListItem = &pxTCB->xStateListItem;
+    }
+
+    ListItem_t *pxNextListItem = NULL;
+    if (pxCurListItem->pxNext == listGET_END_MARKER(pxCurTaskList)) {
+        List_t *pxNextTaskList = pxGetNextTaskList(pxCurTaskList);
+        while (pxNextTaskList != NULL) {
+            if (!listLIST_IS_EMPTY(pxNextTaskList)) {
+                // Get the first item in the next task list
+                pxNextListItem = listGET_HEAD_ENTRY(pxNextTaskList);
+                break;
+            }
+            // Task list is empty. Get the next task list
+            pxNextTaskList = pxGetNextTaskList(pxNextTaskList);
+        }
+    } else {
+        //There are still more items in the current task list. Get the next item
+        pxNextListItem = listGET_NEXT(pxCurListItem);
+    }
+
+    TCB_t *pxNextTCB;
+    if (pxNextListItem == NULL) {
+        pxNextTCB = NULL;
+    } else {
+        pxNextTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxNextListItem);
+    }
+
+    return pxNextTCB;
+}
+
+void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
+{
+    configASSERT( portVALID_TCB_MEM(pxTask) );
+    configASSERT( pxTaskSnapshot != NULL );
+    TCB_t *pxTCB = (TCB_t *)pxTask;
+    pxTaskSnapshot->pxTCB = pxTCB;
+    pxTaskSnapshot->pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
+    pxTaskSnapshot->pxEndOfStack = (StackType_t *)pxTCB->pxEndOfStack;
+}
+
+UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArrayLength, UBaseType_t * const pxTCBSize )
+{
+    UBaseType_t uxArrayNumFilled = 0;
+
+    //Traverse all of the tasks lists
+    List_t *pxCurTaskList = pxGetNextTaskList(NULL);    //Get the first task list
+    while (pxCurTaskList != NULL && uxArrayNumFilled < uxArrayLength) {
+        if (!listLIST_IS_EMPTY(pxCurTaskList)) {
+            const ListItem_t *pxCurListItem;
+            //Walk each task on the current task list
+            pxCurListItem = listGET_HEAD_ENTRY(pxCurTaskList);
+            while (pxCurListItem != listGET_END_MARKER(pxCurTaskList)) {
+                TCB_t *pxTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxCurListItem);
+                vTaskGetSnapshot((TaskHandle_t)pxTCB, &pxTaskSnapshotArray[uxArrayNumFilled]);
+                uxArrayNumFilled++;
+                if (!(uxArrayNumFilled < uxArrayLength)) {
+                    break;
+                }
+                pxCurListItem = listGET_NEXT(pxCurListItem);
+            }
+        }
+        //Get the next task list
+        pxCurTaskList = pxGetNextTaskList(pxCurTaskList);
+    }
+
+    *pxTCBSize = sizeof(TCB_t);
+    return uxArrayNumFilled;
+}
+#endif // CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
+
+/* ----------------------------------------------------- OpenOCD -------------------------------------------------------
+ *
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+#if ( configENABLE_FREERTOS_DEBUG_OCDAWARE == 1 )
+
+/**
+ * Debug param indexes. DO NOT change the order. OpenOCD uses the same indexes
+ * Entries in FreeRTOS_openocd_params must match the order of these indexes
+ */
+enum {
+    ESP_FREERTOS_DEBUG_TABLE_SIZE = 0,
+    ESP_FREERTOS_DEBUG_TABLE_VERSION,
+    ESP_FREERTOS_DEBUG_KERNEL_VER_MAJOR,
+    ESP_FREERTOS_DEBUG_KERNEL_VER_MINOR,
+    ESP_FREERTOS_DEBUG_KERNEL_VER_BUILD,
+    ESP_FREERTOS_DEBUG_UX_TOP_USED_PIORITY,
+    ESP_FREERTOS_DEBUG_PX_TOP_OF_STACK,
+    ESP_FREERTOS_DEBUG_PC_TASK_NAME,
+    /* New entries must be inserted here */
+    ESP_FREERTOS_DEBUG_TABLE_END,
+};
+
+const DRAM_ATTR uint8_t FreeRTOS_openocd_params[ESP_FREERTOS_DEBUG_TABLE_END]  = {
+    ESP_FREERTOS_DEBUG_TABLE_END,       /* table size */
+    1,                                  /* table version */
+    tskKERNEL_VERSION_MAJOR,
+    tskKERNEL_VERSION_MINOR,
+    tskKERNEL_VERSION_BUILD,
+    configMAX_PRIORITIES - 1,           /* uxTopUsedPriority */
+    offsetof(TCB_t, pxTopOfStack),      /* thread_stack_offset; */
+    offsetof(TCB_t, pcTaskName),        /* thread_name_offset; */
+};
+
+#endif // configENABLE_FREERTOS_DEBUG_OCDAWARE == 1

+ 0 - 212
components/freertos/esp_additions/task_snapshot.c

@@ -1,212 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#include "freertos/FreeRTOS.h"
-#include "freertos/task_snapshot.h"
-
-#ifndef DIM
-#define DIM(t) (sizeof(t)/ sizeof(*(t)))
-#endif
-
-#if ( configENABLE_TASK_SNAPSHOT == 1 )
-
-	static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, void *pxTCB )
-	{
-		if (pxTCB == NULL) {
-			return;
-		}
-		pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
-		pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *) pxTCBGetTopOfStack(pxTCB);
-		#if( portSTACK_GROWTH < 0 )
-		{
-			pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetEndOfStack(pxTCB);
-		}
-		#else
-		{
-			pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetStartOfStack(pxTCB);
-		}
-		#endif
-		(*uxTask)++;
-	}
-
-	static void prvTaskGetSnapshotsFromList( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, const UBaseType_t uxArraySize, List_t *pxList )
-	{
-		void *pxNextTCB = NULL;
-		void *pxFirstTCB = NULL;
-
-		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
-		{
-			listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
-			do
-			{
-				if( *uxTask >= uxArraySize ) {
-					break;
-				}
-
-				listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
-				prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
-			} while( pxNextTCB != pxFirstTCB );
-		}
-		else
-		{
-			mtCOVERAGE_TEST_MARKER();
-		}
-	}
-
-	UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz )
-	{
-		UBaseType_t uxTask = 0;
-		UBaseType_t i = 0;
-
-
-		*pxTcbSz = pxTCBGetSize();
-		/* Fill in an TaskStatus_t structure with information on each
-		task in the Ready state. */
-		i = configMAX_PRIORITIES;
-		do
-		{
-			i--;
-			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyTask(i) );
-		} while( i > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
-
-		/* Fill in an TaskStatus_t structure with information on each
-		task in the Blocked state. */
-		prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetDelayedTaskList() );
-		prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetOverflowDelayedTaskList() );
-		for (i = 0; i < configNUM_CORES; i++) {
-			if( uxTask >= uxArraySize ) {
-				break;
-			}
-			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyPendingTask(i) );
-		}
-
-		#if( INCLUDE_vTaskDelete == 1 )
-		{
-			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetTasksWaitingTermination() );
-		}
-		#endif
-
-		#if ( INCLUDE_vTaskSuspend == 1 )
-		{
-			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetSuspendedTaskList() );
-		}
-		#endif
-		return uxTask;
-	}
-
-	static void *prvFirstTaskGet( List_t *pxList )
-	{
-		ListItem_t *pxListItem = listGET_HEAD_ENTRY( pxList );
-		if( pxListItem != listGET_END_MARKER( pxList ) ) {
-			return listGET_LIST_ITEM_OWNER( pxListItem );
-		}
-		return NULL;
-	}
-
-	static void *prvNextTaskGet( void *pxTCB )
-	{
-		List_t *pxList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTCB) );
-		ListItem_t *pxListItem = listGET_NEXT( pxTCBGetStateListItem(pxTCB) );
-		if( pxListItem != listGET_END_MARKER( pxList ) ) {
-			return listGET_LIST_ITEM_OWNER( pxListItem );
-		}
-		return NULL;
-	}
-
-	void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
-	{
-		configASSERT( portVALID_TCB_MEM(pxTask) );
-		configASSERT( pxTaskSnapshot != NULL );
-		pxTaskSnapshot->pxTCB = (void*) pxTask;
-		pxTaskSnapshot->pxTopOfStack = pxTCBGetTopOfStack((void*) pxTask);
-		pxTaskSnapshot->pxEndOfStack = pxTCBGetEndOfStack((void*) pxTask);
-	}
-
-	TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
-	{
-		void *pxTCB = pxTask;
-		List_t *pxTaskList = NULL;
-		UBaseType_t i = configMAX_PRIORITIES;
-		UBaseType_t bCurTaskListFound = pdFALSE;
-		List_t *task_lists[] = {
-			pxGetDelayedTaskList(),
-			pxGetOverflowDelayedTaskList(),
-		#if( INCLUDE_vTaskDelete == 1 )
-			pxGetTasksWaitingTermination(),
-		#endif
-		#if( INCLUDE_vTaskSuspend == 1 )
-			pxGetSuspendedTaskList()
-		#endif
-		};
-
-		if( pxTask != NULL && !portVALID_TCB_MEM(pxTask) ) {
-			return NULL;
-		}
-
-		if( pxTCB != NULL ) {
-			pxTCB = prvNextTaskGet( pxTCB );
-			if( pxTCB != NULL ) {
-				// take care not to return garbage
-				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
-			}
-			pxTaskList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTask) );
-		}
-		/* ready tasks lists */
-		do
-		{
-			i--;
-			List_t *pxList = pxListGetReadyTask(i);
-			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
-				/* need to find list the current task item from */
-				if( pxTaskList == pxList ) {
-					bCurTaskListFound = pdTRUE;
-				}
-				continue; /* go to the next 'ready list' */
-			}
-			pxTCB = prvFirstTaskGet( pxList );
-			if( pxTCB != NULL ) {
-				// take care not to return garbage
-				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
-		}
-		}
-		while( i > tskIDLE_PRIORITY );
-		/* pending ready tasks lists */
-		for (i = 0; i < configNUM_CORES; i++) {
-			List_t *pxList = pxListGetReadyPendingTask(i);
-			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
-				/* need to find list the current task item from */
-				if( pxTaskList == pxList ) {
-					bCurTaskListFound = pdTRUE;
-				}
-				continue; /* go to the next 'ready list' */
-			}
-			pxTCB = prvFirstTaskGet( pxList );
-			if( pxTCB != NULL ) {
-				// take care not to return garbage
-				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
-			}
-		}
-		/* other tasks lists */
-		for (i = 0; i < DIM(task_lists); i++) {
-			List_t *pxList = task_lists[ i ];
-			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
-				/* need to find list the current task item from */
-				if( pxTaskList == pxList ) {
-					bCurTaskListFound = pdTRUE;
-				}
-				continue; /* go to the next 'ready list' */
-			}
-			pxTCB = prvFirstTaskGet( pxList );
-			if( pxTCB != NULL ) {
-				// take care not to return garbage
-				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
-			}
-		}
-
-		return NULL;
-	}
-
-#endif

+ 0 - 2
components/freertos/test/CMakeLists.txt

@@ -1,5 +1,3 @@
 idf_component_register(SRC_DIRS .
                        PRIV_INCLUDE_DIRS .
                        PRIV_REQUIRES cmock test_utils esp_system driver)
-# Enable task snapshots by setting configENABLE_TASK_SNAPSHOT macro
-idf_build_set_property(COMPILE_OPTIONS "-DconfigENABLE_TASK_SNAPSHOT=1" APPEND)

+ 136 - 23
components/freertos/test/test_tasks_snapshot.c

@@ -1,38 +1,151 @@
 /*
- Test FreeRTOS support for core dump.
-*/
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
+#include "sdkconfig.h"
+
+#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
 #include <stdio.h>
-#include "esp_cpu.h"
 #include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
 #include "freertos/task_snapshot.h"
+#include "esp_cpu.h"
 #include "unity.h"
 #include "sdkconfig.h"
 
-#define TEST_MAX_TASKS_NUM	32
+#define TEST_MAX_TASKS_NUM      32
+#define NUM_TASKS_PER_LIST      2
+#define TASK_PRIORITY           (configMAX_PRIORITIES - 2)
 
-/* simple test to check that in normal conditions uxTaskGetSnapshotAll does not generate exception */
-TEST_CASE("Tasks snapshot", "[freertos]")
+static void ready_task(void *arg)
 {
-    TaskSnapshot_t tasks[TEST_MAX_TASKS_NUM];
-    UBaseType_t tcb_sz;
-#ifndef CONFIG_FREERTOS_UNICORE
-    int other_core_id = xPortGetCoreID() == 0 ? 1 : 0;
-#endif
+    while (1) {
+        ;
+    }
+}
+
+static void blocked_task(void *arg)
+{
+    // Delay for portMAX_DELAY - 1 as not to go on the suspended list
+    vTaskDelay(portMAX_DELAY - 1);
+}
 
-    // uxTaskGetSnapshotAll is supposed to be called when all tasks on both CPUs are
-    // inactive and can not alter FreeRTOS internal tasks lists, e.g. from panic handler
-    unsigned state = portSET_INTERRUPT_MASK_FROM_ISR();
-#ifndef CONFIG_FREERTOS_UNICORE
-    esp_cpu_stall(other_core_id);
+static void suspended_task(void *arg)
+{
+    vTaskSuspend(NULL);
+}
+
+static void setup(TaskHandle_t *task_list, int *num_tasks_ret, UBaseType_t *old_priority_ret)
+{
+    // Raise our priority so that we aren't preempted
+    *old_priority_ret = uxTaskPriorityGet(NULL);
+    vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1);
+
+    // Create tasks
+    int num_tasks = 0;
+    for (int i = 0; i < NUM_TASKS_PER_LIST; i++) {
+        //Ready task
+        xTaskCreate(ready_task, "ready", 1024, NULL, TASK_PRIORITY, &(task_list[num_tasks]));
+        num_tasks++;
+        //Blocked task
+        xTaskCreate(blocked_task, "blkd", 1024, NULL, TASK_PRIORITY, &(task_list[num_tasks]));
+        num_tasks++;
+        //Suspended task
+        xTaskCreate(suspended_task, "susp", 1024, NULL, TASK_PRIORITY, &(task_list[num_tasks]));
+        num_tasks++;
+    }
+    *num_tasks_ret = num_tasks;
+    // Short delay to allow tasks to spin up
+    vTaskDelay(10);
+
+    // Stop preemption on this core, and stall the other core
+    taskDISABLE_INTERRUPTS();
+#if !CONFIG_FREERTOS_UNICORE
+    esp_cpu_stall(!xPortGetCoreID());
 #endif
-    UBaseType_t task_num = uxTaskGetSnapshotAll(tasks, TEST_MAX_TASKS_NUM, &tcb_sz);
-#ifndef CONFIG_FREERTOS_UNICORE
-    esp_cpu_unstall(other_core_id);
+
+
+}
+
+static void check_snapshots(TaskHandle_t *task_list, int num_tasks, TaskSnapshot_t *task_snapshots, UBaseType_t num_snapshots)
+{
+    // Check task snapshots. Every created task should be found in the task snapshot
+    for (int i = 0; i < num_tasks; i++) {
+        bool found = false;
+        for (int j = 0; j < num_snapshots; j++) {
+            if (task_list[i] == (TaskHandle_t)task_snapshots[j].pxTCB) {
+                found = true;
+                break;
+            }
+        }
+        TEST_ASSERT(found);
+    }
+}
+
+static void teardown(TaskHandle_t *task_list, int num_tasks, UBaseType_t old_priority)
+{
+    // Resume other cores and allow preemption
+#if !CONFIG_FREERTOS_UNICORE
+    esp_cpu_unstall(!xPortGetCoreID());
 #endif
-    portCLEAR_INTERRUPT_MASK_FROM_ISR(state);
+    taskENABLE_INTERRUPTS();
+
+    for (int i = 0; i < num_tasks; i++) {
+        vTaskDelete(task_list[i]);
+    }
+    // Restore priority
+    vTaskPrioritySet(NULL, old_priority);
+    // Short delay to allow tasks to clean up
+    vTaskDelay(10);
+}
+
+TEST_CASE("Task snapshot: Get all", "[freertos]")
+{
+    // Short delay to allow both cores to spin up
+    vTaskDelay(10);
 
-    printf("Dumped %d tasks. TCB size %d\n", task_num, tcb_sz);
-    TEST_ASSERT_NOT_EQUAL(0, task_num);
-    TEST_ASSERT_NOT_EQUAL(0, tcb_sz);
+    TaskHandle_t task_list[TEST_MAX_TASKS_NUM];
+    int num_tasks;
+    UBaseType_t old_priority;
+    setup(task_list, &num_tasks, &old_priority);
+
+    // Get task snapshots using uxTaskGetSnapshotAll()
+    TaskSnapshot_t task_snapshots[TEST_MAX_TASKS_NUM];
+    UBaseType_t tcb_size;
+    UBaseType_t num_snapshots;
+    num_snapshots = uxTaskGetSnapshotAll(task_snapshots, TEST_MAX_TASKS_NUM, &tcb_size);
+    TEST_ASSERT_LESS_OR_EQUAL(TEST_MAX_TASKS_NUM, num_snapshots);
+
+    check_snapshots(task_list, num_tasks, task_snapshots, num_snapshots);
+    teardown(task_list, num_tasks, old_priority);
 }
+
+TEST_CASE("Task snapshot: Iterate", "[freertos]")
+{
+    // Short delay to allow both cores to spin up
+    vTaskDelay(10);
+
+    TaskHandle_t task_list[TEST_MAX_TASKS_NUM];
+    int num_tasks;
+    UBaseType_t old_priority;
+    setup(task_list, &num_tasks, &old_priority);
+
+    // Get task snapshots using pxTaskGetNext() and vTaskGetSnapshot()
+    TaskSnapshot_t task_snapshots[TEST_MAX_TASKS_NUM];
+    UBaseType_t num_snapshots = 0;
+    TaskHandle_t cur_task_handle = pxTaskGetNext(NULL);
+    while (cur_task_handle != NULL) {
+        // Get the task's snapshot
+        vTaskGetSnapshot(cur_task_handle, &task_snapshots[num_snapshots]);
+        num_snapshots++;
+        cur_task_handle = pxTaskGetNext(cur_task_handle);
+    }
+    TEST_ASSERT_LESS_OR_EQUAL(TEST_MAX_TASKS_NUM, num_snapshots);
+
+    check_snapshots(task_list, num_tasks, task_snapshots, num_snapshots);
+    teardown(task_list, num_tasks, old_priority);
+}
+
+#endif // CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT

+ 1 - 0
tools/unit-test-app/configs/freertos_options

@@ -20,3 +20,4 @@ CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
 CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
 CONFIG_FREERTOS_FPU_IN_ISR=y
 CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=16
+CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y