You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
LiteOS-Reading/src/kernel/base/shellcmd/task_shellcmd.c

404 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* ----------------------------------------------------------------------------
* Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
* Description: ShellCmd Task
* Author: Huawei LiteOS Team
* Create: 2013-01-01
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --------------------------------------------------------------------------- */
/*
这段文件是针对LiteOS操作系统中的Shell命令编写的
主要实现了操作系统的任务管理模块,通过进程号获取该进程的所有信息,或者直接获取所有进程的信息。
*/
#include "stdio.h"
#include "stdlib.h"
#include "los_config.h"
#include "los_exc.h"
#include "los_memstat_pri.h"
#include "los_sem_pri.h"
#include "los_task_pri.h"
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#include "shell.h"
#endif
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#ifdef LOSCFG_SHELL_EXCINFO_DUMP
#include "los_exc_pri.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define OS_INVALID_SEM_ID 0xFFFFFFFF
#ifdef LOSCFG_KERNEL_CPUP
LITE_OS_SEC_BSS STATIC CPUP_INFO_S g_taskCpupAll[LOSCFG_BASE_CORE_TSK_LIMIT];//所有时间段CPU利用率的统计信息
LITE_OS_SEC_BSS STATIC CPUP_INFO_S g_taskCpup10s[LOSCFG_BASE_CORE_TSK_LIMIT];//最近10sCPU利用率的统计信息
LITE_OS_SEC_BSS STATIC CPUP_INFO_S g_taskCpup1s[LOSCFG_BASE_CORE_TSK_LIMIT];//最近1sCPU利用率的统计信息
#endif
LITE_OS_SEC_BSS STATIC UINT32 g_taskWaterLine[LOSCFG_BASE_CORE_TSK_LIMIT];//记录各个堆栈最低的水位
//这个函数通过进程状态位来判断进程的状态,并返回相应的字符串表示进程状态。
LITE_OS_SEC_TEXT_MINOR UINT8 *OsShellCmdConvertTskStatus(UINT16 taskStatus)
{
//进程处于运行状态返回Running
if (taskStatus & OS_TASK_STATUS_RUNNING) {
return (UINT8 *)"Running";
//进程处于就绪状态返回Ready
} else if (taskStatus & OS_TASK_STATUS_READY) {
return (UINT8 *)"Ready";
//其他的进程状态
} else {
//进程处于延迟状态返回Delay
if (taskStatus & OS_TASK_STATUS_DELAY) {
return (UINT8 *)"Delay";
} else if (taskStatus & OS_TASK_STATUS_PEND_TIME) {
//进程处于定时挂起状态返回SuspendTime
if (taskStatus & OS_TASK_STATUS_SUSPEND) {
return (UINT8 *)"SuspendTime";
//进程处于定时等待状态返回PendTime
} else if (taskStatus & OS_TASK_STATUS_PEND) {
return (UINT8 *)"PendTime";
}
//进程处于等待状态返回Pend
} else if (taskStatus & OS_TASK_STATUS_PEND) {
return (UINT8 *)"Pend";
//进程处于挂起状态返回SusPend
} else if (taskStatus & OS_TASK_STATUS_SUSPEND) {
return (UINT8 *)"Suspend";
}
}
//进程状态不合法返回Invalid
return (UINT8 *)"Invalid";
}
//这个函数用于获取所有堆栈的栈水位(堆栈的使用情况)
STATIC VOID OsShellCmdTaskWaterLineGet(const LosTaskCB *allTaskArray)
{
const LosTaskCB *taskCB = NULL;
UINT32 loop;
//遍历所有堆栈
for (loop = 0; loop < g_taskMaxNum; ++loop) {
taskCB = allTaskArray + loop;
//如果该堆栈未使用,直接跳过
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
continue;
}
//调用OsStackWaterLineGet输出堆栈的栈水位信息
(VOID)OsStackWaterLineGet((const UINTPTR *)((UINTPTR)taskCB->topOfStack + taskCB->stackSize),
(const UINTPTR *)taskCB->topOfStack, &g_taskWaterLine[taskCB->taskId]);
}
}
#ifdef LOSCFG_SHELL_EXCINFO_DUMP
//这个函数用于在异常信息输出缓冲区中打印任务信息的标题。
LITE_OS_SEC_TEXT_MINOR STATIC VOID OsShellCmdTskInfoTitleExc(VOID)
{
WriteExcInfoToBuf("\r\nName TaskEntryAddr TID ");
#ifdef LOSCFG_KERNEL_SMP
WriteExcInfoToBuf("Affi CPU ");
#endif
WriteExcInfoToBuf("Priority Status "
"StackSize WaterLine StackPoint TopOfStack SemID EventMask");
#ifdef LOSCFG_KERNEL_CPUP
WriteExcInfoToBuf(" CPUUSE CPUUSE10s CPUUSE1s ");
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
WriteExcInfoToBuf(" MEMUSE");
#endif
WriteExcInfoToBuf("\n");
WriteExcInfoToBuf("---- ------------- --- ");
#ifdef LOSCFG_KERNEL_SMP
WriteExcInfoToBuf("----- ---- ");
#endif
WriteExcInfoToBuf("-------- -------- "
"--------- ---------- ---------- ---------- ---------- ---------");
#ifdef LOSCFG_KERNEL_CPUP
WriteExcInfoToBuf(" ------ --------- -------- ");
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
WriteExcInfoToBuf(" ------");
#endif
WriteExcInfoToBuf("\n");
}
#endif
//这个函数用于在控制台打印任务信息的标题。
LITE_OS_SEC_TEXT_MINOR STATIC VOID OsShellCmdTskInfoTitle(VOID)
{
PRINTK("\r\nName TaskEntryAddr TID ");
#ifdef LOSCFG_KERNEL_SMP
PRINTK("Affi CPU ");
#endif
PRINTK("Priority Status "
"StackSize WaterLine StackPoint TopOfStack SemID EventMask");
#ifdef LOSCFG_KERNEL_CPUP
PRINTK(" CPUUSE CPUUSE10s CPUUSE1s ");
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
PRINTK(" MEMUSE");
#endif
PRINTK("\n");
PRINTK("---- ------------- --- ");
#ifdef LOSCFG_KERNEL_SMP
PRINTK("----- ---- ");
#endif
PRINTK("-------- -------- "
"--------- ---------- ---------- ---------- ---------- ---------");
#ifdef LOSCFG_KERNEL_CPUP
PRINTK(" ------ --------- -------- ");
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
PRINTK(" ------");
#endif
PRINTK("\n");
#ifdef LOSCFG_SHELL_EXCINFO_DUMP
//在异常信息输出缓冲区中打印任务信息的标题。
OsShellCmdTskInfoTitleExc();
#endif
}
//这个函数通过TCB进程控制块获取进程所持有的信号量的ID。
LITE_OS_SEC_TEXT_MINOR STATIC INLINE UINT32 OsGetSemID(const LosTaskCB *taskCB)
{
UINT32 semId = OS_INVALID_SEM_ID;
//返回该进程的信号量ID
if (taskCB->taskSem != NULL) {
semId = ((LosSemCB *)taskCB->taskSem)->semId;
}
return semId;
}
#ifdef LOSCFG_SHELL_EXCINFO_DUMP
//这个函数用于将TCB进程控制块中的进程信息输出到异常信息输出缓冲区。
LITE_OS_SEC_TEXT_MINOR STATIC VOID OsShellCmdTskInfoDataExc(const LosTaskCB *allTaskArray)
{
const LosTaskCB *taskCB = NULL;
UINT32 loop;
UINT32 semId;
//遍历所有的堆栈
for (loop = 0; loop < g_taskMaxNum; ++loop) {
taskCB = allTaskArray + loop;
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
continue;
}
semId = OsGetSemID(taskCB);
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf("%-23s0x%-18.8x0x%-5x", taskCB->taskName, taskCB->taskEntry, taskCB->taskId);
#ifdef LOSCFG_KERNEL_SMP
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf("0x%04x %4d ", taskCB->cpuAffiMask, (INT16)(taskCB->currCpu));
#endif
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf("%-11u%-13s0x%-11x0x%-11x 0x%-.8x 0x%-.8x 0x%-11x", taskCB->priority,
OsShellCmdConvertTskStatus(taskCB->taskStatus), taskCB->stackSize,
g_taskWaterLine[taskCB->taskId],
taskCB->stackPointer, taskCB->topOfStack, semId);
#ifdef LOSCFG_BASE_IPC_EVENT
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf("0x%-6x", taskCB->eventMask);
#endif
#ifdef LOSCFG_KERNEL_CPUP
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf(" %4u.%1u%9u.%1u%8u.%1u ",
g_taskCpupAll[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpupAll[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT,
g_taskCpup10s[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpup10s[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT,
g_taskCpup1s[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpup1s[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT);
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf(" %-11u", OsMemTaskUsage(taskCB->taskId));
#endif
//调用WriteExcInfoToBuf函数将TCB进程控制块的信息写入缓冲区
WriteExcInfoToBuf("\n");
}
}
#endif
//这个函数可以将TCB(进程控制块)中的信息输出到控制台。
LITE_OS_SEC_TEXT_MINOR STATIC VOID OsShellCmdTskInfoData(const LosTaskCB *allTaskArray)
{
const LosTaskCB *taskCB = NULL;
UINT32 loop;
UINT32 semId;
//遍历所有的堆栈
for (loop = 0; loop < g_taskMaxNum; ++loop) {
taskCB = allTaskArray + loop;
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
continue;
}
//调用OsGetSemID获取该进程的信号量ID
semId = OsGetSemID(taskCB);
//输出进程信息到控制台
PRINTK("%-23s0x%-18.8x0x%-5x", taskCB->taskName, taskCB->taskEntry, taskCB->taskId);
#ifdef LOSCFG_KERNEL_SMP
//输出进程信息到控制台
PRINTK("0x%04x %4d ", taskCB->cpuAffiMask, (INT16)(taskCB->currCpu));
#endif
//输出进程信息到控制台
PRINTK("%-11u%-13s0x%-11x0x%-11x 0x%-.8x 0x%-.8x 0x%-11x", taskCB->priority,
OsShellCmdConvertTskStatus(taskCB->taskStatus), taskCB->stackSize,
g_taskWaterLine[taskCB->taskId],
taskCB->stackPointer, taskCB->topOfStack, semId);
#ifdef LOSCFG_BASE_IPC_EVENT
//输出进程信息到控制台
PRINTK("0x%-6x", taskCB->eventMask);
#endif
#ifdef LOSCFG_KERNEL_CPUP
//输出进程信息到控制台
PRINTK(" %4u.%1u%9u.%1u%8u.%1u ",
g_taskCpupAll[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpupAll[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT,
g_taskCpup10s[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpup10s[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT,
g_taskCpup1s[taskCB->taskId].uwUsage / LOS_CPUP_PRECISION_MULT,
g_taskCpup1s[taskCB->taskId].uwUsage % LOS_CPUP_PRECISION_MULT);
#endif /* LOSCFG_KERNEL_CPUP */
#ifdef LOSCFG_MEM_TASK_STAT
//输出进程信息到控制台
PRINTK(" %-11u", OsMemTaskUsage(taskCB->taskId));
#endif
//输出进程信息到控制台
PRINTK("\n");
}
#ifdef LOSCFG_SHELL_EXCINFO_DUMP
//将进程信息输出到异常信息输出缓冲区。
OsShellCmdTskInfoDataExc(allTaskArray);
#endif
}
//这个函数可以通过进程号获取进程的信息
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTskInfoGet(UINT32 taskId)
{
BOOL backupFlag = TRUE;
BOOL lockFlag = FALSE;
UINT32 size, intSave;
LosTaskCB *tcbArray = NULL;
INT32 ret;
//如果是目标进程
if (taskId == OS_ALL_TASK_MASK) {
size = g_taskMaxNum * sizeof(LosTaskCB);
tcbArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem1, size);
//如果目标进程信息为空输出错误信息将backup设置为Fasle不备份该进程信息
if (tcbArray == NULL) {
PRINTK("Memory is not enough to save task info!\n");
tcbArray = g_taskCBArray;
backupFlag = FALSE;
}
#ifdef LOSCFG_KERNEL_CPUP
(VOID)memset_s((VOID *)g_taskCpupAll, sizeof(g_taskCpupAll), 0, sizeof(g_taskCpupAll));//置零
(VOID)memset_s((VOID *)g_taskCpup10s, sizeof(g_taskCpup10s), 0, sizeof(g_taskCpup10s));//置零
(VOID)memset_s((VOID *)g_taskCpup1s, sizeof(g_taskCpup1s), 0, sizeof(g_taskCpup1s));//置零
#endif
(VOID)memset_s((VOID *)g_taskWaterLine, sizeof(g_taskWaterLine), 0, sizeof(g_taskWaterLine));//置零
//如果没有调度器自旋锁,为该进程添加调度器自旋锁
if (LOS_SpinHeld(&g_taskSpin) == FALSE) {
SCHEDULER_LOCK(intSave);
lockFlag = TRUE;
}
//如果需要将进程信息备份
if (backupFlag == TRUE) {
//将进程信息备份到tcbArray
ret = memcpy_s(tcbArray, size, g_taskCBArray, size);
//如果没有备份成果返回错误
if (ret != EOK) {
return LOS_NOK;
}
}
#ifdef LOSCFG_KERNEL_CPUP
(VOID)LOS_AllCpuUsage(LOSCFG_BASE_CORE_TSK_LIMIT, g_taskCpupAll, CPUP_ALL_TIME, 1);//显示CPU所有时段的使用率信息
(VOID)LOS_AllCpuUsage(LOSCFG_BASE_CORE_TSK_LIMIT, g_taskCpup10s, CPUP_LAST_TEN_SECONDS, 1);//显示CPU最近10s的使用率信息
(VOID)LOS_AllCpuUsage(LOSCFG_BASE_CORE_TSK_LIMIT, g_taskCpup1s, CPUP_LAST_ONE_SECONDS, 1);//显示CPU最近1s的使用率信息
#endif
//获取进程的栈水位信息
OsShellCmdTaskWaterLineGet(tcbArray);
//如果进程有调度器自旋锁,将该进程解锁
if (lockFlag == TRUE) {
SCHEDULER_UNLOCK(intSave);
}
//打印进程信息标题
OsShellCmdTskInfoTitle();
//打印进程信息的数据
OsShellCmdTskInfoData(tcbArray);
//如果进程信息数据备份成果释放tcbArrayd的内存空间
if (backupFlag == TRUE) {
(VOID)LOS_MemFree(m_aucSysMem1, tcbArray);
}
} else {
//调用 OsTaskBackTrace函数来获取该任务的回溯信息。
OsTaskBackTrace(taskId);
}
return LOS_OK;
}
#ifdef LOSCFG_SHELL
//这个函数用于处理task命令通过各种参数输出结果
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpTask(INT32 argc, const CHAR **argv)
{
size_t taskId;
CHAR *endPtr = NULL;
//当参数数量合法时
if (argc < 2) { /* 2:Just as number of parameters */
//如果没有参数,进程号是所有进程
if (argc == 0) {
taskId = OS_ALL_TASK_MASK;
//存在一个参数为进程号
} else {
taskId = strtoul(argv[0], &endPtr, 0);
//如果进程号不合法,打印错误信息
if ((*endPtr != 0) || (taskId >= g_taskMaxNum)) {
PRINTK("\ntask ID can't access %s.\n", argv[0]);
return OS_ERROR;
}
}
//调用OsShellCmdTskInfoGet函数输出该进程的进程信息
return OsShellCmdTskInfoGet((UINT32)taskId);
} else {
//参数不合法,打印错误信息
PRINTK("\nUsage: task or task ID\n");
return OS_ERROR;
}
}
//注册Shell命令task调用OsShellCmdDumpTask根据参数进程号或者没有参数获取进程信息并输出。
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask);
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */