mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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
This commit is contained in:
commit
82e9afeade
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user