freertos: Update task snapshot

This commit updates task snapshot as follows:

- Refactored implementation to increase readability
- Implementation moved into freertos_tasks_c_additions.h
- freertos_tasks_c_additions.h made a private header
- Support SMP FreeRTOS
- Removed configENABLE_TASK_SNAPSHOT option. CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
  is direclty used instead.
This commit is contained in:
Darian Leung
2022-03-24 13:45:19 +08:00
parent e13bb580c7
commit 80f0c64c2a
8 changed files with 292 additions and 388 deletions

View File

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

View File

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

View File

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

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

View File

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

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