mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 21:24:32 +02: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:
@@ -31,7 +31,6 @@ if(CONFIG_FREERTOS_SMP)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND srcs
|
list(APPEND srcs
|
||||||
"esp_additions/task_snapshot.c"
|
|
||||||
"FreeRTOS-Kernel-SMP/croutine.c"
|
"FreeRTOS-Kernel-SMP/croutine.c"
|
||||||
"FreeRTOS-Kernel-SMP/event_groups.c"
|
"FreeRTOS-Kernel-SMP/event_groups.c"
|
||||||
"FreeRTOS-Kernel-SMP/list.c"
|
"FreeRTOS-Kernel-SMP/list.c"
|
||||||
@@ -92,7 +91,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND srcs
|
list(APPEND srcs
|
||||||
"esp_additions/task_snapshot.c"
|
|
||||||
"FreeRTOS-Kernel/portable/port_common.c"
|
"FreeRTOS-Kernel/portable/port_common.c"
|
||||||
"FreeRTOS-Kernel/portable/port_systick.c"
|
"FreeRTOS-Kernel/portable/port_systick.c"
|
||||||
"FreeRTOS-Kernel/croutine.c"
|
"FreeRTOS-Kernel/croutine.c"
|
||||||
@@ -106,7 +104,8 @@ else()
|
|||||||
"esp_additions/freertos_v8_compat.c")
|
"esp_additions/freertos_v8_compat.c")
|
||||||
|
|
||||||
list(APPEND private_include_dirs
|
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)
|
if(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
|
||||||
list(APPEND srcs "FreeRTOS-Kernel/portable/xtensa/xtensa_loadstore_handler.S")
|
list(APPEND srcs "FreeRTOS-Kernel/portable/xtensa/xtensa_loadstore_handler.S")
|
||||||
|
@@ -285,12 +285,6 @@ extern uint32_t port_switch_flag[];
|
|||||||
|
|
||||||
// ---------------------- Features -------------------------
|
// ---------------------- 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 */
|
/* These currently aren't required, but could be useful additions in the future */
|
||||||
#if 0
|
#if 0
|
||||||
#ifndef configIDLE_TASK_STACK_SIZE
|
#ifndef configIDLE_TASK_STACK_SIZE
|
||||||
|
@@ -462,7 +462,7 @@ menu "FreeRTOS"
|
|||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
When enabled, the functions related to snapshots, such as vTaskGetSnapshot or uxTaskGetSnapshotAll,
|
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
|
config FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH
|
||||||
bool "Place task snapshot functions 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
|
#ifndef configIDLE_TASK_STACK_SIZE
|
||||||
#define configIDLE_TASK_STACK_SIZE CONFIG_FREERTOS_IDLE_TASK_STACKSIZE
|
#define configIDLE_TASK_STACK_SIZE CONFIG_FREERTOS_IDLE_TASK_STACKSIZE
|
||||||
#endif
|
#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
|
#if CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER
|
||||||
#define configCHECK_MUTEX_GIVEN_BY_OWNER 1
|
#define configCHECK_MUTEX_GIVEN_BY_OWNER 1
|
||||||
#else
|
#else
|
||||||
|
@@ -6,77 +6,74 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
|
||||||
#if ( configENABLE_TASK_SNAPSHOT == 1 )
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT || defined __DOXYGEN__
|
||||||
/**
|
/**
|
||||||
* Check `freertos_tasks_c_additions.h` file for more info
|
* @brief Task Snapshot structure
|
||||||
* about these functions declaration.
|
*
|
||||||
*/
|
* - Used with the uxTaskGetSnapshotAll() function to save memory snapshot of each task in the system.
|
||||||
UBaseType_t pxTCBGetSize ( void );
|
* - We need this structure because TCB_t is defined (hidden) in tasks.c.
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
typedef struct xTASK_SNAPSHOT
|
typedef struct xTASK_SNAPSHOT
|
||||||
{
|
{
|
||||||
void *pxTCB; /*!< Address of task control block. */
|
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 *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
|
StackType_t *pxEndOfStack; /*!< Points to the end of the stack. pxTopOfStack < pxEndOfStack, stack grows hi2lo
|
||||||
pxTopOfStack > pxEndOfStack, stack grows lo2hi*/
|
pxTopOfStack > pxEndOfStack, stack grows lo2hi*/
|
||||||
} TaskSnapshot_t;
|
} TaskSnapshot_t;
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* @brief Iterate over all tasks in the system
|
||||||
* 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.
|
* - This function can be used to iterate over every task in the system
|
||||||
* Only available when configENABLE_TASK_SNAPSHOT is set to 1.
|
* - The first call to this function must set pxTask to NULL
|
||||||
* @param pxTaskSnapshotArray Pointer to array of TaskSnapshot_t structures to store tasks snapshot data.
|
* - When all functions have been iterated, this function will return NULL.
|
||||||
* @param uxArraySize Size of tasks snapshots array.
|
* - This function is only available when CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is set to 1.
|
||||||
* @param pxTcbSz Pointer to store size of TCB.
|
*
|
||||||
* @return Number of elements stored in array.
|
* @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.
|
||||||
UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz );
|
* @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)
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask );
|
TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask );
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* This function fills TaskSnapshot_t structure for specified task.
|
* @brief Fill a 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.
|
* - This function is used by the panic handler to get the snapshot of a particular task.
|
||||||
* @note This function should not be used while FreeRTOS is running (as it doesn't acquire any locks).
|
* - This function is only available when CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT is set to 1.
|
||||||
* @param pxTask task handle.
|
*
|
||||||
* @param pxTaskSnapshot address of TaskSnapshot_t structure to fill.
|
* @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 );
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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 .
|
idf_component_register(SRC_DIRS .
|
||||||
PRIV_INCLUDE_DIRS .
|
PRIV_INCLUDE_DIRS .
|
||||||
PRIV_REQUIRES cmock test_utils esp_system driver)
|
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 <stdio.h>
|
||||||
#include "esp_cpu.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
#include "freertos/task_snapshot.h"
|
#include "freertos/task_snapshot.h"
|
||||||
|
#include "esp_cpu.h"
|
||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include "sdkconfig.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 */
|
static void ready_task(void *arg)
|
||||||
TEST_CASE("Tasks snapshot", "[freertos]")
|
|
||||||
{
|
{
|
||||||
TaskSnapshot_t tasks[TEST_MAX_TASKS_NUM];
|
while (1) {
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||||
CONFIG_FREERTOS_FPU_IN_ISR=y
|
CONFIG_FREERTOS_FPU_IN_ISR=y
|
||||||
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=16
|
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=16
|
||||||
|
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
|
||||||
|
Reference in New Issue
Block a user