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:
Darian 2022-04-04 07:49:20 +08:00
commit 82e9afeade
11 changed files with 433 additions and 417 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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