/* ---------------------------------------------------------------------------- * 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 */