From 80f0c64c2a32708ed01b24113f6aef99138b3a83 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 24 Mar 2022 13:45:19 +0800 Subject: [PATCH 1/2] freertos: Update task snapshot This commit updates task snapshot as follows: - Refactored implementation to increase readability - Implementation moved into freertos_tasks_c_additions.h - freertos_tasks_c_additions.h made a private header - Support SMP FreeRTOS - Removed configENABLE_TASK_SNAPSHOT option. CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is direclty used instead. --- components/freertos/CMakeLists.txt | 5 +- .../include/freertos/FreeRTOSConfig_smp.h | 6 - components/freertos/Kconfig | 2 +- .../include/freertos/FreeRTOSConfig.h | 7 +- .../include/freertos/task_snapshot.h | 101 ++++---- .../include/freertos_tasks_c_additions.h | 108 -------- .../freertos_tasks_c_additions.h | 239 ++++++++++++++++++ .../freertos/esp_additions/task_snapshot.c | 212 ---------------- 8 files changed, 292 insertions(+), 388 deletions(-) delete mode 100644 components/freertos/esp_additions/include/freertos_tasks_c_additions.h create mode 100644 components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h delete mode 100644 components/freertos/esp_additions/task_snapshot.c diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index eea02bacd5..9ea528a7eb 100644 --- a/components/freertos/CMakeLists.txt +++ b/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") 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 6626101312..74fcd8fd82 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 @@ -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 diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 342ae097f3..df71801e73 100644 --- a/components/freertos/Kconfig +++ b/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" diff --git a/components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h b/components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h index 8bdb5f4c18..09f421bceb 100644 --- a/components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h +++ b/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 diff --git a/components/freertos/esp_additions/include/freertos/task_snapshot.h b/components/freertos/esp_additions/include/freertos/task_snapshot.h index b6fc2d089c..bd8fe82a1b 100644 --- a/components/freertos/esp_additions/include/freertos/task_snapshot.h +++ b/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 diff --git a/components/freertos/esp_additions/include/freertos_tasks_c_additions.h b/components/freertos/esp_additions/include/freertos_tasks_c_additions.h deleted file mode 100644 index 1e742fd326..0000000000 --- a/components/freertos/esp_additions/include/freertos_tasks_c_additions.h +++ /dev/null @@ -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 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 new file mode 100644 index 0000000000..8100c632b5 --- /dev/null +++ b/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 diff --git a/components/freertos/esp_additions/task_snapshot.c b/components/freertos/esp_additions/task_snapshot.c deleted file mode 100644 index 1244118b60..0000000000 --- a/components/freertos/esp_additions/task_snapshot.c +++ /dev/null @@ -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 From 8c88c6f68f95b666a011589c60ae8a9075016564 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 24 Mar 2022 13:45:31 +0800 Subject: [PATCH 2/2] freertos: Update task snapshot unit tests This commit updates the task snapshot unit tests as follows: - Both uxTaskGetSnapshotAll() and vTaskGetSnapshot() are now both tested - Test cases are now dependent on CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT --- components/freertos/test/CMakeLists.txt | 2 - .../freertos/test/test_tasks_snapshot.c | 167 +++++++++++++++--- tools/unit-test-app/configs/freertos_options | 1 + 3 files changed, 141 insertions(+), 29 deletions(-) diff --git a/components/freertos/test/CMakeLists.txt b/components/freertos/test/CMakeLists.txt index e25755ba72..00b876bf1c 100644 --- a/components/freertos/test/CMakeLists.txt +++ b/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) diff --git a/components/freertos/test/test_tasks_snapshot.c b/components/freertos/test/test_tasks_snapshot.c index 20ffd8d855..8551005d13 100644 --- a/components/freertos/test/test_tasks_snapshot.c +++ b/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 -#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 - - // 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); -#endif - UBaseType_t task_num = uxTaskGetSnapshotAll(tasks, TEST_MAX_TASKS_NUM, &tcb_sz); -#ifndef CONFIG_FREERTOS_UNICORE - esp_cpu_unstall(other_core_id); -#endif - portCLEAR_INTERRUPT_MASK_FROM_ISR(state); - - 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); + 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); +} + +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 + + +} + +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 + 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); + + 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 diff --git a/tools/unit-test-app/configs/freertos_options b/tools/unit-test-app/configs/freertos_options index d48ae92fb1..3e3196c6c5 100644 --- a/tools/unit-test-app/configs/freertos_options +++ b/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