parent
2bdb3fa4bd
commit
0771df2fb3
@ -0,0 +1,257 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
|
||||||
|
* Description: Mutex Deadlock Check
|
||||||
|
* 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.
|
||||||
|
* --------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "los_mux_debug_pri.h"
|
||||||
|
#include "los_typedef.h"
|
||||||
|
#include "los_task.h"
|
||||||
|
#include "arch/exception.h"
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
#include "shcmd.h"
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */nbb
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LOS_DL_LIST muxListHead; /* Task-held mutexs list */ //用于管理任务持有的互斥锁列表//
|
||||||
|
UINT64 lastAccessTime; /* The last operation time */ //记录最后一次操作的时间//
|
||||||
|
} MuxDLinkCB;
|
||||||
|
|
||||||
|
/*管理任务持有的互斥锁列表和跟踪死锁情况*/
|
||||||
|
typedef struct {
|
||||||
|
LOS_DL_LIST muxList; /* Insert mutex into the owner task CB */ //用于将互斥锁插入到所属任务的控制块中//
|
||||||
|
VOID *muxCB; /* The Mutex CB pointer */ //指向互斥锁控制块的指针//
|
||||||
|
} MuxDLinkNode;
|
||||||
|
|
||||||
|
STATIC MuxDLinkCB *g_muxDeadlockCBArray = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex deadlock detection time threshold, will print out task information
|
||||||
|
* that has not been scheduled within this time.
|
||||||
|
* The unit is tick.
|
||||||
|
*/
|
||||||
|
#define OS_MUX_DEADLOCK_CHECK_THRESHOLD 60000 //定义两次检查互斥锁死锁之间的最小时间间隔,单位为毫秒//
|
||||||
|
|
||||||
|
UINT32 OsMuxDlockCheckInit(VOID) //用于分配内存并初始化互斥锁控制块列表//
|
||||||
|
{
|
||||||
|
UINT32 index;
|
||||||
|
UINT32 size = (LOSCFG_BASE_CORE_TSK_LIMIT + 1) * sizeof(MuxDLinkCB);
|
||||||
|
|
||||||
|
/* system resident memory, don't free */
|
||||||
|
g_muxDeadlockCBArray = (MuxDLinkCB *)LOS_MemAlloc(m_aucSysMem1, size);
|
||||||
|
if (g_muxDeadlockCBArray == NULL) {
|
||||||
|
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
|
||||||
|
return LOS_NOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < LOSCFG_BASE_CORE_TSK_LIMIT + 1; index++) {
|
||||||
|
g_muxDeadlockCBArray[index].lastAccessTime = 0;
|
||||||
|
LOS_ListInit(&g_muxDeadlockCBArray[index].muxListHead);
|
||||||
|
}
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMuxDlockNodeInsert(UINT32 taskId, VOID *muxCB) //用于向指定任务的互斥锁链表中插入一个互斥锁节点//
|
||||||
|
{
|
||||||
|
MuxDLinkNode *muxDLNode = NULL;
|
||||||
|
|
||||||
|
if ((taskId > LOSCFG_BASE_CORE_TSK_LIMIT) || (muxCB == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
muxDLNode = (MuxDLinkNode *)LOS_MemAlloc(m_aucSysMem1, sizeof(MuxDLinkNode));
|
||||||
|
if (muxDLNode == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(VOID)memset_s(muxDLNode, sizeof(MuxDLinkNode), 0, sizeof(MuxDLinkNode));
|
||||||
|
muxDLNode->muxCB = muxCB;
|
||||||
|
|
||||||
|
LOS_ListTailInsert(&g_muxDeadlockCBArray[taskId].muxListHead, &muxDLNode->muxList);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMuxDlockNodeDelete(UINT32 taskId, const VOID *muxCB) //用于从指定任务的互斥锁链表中删除指定的互斥锁节点//
|
||||||
|
{
|
||||||
|
MuxDLinkCB *muxDLCB = NULL;
|
||||||
|
LOS_DL_LIST *list = NULL;
|
||||||
|
MuxDLinkNode *muxDLNode = NULL;
|
||||||
|
|
||||||
|
if ((taskId > LOSCFG_BASE_CORE_TSK_LIMIT) || (muxCB == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
muxDLCB = &g_muxDeadlockCBArray[taskId];
|
||||||
|
LOS_DL_LIST_FOR_EACH(list, &muxDLCB->muxListHead) {
|
||||||
|
muxDLNode = LOS_DL_LIST_ENTRY(list, MuxDLinkNode, muxList);
|
||||||
|
if (muxDLNode->muxCB == muxCB) {
|
||||||
|
LOS_ListDelete(&muxDLNode->muxList);
|
||||||
|
(VOID)LOS_MemFree(m_aucSysMem1, muxDLNode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsTaskTimeUpdate(UINT32 taskId, UINT64 tickCount) //用于更新任务的最后访问时间//
|
||||||
|
{
|
||||||
|
if (taskId > LOSCFG_BASE_CORE_TSK_LIMIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_muxDeadlockCBArray[taskId].lastAccessTime = tickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC VOID OsDeadlockBackTrace(const LosTaskCB *taskCB) //用于打印任务的函数调用栈信息//
|
||||||
|
{
|
||||||
|
TaskContext *context = NULL;
|
||||||
|
|
||||||
|
PRINTK("*******backtrace begin*******\n");
|
||||||
|
context = (TaskContext *)taskCB->stackPointer;
|
||||||
|
ArchBackTraceWithSp(context);
|
||||||
|
PRINTK("********backtrace end********\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC VOID OsMutexPendTaskList(LOS_DL_LIST *list) //用于打印互斥锁等待任务的列表信息//
|
||||||
|
{
|
||||||
|
LOS_DL_LIST *listTmp = NULL;
|
||||||
|
LosTaskCB *pendedTask = NULL;
|
||||||
|
CHAR *name = NULL;
|
||||||
|
UINT32 index = 0;
|
||||||
|
UINT32 id, intSave;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
if (LOS_ListEmpty(list) == TRUE) {
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINTK("Pended Task: null\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOS_DL_LIST_FOR_EACH(listTmp, list) {
|
||||||
|
pendedTask = OS_TCB_FROM_PENDLIST(listTmp);
|
||||||
|
name = pendedTask->taskName;
|
||||||
|
id = pendedTask->taskId;
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
if (index == 0) {
|
||||||
|
PRINTK("Pended task: %u. name:%-15s, id:0x%-5x\n", index, name, id);
|
||||||
|
} else {
|
||||||
|
PRINTK(" %u. name:%-15s, id:0x%-5x\n", index, name, id);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC VOID OsTaskHoldMutexList(MuxDLinkCB *muxDLCB) //用于打印任务持有的互斥锁的信息//
|
||||||
|
{
|
||||||
|
UINT32 index = 0;
|
||||||
|
MuxDLinkNode *muxDLNode = NULL;
|
||||||
|
CHAR *ownerName = NULL;
|
||||||
|
LosMuxCB *muxCB = NULL;
|
||||||
|
LOS_DL_LIST *list = NULL;
|
||||||
|
LOS_DL_LIST *listTmp = NULL;
|
||||||
|
UINT32 count, intSave;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
if (LOS_ListEmpty(&muxDLCB->muxListHead) == TRUE) {
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINTK("null\n");
|
||||||
|
} else {
|
||||||
|
LOS_DL_LIST_FOR_EACH(list, &muxDLCB->muxListHead) {
|
||||||
|
muxDLNode = LOS_DL_LIST_ENTRY(list, MuxDLinkNode, muxList);
|
||||||
|
muxCB = (LosMuxCB *)muxDLNode->muxCB;
|
||||||
|
count = muxCB->muxCount;
|
||||||
|
ownerName = muxCB->owner->taskName;
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINTK("<Mutex%u info>\n", index);
|
||||||
|
PRINTK("Ptr handle:%p\n", muxCB);
|
||||||
|
PRINTK("Owner:%s\n", ownerName);
|
||||||
|
PRINTK("Count:%u\n", count);
|
||||||
|
|
||||||
|
listTmp = &muxCB->muxList;
|
||||||
|
OsMutexPendTaskList(listTmp);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMutexDlockCheck(VOID) //用于检测互斥锁死锁情况并输出相关信息//
|
||||||
|
{
|
||||||
|
UINT32 loop, intSave;
|
||||||
|
UINT32 taskId;
|
||||||
|
CHAR *name = NULL;
|
||||||
|
LosTaskCB *taskCB = NULL;
|
||||||
|
MuxDLinkCB *muxDLCB = NULL;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
for (loop = 0; loop < g_taskMaxNum; loop++) {
|
||||||
|
taskCB = (LosTaskCB *)g_taskCBArray + loop;
|
||||||
|
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
muxDLCB = &g_muxDeadlockCBArray[taskCB->taskId];
|
||||||
|
if ((LOS_TickCountGet() - muxDLCB->lastAccessTime) > OS_MUX_DEADLOCK_CHECK_THRESHOLD) {
|
||||||
|
name = taskCB->taskName;
|
||||||
|
taskId = taskCB->taskId;
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINTK("Task_name:%s, ID:0x%x, holds the Mutexs below:\n", name, taskId);
|
||||||
|
OsTaskHoldMutexList(muxDLCB);
|
||||||
|
OsDeadlockBackTrace(taskCB);
|
||||||
|
PRINTK("\n");
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LOSCFG_SHELL //用于在命令行中执行互斥锁死锁检查并输出相关信息//
|
||||||
|
UINT32 OsShellCmdMuxDeadlockCheck(UINT32 argc, const CHAR **argv)
|
||||||
|
{
|
||||||
|
if (argc > 0) {
|
||||||
|
PRINTK("\nUsage: dlock\n");
|
||||||
|
return OS_ERROR;
|
||||||
|
}
|
||||||
|
PRINTK("Start mutexs deadlock check: \n");
|
||||||
|
OsMutexDlockCheck();
|
||||||
|
PRINTK("-----------End-----------\n");
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
SHELLCMD_ENTRY(deadlock_shellcmd, CMD_TYPE_EX, "dlock", 0, (CmdCallBackFunc)OsShellCmdMuxDeadlockCheck);
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
@ -0,0 +1,189 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
|
||||||
|
* Description: Mutex Debug
|
||||||
|
* 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.
|
||||||
|
* --------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "los_mux_debug_pri.h"
|
||||||
|
#include "los_typedef.h"
|
||||||
|
#include "los_task.h"
|
||||||
|
#include "los_misc_pri.h"
|
||||||
|
#include "arch/exception.h"
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
#include "shcmd.h"
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef LOSCFG_DEBUG_MUTEX //用于表示互斥锁的调试信息//
|
||||||
|
typedef struct {
|
||||||
|
TSK_ENTRY_FUNC creator; /* The task entry who created this mutex */
|
||||||
|
UINT64 lastAccessTime; /* The last access time */
|
||||||
|
} MuxDebugCB;
|
||||||
|
STATIC MuxDebugCB *g_muxDebugArray = NULL;
|
||||||
|
|
||||||
|
//用于比较两个互斥锁调试信息的最后访问时间//
|
||||||
|
STATIC BOOL MuxCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right)
|
||||||
|
{
|
||||||
|
return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) >
|
||||||
|
*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right)));
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 OsMuxDbgInit(VOID) //用于初始化互斥锁调试信息数组//
|
||||||
|
{
|
||||||
|
UINT32 size = LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(MuxDebugCB);
|
||||||
|
/* system resident memory, don't free */
|
||||||
|
g_muxDebugArray = (MuxDebugCB *)LOS_MemAlloc(m_aucSysMem1, size);
|
||||||
|
if (g_muxDebugArray == NULL) {
|
||||||
|
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
|
||||||
|
return LOS_NOK;
|
||||||
|
}
|
||||||
|
(VOID)memset_s(g_muxDebugArray, size, 0, size);
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMuxDbgTimeUpdate(UINT32 muxId) //用于更新指定互斥锁的最后访问时间//
|
||||||
|
{
|
||||||
|
MuxDebugCB *muxDebug = &g_muxDebugArray[GET_MUX_INDEX(muxId)];
|
||||||
|
muxDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMuxDbgUpdate(UINT32 muxId, TSK_ENTRY_FUNC creator) //用于更新指定互斥锁的创建者和最后访问时间//
|
||||||
|
{
|
||||||
|
MuxDebugCB *muxDebug = &g_muxDebugArray[GET_MUX_INDEX(muxId)];
|
||||||
|
muxDebug->creator = creator;
|
||||||
|
muxDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
//用于对互斥锁索引数组进行排序,并检查可能存在的互斥锁泄漏//
|
||||||
|
STATIC VOID SortMuxIndexArray(UINT32 *indexArray, UINT32 count)
|
||||||
|
{
|
||||||
|
LosMuxCB muxNode = {{0, 0}, 0, 0, 0, 0};
|
||||||
|
MuxDebugCB muxDebugNode = {0};
|
||||||
|
UINT32 index, intSave;
|
||||||
|
SortParam muxSortParam;
|
||||||
|
muxSortParam.buf = (CHAR *)g_muxDebugArray;
|
||||||
|
muxSortParam.ctrlBlockSize = sizeof(MuxDebugCB);
|
||||||
|
muxSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_MUX_LIMIT;
|
||||||
|
muxSortParam.sortElemOff = LOS_OFF_SET_OF(MuxDebugCB, lastAccessTime);
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
OsArraySort(indexArray, 0, count - 1, &muxSortParam, MuxCompareValue);
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
for (index = 0; index < count; index++) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&muxNode, sizeof(LosMuxCB),
|
||||||
|
GET_MUX(indexArray[index]), sizeof(LosMuxCB));
|
||||||
|
(VOID)memcpy_s(&muxDebugNode, sizeof(MuxDebugCB),
|
||||||
|
&g_muxDebugArray[indexArray[index]], sizeof(MuxDebugCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
/*
|
||||||
|
* muxStat may be altered after the g_taskSpin is unlocked in OsMutexCheck.
|
||||||
|
* We should recheck the muxStat before the print.
|
||||||
|
*/
|
||||||
|
if ((muxNode.muxStat != LOS_USED) ||
|
||||||
|
((muxNode.muxStat == LOS_USED) && ((muxDebugNode.creator == NULL) || (muxNode.owner == NULL)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PRINTK("Mutex ID <0x%x> may leak, TaskID of owner:0x%x, TaskEntry of owner: %p,"
|
||||||
|
"TaskEntry of creator: %p,Latest operation time: 0x%llx\n",
|
||||||
|
muxNode.muxId, muxNode.owner->taskId, muxNode.owner->taskEntry, muxDebugNode.creator,
|
||||||
|
muxDebugNode.lastAccessTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, indexArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsMutexCheck(VOID) //用于检查互斥锁的状态并对可能存在的互斥锁泄漏进行处理//
|
||||||
|
{
|
||||||
|
LosMuxCB muxNode = {{0, 0}, 0, 0, 0, 0};
|
||||||
|
MuxDebugCB muxDebugNode = {0};
|
||||||
|
UINT32 index, intSave;
|
||||||
|
UINT32 count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This return value does not need to be judged immediately,
|
||||||
|
* and the following code logic has already distinguished the return value from null and non-empty,
|
||||||
|
* and there is no case of accessing the null pointer.
|
||||||
|
*/
|
||||||
|
UINT32 *indexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(UINT32));
|
||||||
|
|
||||||
|
for (index = 0; index < LOSCFG_BASE_IPC_MUX_LIMIT; index++) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&muxNode, sizeof(LosMuxCB), GET_MUX(index), sizeof(LosMuxCB));
|
||||||
|
(VOID)memcpy_s(&muxDebugNode, sizeof(MuxDebugCB), &g_muxDebugArray[index], sizeof(MuxDebugCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
|
||||||
|
if ((muxNode.muxStat != LOS_USED) ||
|
||||||
|
((muxNode.muxStat == LOS_USED) && (muxDebugNode.creator == NULL))) {
|
||||||
|
continue;
|
||||||
|
} else if ((muxNode.muxStat == LOS_USED) && (muxNode.owner == NULL)) {
|
||||||
|
PRINTK("Mutex ID <0x%x> may leak, Owner is null, TaskEntry of creator: %p,"
|
||||||
|
"Latest operation time: 0x%llx\n",
|
||||||
|
muxNode.muxId, muxDebugNode.creator, muxDebugNode.lastAccessTime);
|
||||||
|
} else {
|
||||||
|
if (indexArray != NULL) {
|
||||||
|
*(indexArray + count) = index;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
PRINTK("Mutex ID <0x%x> may leak, TaskID of owner:0x%x, TaskEntry of owner: %p,"
|
||||||
|
"TaskEntry of creator: %p,Latest operation time: 0x%llx\n",
|
||||||
|
muxNode.muxId, muxNode.owner->taskId, muxNode.owner->taskEntry, muxDebugNode.creator,
|
||||||
|
muxDebugNode.lastAccessTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexArray != NULL) {
|
||||||
|
SortMuxIndexArray(indexArray, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
//用于获取互斥锁信息//
|
||||||
|
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdMuxInfoGet(UINT32 argc, const CHAR **argv)
|
||||||
|
{
|
||||||
|
if (argc > 0) {
|
||||||
|
PRINTK("\nUsage: mutex\n");
|
||||||
|
return OS_ERROR;
|
||||||
|
}
|
||||||
|
PRINTK("used mutexs information: \n");
|
||||||
|
OsMutexCheck();
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
SHELLCMD_ENTRY(mutex_shellcmd, CMD_TYPE_EX, "mutex", 0, (CmdCallBackFunc)OsShellCmdMuxInfoGet);
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
#endif /* LOSCFG_DEBUG_MUTEX */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
@ -0,0 +1,206 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
|
||||||
|
* Description: Queue Debug
|
||||||
|
* 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.
|
||||||
|
* --------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "los_queue_debug_pri.h"
|
||||||
|
#include "los_misc_pri.h"
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
#include "shcmd.h"
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef LOSCFG_DEBUG_QUEUE //用于保存队列的调试信息//
|
||||||
|
typedef struct {
|
||||||
|
TSK_ENTRY_FUNC creator; /* The task entry who created this queue */
|
||||||
|
UINT64 lastAccessTime; /* The last access time */
|
||||||
|
} QueueDebugCB;
|
||||||
|
STATIC QueueDebugCB *g_queueDebugArray = NULL;
|
||||||
|
|
||||||
|
//用于比较队列中的元素值//
|
||||||
|
STATIC BOOL QueueCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right)
|
||||||
|
{
|
||||||
|
return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) >
|
||||||
|
*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right)));
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 OsQueueDbgInit(VOID) //用于初始化队列的调试信息//
|
||||||
|
{
|
||||||
|
UINT32 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(QueueDebugCB);
|
||||||
|
|
||||||
|
/* system resident memory, don't free */
|
||||||
|
g_queueDebugArray = (QueueDebugCB *)LOS_MemAlloc(m_aucSysMem1, size);
|
||||||
|
if (g_queueDebugArray == NULL) {
|
||||||
|
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
|
||||||
|
return LOS_NOK;
|
||||||
|
}
|
||||||
|
(VOID)memset_s(g_queueDebugArray, size, 0, size);
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsQueueDbgTimeUpdate(UINT32 queueId) //用于更新队列的最后访问时间//
|
||||||
|
{
|
||||||
|
QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueId)];
|
||||||
|
queueDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsQueueDbgUpdate(UINT32 queueId, TSK_ENTRY_FUNC entry) //用于更新队列的调试信息//
|
||||||
|
{
|
||||||
|
QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueId)];
|
||||||
|
queueDebug->creator = entry;
|
||||||
|
queueDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC INLINE VOID OsQueueInfoOutPut(const LosQueueCB *node) //用于输出队列的信息//
|
||||||
|
{
|
||||||
|
PRINTK("Queue ID <0x%x> may leak, queue len is 0x%x, "
|
||||||
|
"readable cnt:0x%x, writeable cnt:0x%x, ",
|
||||||
|
node->queueId,
|
||||||
|
node->queueLen,
|
||||||
|
node->readWriteableCnt[OS_QUEUE_READ],
|
||||||
|
node->readWriteableCnt[OS_QUEUE_WRITE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC INLINE VOID OsQueueOpsOutput(const QueueDebugCB *node) //用于输出队列操作的信息//
|
||||||
|
{
|
||||||
|
PRINTK("TaskEntry of creator:0x%p, Latest operation time: 0x%llx\n",
|
||||||
|
node->creator, node->lastAccessTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC VOID SortQueueIndexArray(UINT32 *indexArray, UINT32 count) //用于对队列索引数组进行排序并输出相应的队列信息//
|
||||||
|
{
|
||||||
|
LosQueueCB queueNode = {0};
|
||||||
|
QueueDebugCB queueDebugNode = {0};
|
||||||
|
UINT32 index, intSave;
|
||||||
|
SortParam queueSortParam;
|
||||||
|
queueSortParam.buf = (CHAR *)g_queueDebugArray;
|
||||||
|
queueSortParam.ctrlBlockSize = sizeof(QueueDebugCB);
|
||||||
|
queueSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_QUEUE_LIMIT;
|
||||||
|
queueSortParam.sortElemOff = LOS_OFF_SET_OF(QueueDebugCB, lastAccessTime);
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
OsArraySort(indexArray, 0, count - 1, &queueSortParam, QueueCompareValue);
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
for (index = 0; index < count; index++) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&queueNode, sizeof(LosQueueCB),
|
||||||
|
GET_QUEUE_HANDLE(indexArray[index]), sizeof(LosQueueCB));
|
||||||
|
(VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB),
|
||||||
|
&g_queueDebugArray[indexArray[index]], sizeof(QueueDebugCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
if (queueNode.queueState == LOS_UNUSED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OsQueueInfoOutPut(&queueNode);
|
||||||
|
OsQueueOpsOutput(&queueDebugNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, indexArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsQueueCheck(VOID) //用于检查队列的状态并输出相应信息//
|
||||||
|
{
|
||||||
|
LosQueueCB queueNode = {0};
|
||||||
|
QueueDebugCB queueDebugNode = {0};
|
||||||
|
UINT32 index, intSave;
|
||||||
|
UINT32 count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This return value does not need to be judged immediately,
|
||||||
|
* and the following code logic has already distinguished the return value from null and non-empty,
|
||||||
|
* and there is no case of accessing the null pointer.
|
||||||
|
*/
|
||||||
|
UINT32 *indexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(UINT32));
|
||||||
|
|
||||||
|
for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&queueNode, sizeof(LosQueueCB),
|
||||||
|
GET_QUEUE_HANDLE(index), sizeof(LosQueueCB));
|
||||||
|
(VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB),
|
||||||
|
&g_queueDebugArray[index], sizeof(QueueDebugCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
if ((queueNode.queueState == LOS_UNUSED) ||
|
||||||
|
((queueNode.queueState == LOS_USED) && (queueDebugNode.creator == NULL))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((queueNode.queueState == LOS_USED) &&
|
||||||
|
(queueNode.queueLen == queueNode.readWriteableCnt[OS_QUEUE_WRITE]) &&
|
||||||
|
LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_READ]) &&
|
||||||
|
LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_WRITE]) &&
|
||||||
|
LOS_ListEmpty(&queueNode.memList)) {
|
||||||
|
PRINTK("Queue ID <0x%x> may leak, No task uses it, "
|
||||||
|
"QueueLen is 0x%x, ",
|
||||||
|
queueNode.queueId,
|
||||||
|
queueNode.queueLen);
|
||||||
|
OsQueueOpsOutput(&queueDebugNode);
|
||||||
|
} else {
|
||||||
|
if (indexArray != NULL) {
|
||||||
|
*(indexArray + count) = index;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
OsQueueInfoOutPut(&queueNode);
|
||||||
|
OsQueueOpsOutput(&queueDebugNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexArray != NULL) {
|
||||||
|
SortQueueIndexArray(indexArray, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
//当用户输入 "queue" 命令时,会输出已使用队列的信息//
|
||||||
|
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdQueueInfoGet(UINT32 argc, const CHAR **argv)
|
||||||
|
{
|
||||||
|
if (argc > 0) {
|
||||||
|
PRINTK("\nUsage: queue\n");
|
||||||
|
return OS_ERROR;
|
||||||
|
}
|
||||||
|
PRINTK("used queues information: \n");
|
||||||
|
OsQueueCheck();
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELLCMD_ENTRY(queue_shellcmd, CMD_TYPE_EX, "queue", 0, (CmdCallBackFunc)OsShellCmdQueueInfoGet);
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
#endif /* LOSCFG_DEBUG_QUEUE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
@ -0,0 +1,347 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
||||||
|
* Description: Schedule Statistics
|
||||||
|
* Author: Huawei LiteOS Team
|
||||||
|
* Create: 2018-11-16
|
||||||
|
* 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.
|
||||||
|
* --------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "los_task_pri.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef LOSCFG_DEBUG_SCHED_STATISTICS
|
||||||
|
#define HIGHTASKPRI 16
|
||||||
|
#define NS_PER_MS 1000000
|
||||||
|
#define DECIMAL_TO_PERCENTAGE 100
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT64 idleRuntime; //空闲任务的运行时间//
|
||||||
|
UINT64 idleStarttime; //空闲任务的启动时间//
|
||||||
|
UINT64 highTaskRuntime; //高优先级任务的运行时间//
|
||||||
|
UINT64 highTaskStarttime; //高优先级任务的启动时间//
|
||||||
|
UINT64 sumPriority; //任务优先级之和//
|
||||||
|
UINT32 prioritySwitch; //任务切换次数//
|
||||||
|
UINT32 highTaskSwitch; //高优先级任务切换次数//
|
||||||
|
UINT32 contexSwitch; //上下文切换次数//
|
||||||
|
UINT32 hwiNum; //硬件中断次数//
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
UINT32 ipiIrqNum; //中断次数(仅在多核配置下定义)//
|
||||||
|
#endif
|
||||||
|
} StatPercpu;
|
||||||
|
|
||||||
|
STATIC BOOL g_statisticsStartFlag = FALSE;
|
||||||
|
STATIC UINT64 g_statisticsStartTime;
|
||||||
|
STATIC StatPercpu g_statPercpu[LOSCFG_KERNEL_CORE_NUM];
|
||||||
|
|
||||||
|
//用于在每个 CPU 核心上进行调度统计//
|
||||||
|
STATIC VOID OsSchedStatisticsPerCpu(const LosTaskCB *runTask, const LosTaskCB *newTask)
|
||||||
|
{
|
||||||
|
UINT32 cpuId;
|
||||||
|
UINT32 idleTaskId;
|
||||||
|
UINT64 now, runtime;
|
||||||
|
|
||||||
|
if (g_statisticsStartFlag != TRUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuId = ArchCurrCpuid();
|
||||||
|
idleTaskId = OsGetIdleTaskId();
|
||||||
|
now = LOS_CurrNanosec();
|
||||||
|
|
||||||
|
g_statPercpu[cpuId].contexSwitch++;
|
||||||
|
|
||||||
|
if ((runTask->taskId != idleTaskId) && (newTask->taskId == idleTaskId)) {
|
||||||
|
g_statPercpu[cpuId].idleStarttime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((runTask->taskId == idleTaskId) && (newTask->taskId != idleTaskId)) {
|
||||||
|
runtime = now - g_statPercpu[cpuId].idleStarttime;
|
||||||
|
g_statPercpu[cpuId].idleRuntime += runtime;
|
||||||
|
g_statPercpu[cpuId].idleStarttime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((runTask->priority >= HIGHTASKPRI) && (newTask->priority < HIGHTASKPRI)) {
|
||||||
|
g_statPercpu[cpuId].highTaskStarttime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((runTask->priority < HIGHTASKPRI) && (newTask->priority >= HIGHTASKPRI)) {
|
||||||
|
runtime = now - g_statPercpu[cpuId].highTaskStarttime;
|
||||||
|
g_statPercpu[cpuId].highTaskRuntime += runtime;
|
||||||
|
g_statPercpu[cpuId].highTaskStarttime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newTask->priority < HIGHTASKPRI) {
|
||||||
|
g_statPercpu[cpuId].highTaskSwitch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newTask->taskId != idleTaskId) {
|
||||||
|
g_statPercpu[cpuId].sumPriority += newTask->priority;
|
||||||
|
g_statPercpu[cpuId].prioritySwitch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//用于更新调度统计信息//
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsSchedStatistics(LosTaskCB *runTask, LosTaskCB *newTask)
|
||||||
|
{
|
||||||
|
UINT64 runtime;
|
||||||
|
UINT32 cpuId = ArchCurrCpuid();
|
||||||
|
UINT64 now = LOS_CurrNanosec();
|
||||||
|
|
||||||
|
SchedStat *schedRun = &runTask->schedStat;
|
||||||
|
SchedStat *schedNew = &newTask->schedStat;
|
||||||
|
SchedPercpu *cpuRun = &schedRun->schedPercpu[cpuId];
|
||||||
|
SchedPercpu *cpuNew = &schedNew->schedPercpu[cpuId];
|
||||||
|
|
||||||
|
/* calculate one chance of running time */
|
||||||
|
runtime = now - schedRun->startRuntime;
|
||||||
|
|
||||||
|
/* add running timer to running task statistics */
|
||||||
|
cpuRun->runtime += runtime;
|
||||||
|
schedRun->allRuntime += runtime;
|
||||||
|
|
||||||
|
/* add context switch counters and schedule start time */
|
||||||
|
cpuNew->contexSwitch++;
|
||||||
|
schedNew->allContextSwitch++;
|
||||||
|
schedNew->startRuntime = now;
|
||||||
|
OsSchedStatisticsPerCpu(runTask, newTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsHwiStatistics(size_t intNum) //用于更新硬中断的统计信息//
|
||||||
|
{
|
||||||
|
UINT32 cpuId = ArchCurrCpuid();
|
||||||
|
|
||||||
|
if ((g_statisticsStartFlag != TRUE) || (intNum == OS_TICK_INT_NUM)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_statPercpu[cpuId].hwiNum++;
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
/* 16: 0~15 is ipi interrupts */
|
||||||
|
if (intNum < 16) {
|
||||||
|
g_statPercpu[cpuId].ipiIrqNum++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsShellCmdDumpSched(VOID) //用于打印任务的调度统计信息//
|
||||||
|
{
|
||||||
|
LosTaskCB *taskCB = NULL;
|
||||||
|
UINT32 loop;
|
||||||
|
UINT32 cpuId;
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
UINT32 affinity;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PRINTK("\n");
|
||||||
|
PRINTK("Task TID Total Time Total CST "
|
||||||
|
"CPU Time CST\n");
|
||||||
|
PRINTK("---- --- ------------------ ---------- -"
|
||||||
|
"--- ------------------ ----------\n");
|
||||||
|
|
||||||
|
for (loop = 0; loop < g_taskMaxNum; loop++) {
|
||||||
|
taskCB = (((LosTaskCB *)g_taskCBArray) + loop);
|
||||||
|
if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
affinity = (UINT32)taskCB->cpuAffiMask;
|
||||||
|
#endif
|
||||||
|
PRINTK("%-30s0x%-6x%+16lf ms %10u\n", taskCB->taskName, taskCB->taskId,
|
||||||
|
(DOUBLE)(taskCB->schedStat.allRuntime) / NS_PER_MS,
|
||||||
|
taskCB->schedStat.allContextSwitch);
|
||||||
|
|
||||||
|
for (cpuId = 0; cpuId < LOSCFG_KERNEL_CORE_NUM; cpuId++) {
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
if (!((1U << cpuId) & affinity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
PRINTK(" "
|
||||||
|
"CPU%u %+16lf ms %12u\n", cpuId,
|
||||||
|
(DOUBLE)(taskCB->schedStat.schedPercpu[cpuId].runtime) / NS_PER_MS,
|
||||||
|
taskCB->schedStat.schedPercpu[cpuId].contexSwitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTK("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsStatisticsShow(UINT64 statisticsPastTime) //用于显示系统的统计信息//
|
||||||
|
{
|
||||||
|
UINT32 cpuId;
|
||||||
|
PRINTK("\n");
|
||||||
|
PRINTK("Passed Time: %+16lf ms\n", ((DOUBLE)statisticsPastTime / NS_PER_MS));
|
||||||
|
PRINTK("--------------------------------\n");
|
||||||
|
PRINTK("CPU Idle(%%) ContexSwitch HwiNum "
|
||||||
|
"Avg Pri HiTask(%%) HiTask SwiNum HiTask P(ms)"
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
" MP Hwi\n");
|
||||||
|
#else
|
||||||
|
"\n");
|
||||||
|
#endif
|
||||||
|
PRINTK("---- --------- ----------- -------- --------- "
|
||||||
|
"---------- ------------ ----------"
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
" ------\n");
|
||||||
|
#else
|
||||||
|
"\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (cpuId = 0; cpuId < LOSCFG_KERNEL_CORE_NUM; cpuId++) {
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
PRINTK("CPU%u %+10lf%14u%14u %+11lf %+11lf%14u %+11lf %11u\n", cpuId,
|
||||||
|
#else
|
||||||
|
PRINTK("CPU%u %+10lf%14u%14u %+11lf %+11lf%14u %+11lf\n", cpuId,
|
||||||
|
#endif
|
||||||
|
((DOUBLE)(g_statPercpu[cpuId].idleRuntime) / statisticsPastTime) * DECIMAL_TO_PERCENTAGE,
|
||||||
|
g_statPercpu[cpuId].contexSwitch,
|
||||||
|
g_statPercpu[cpuId].hwiNum,
|
||||||
|
(g_statPercpu[cpuId].prioritySwitch == 0) ? OS_TASK_PRIORITY_LOWEST :
|
||||||
|
((DOUBLE)(g_statPercpu[cpuId].sumPriority) / (g_statPercpu[cpuId].prioritySwitch)),
|
||||||
|
((DOUBLE)(g_statPercpu[cpuId].highTaskRuntime) / statisticsPastTime) * DECIMAL_TO_PERCENTAGE,
|
||||||
|
g_statPercpu[cpuId].highTaskSwitch,
|
||||||
|
(g_statPercpu[cpuId].highTaskSwitch == 0) ? 0 :
|
||||||
|
((DOUBLE)(g_statPercpu[cpuId].highTaskRuntime) / (g_statPercpu[cpuId].highTaskSwitch)) / NS_PER_MS
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
, g_statPercpu[cpuId].ipiIrqNum);
|
||||||
|
#else
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTK("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsShellStatisticsStart(VOID) //用于在多核系统中启动统计功能//
|
||||||
|
{
|
||||||
|
LosTaskCB *taskCB = NULL;
|
||||||
|
UINT32 loop;
|
||||||
|
UINT32 cpuId = 0;
|
||||||
|
UINT32 intSave;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
|
||||||
|
if (g_statisticsStartFlag) {
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINT_WARN("mp static has started\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_statisticsStartTime = LOS_CurrNanosec();
|
||||||
|
|
||||||
|
for (loop = 0; loop < g_taskMaxNum; loop++) {
|
||||||
|
taskCB = (((LosTaskCB *)g_taskCBArray) + loop);
|
||||||
|
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
cpuId = taskCB->currCpu;
|
||||||
|
#endif
|
||||||
|
if ((UINT32)(OS_TASK_INVALID_CPUID) == cpuId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(taskCB->taskName, "IdleCore000")) {
|
||||||
|
g_statPercpu[cpuId].idleStarttime = g_statisticsStartTime;
|
||||||
|
}
|
||||||
|
if (taskCB->priority < HIGHTASKPRI) {
|
||||||
|
g_statPercpu[cpuId].highTaskStarttime = g_statisticsStartTime;
|
||||||
|
g_statPercpu[cpuId].highTaskSwitch++;
|
||||||
|
}
|
||||||
|
if (strcmp(taskCB->taskName, "IdleCore000")) {
|
||||||
|
g_statPercpu[cpuId].sumPriority += taskCB->priority;
|
||||||
|
g_statPercpu[cpuId].prioritySwitch++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_statisticsStartFlag = TRUE;
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
|
||||||
|
PRINTK("mp static start\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//用于在多核系统中停止统计功能,并进行统计数据的处理和展示//
|
||||||
|
LITE_OS_SEC_TEXT_MINOR VOID OsShellStatisticsStop(VOID)
|
||||||
|
{
|
||||||
|
LosTaskCB *taskCB = NULL;
|
||||||
|
UINT32 loop;
|
||||||
|
UINT32 cpuId = 0;
|
||||||
|
UINT64 statisticsStopTime;
|
||||||
|
UINT64 statisticsPastTime;
|
||||||
|
UINT64 runtime;
|
||||||
|
UINT32 intSave;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
|
||||||
|
if (g_statisticsStartFlag != TRUE) {
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
PRINT_WARN("Please set mp static start\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_statisticsStartFlag = FALSE;
|
||||||
|
statisticsStopTime = LOS_CurrNanosec();
|
||||||
|
statisticsPastTime = statisticsStopTime - g_statisticsStartTime;
|
||||||
|
|
||||||
|
for (loop = 0; loop < g_taskMaxNum; loop++) {
|
||||||
|
taskCB = (((LosTaskCB *)g_taskCBArray) + loop);
|
||||||
|
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
|
||||||
|
#ifdef LOSCFG_KERNEL_SMP
|
||||||
|
cpuId = taskCB->currCpu;
|
||||||
|
#endif
|
||||||
|
if (cpuId == (UINT32)(OS_TASK_INVALID_CPUID)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(taskCB->taskName, "IdleCore000")) {
|
||||||
|
runtime = statisticsStopTime - g_statPercpu[cpuId].idleStarttime;
|
||||||
|
g_statPercpu[cpuId].idleRuntime += runtime;
|
||||||
|
g_statPercpu[cpuId].idleStarttime = 0;
|
||||||
|
}
|
||||||
|
if (taskCB->priority < HIGHTASKPRI) {
|
||||||
|
runtime = statisticsStopTime - g_statPercpu[cpuId].highTaskStarttime;
|
||||||
|
g_statPercpu[cpuId].highTaskRuntime += runtime;
|
||||||
|
g_statPercpu[cpuId].highTaskStarttime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
OsStatisticsShow(statisticsPastTime);
|
||||||
|
|
||||||
|
(VOID)memset_s(g_statPercpu, sizeof(g_statPercpu), 0, sizeof(g_statPercpu));
|
||||||
|
g_statisticsStartTime = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* __cplusplus */
|
@ -0,0 +1,299 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
|
||||||
|
* Description: Sem Debug
|
||||||
|
* 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.
|
||||||
|
* --------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include "los_sem_debug_pri.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "los_typedef.h"
|
||||||
|
#include "los_task_pri.h"
|
||||||
|
#include "los_misc_pri.h"
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
#include "shcmd.h"
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef LOSCFG_DEBUG_SEMAPHORE
|
||||||
|
#define OS_ALL_SEM_MASK 0xffffffff
|
||||||
|
|
||||||
|
STATIC VOID OsSemPendedTaskNamePrint(LosSemCB *semNode) //用于打印等待某个信号量的任务列表//
|
||||||
|
{
|
||||||
|
LosTaskCB *tskCB = NULL;
|
||||||
|
CHAR *nameArr[LOSCFG_BASE_CORE_TSK_LIMIT] = {0};
|
||||||
|
UINT32 i, intSave;
|
||||||
|
UINT32 num = 0;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
if ((semNode->semStat == LOS_UNUSED) || (LOS_ListEmpty(&semNode->semList))) {
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &semNode->semList, LosTaskCB, pendList) {
|
||||||
|
nameArr[num++] = tskCB->taskName;
|
||||||
|
if (num == LOSCFG_BASE_CORE_TSK_LIMIT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
|
||||||
|
PRINTK("Pended task list : ");
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
PRINTK("%s\n", nameArr[i]);
|
||||||
|
} else {
|
||||||
|
PRINTK(", %s", nameArr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PRINTK("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct { //用于记录信号量的调试信息//
|
||||||
|
UINT16 origSemCount; /* Number of original available semaphores */
|
||||||
|
UINT64 lastAccessTime; /* The last operation time */
|
||||||
|
TSK_ENTRY_FUNC creator; /* The task entry who created this sem */
|
||||||
|
} SemDebugCB;
|
||||||
|
STATIC SemDebugCB *g_semDebugArray = NULL; //用于存储所有信号量的调试信息//
|
||||||
|
|
||||||
|
//用于比较两个排序元素的值//
|
||||||
|
STATIC BOOL SemCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right)
|
||||||
|
{
|
||||||
|
return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) >
|
||||||
|
*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right)));
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 OsSemDbgInit(VOID) //用于初始化信号量的调试信息数组//
|
||||||
|
{
|
||||||
|
UINT32 size = LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(SemDebugCB);
|
||||||
|
/* system resident memory, don't free */
|
||||||
|
g_semDebugArray = (SemDebugCB *)LOS_MemAlloc(m_aucSysMem1, size);
|
||||||
|
if (g_semDebugArray == NULL) {
|
||||||
|
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
|
||||||
|
return LOS_NOK;
|
||||||
|
}
|
||||||
|
(VOID)memset_s(g_semDebugArray, size, 0, size);
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsSemDbgTimeUpdate(UINT32 semId) //用于更新指定信号量的最后一次访问时间//
|
||||||
|
{
|
||||||
|
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semId)];
|
||||||
|
semDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID OsSemDbgUpdate(UINT32 semId, TSK_ENTRY_FUNC creator, UINT16 count) //用于更新指定信号量的调试信息//
|
||||||
|
{
|
||||||
|
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semId)];
|
||||||
|
semDebug->creator = creator;
|
||||||
|
semDebug->lastAccessTime = LOS_TickCountGet();
|
||||||
|
semDebug->origSemCount = count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*用于按照信号量的最后访问时间对当前正在使用的信号量进行排序,*/
|
||||||
|
/*并打印每个信号量的调试信息和等待该信号量的任务名*/
|
||||||
|
STATIC VOID OsSemSort(UINT32 *semIndexArray, UINT32 usedCount)
|
||||||
|
{
|
||||||
|
UINT32 i, intSave;
|
||||||
|
LosSemCB *semCB = NULL;
|
||||||
|
LosSemCB semNode = {0};
|
||||||
|
SemDebugCB semDebug = {0};
|
||||||
|
SortParam semSortParam;
|
||||||
|
semSortParam.buf = (CHAR *)g_semDebugArray;
|
||||||
|
semSortParam.ctrlBlockSize = sizeof(SemDebugCB);
|
||||||
|
semSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_SEM_LIMIT;
|
||||||
|
semSortParam.sortElemOff = LOS_OFF_SET_OF(SemDebugCB, lastAccessTime);
|
||||||
|
|
||||||
|
/* It will Print out ALL the Used Semaphore List. */
|
||||||
|
PRINTK("Used Semaphore List: \n");
|
||||||
|
PRINTK("\r\n SemID Count OriginalCount Creater(TaskEntry) LastAccessTime\n");
|
||||||
|
PRINTK(" ------ ------ ------------- ------------------ -------------- \n");
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
OsArraySort(semIndexArray, 0, usedCount - 1, &semSortParam, SemCompareValue);
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
for (i = 0; i < usedCount; i++) {
|
||||||
|
semCB = GET_SEM(semIndexArray[i]);
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
|
||||||
|
(VOID)memcpy_s(&semDebug, sizeof(SemDebugCB), &g_semDebugArray[semIndexArray[i]], sizeof(SemDebugCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
if ((semNode.semStat != LOS_USED) || (semDebug.creator == NULL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PRINTK(" 0x%-07x0x%-07u0x%-14u%-22p0x%llx\n", semNode.semId, semDebug.origSemCount,
|
||||||
|
semNode.semCount, semDebug.creator, semDebug.lastAccessTime);
|
||||||
|
if (!LOS_ListEmpty(&semNode.semList)) {
|
||||||
|
OsSemPendedTaskNamePrint(semCB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*用于获取当前正在使用的信号量信息,并按照信号量的最后访问时间对信号量进行排序*/
|
||||||
|
UINT32 OsSemInfoGetFullData(VOID)
|
||||||
|
{
|
||||||
|
UINT32 usedSemCnt = 0;
|
||||||
|
LosSemCB *semNode = NULL;
|
||||||
|
SemDebugCB *semDebug = NULL;
|
||||||
|
UINT32 i;
|
||||||
|
UINT32 *semIndexArray = NULL;
|
||||||
|
UINT32 count, intSave;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
/* Get the used semaphore count. */
|
||||||
|
for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) {
|
||||||
|
semNode = GET_SEM(i);
|
||||||
|
semDebug = &g_semDebugArray[i];
|
||||||
|
if ((semNode->semStat == LOS_USED) && (semDebug->creator != NULL)) {
|
||||||
|
usedSemCnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
|
||||||
|
if (usedSemCnt > 0) {
|
||||||
|
semIndexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, usedSemCnt * sizeof(UINT32));
|
||||||
|
if (semIndexArray == NULL) {
|
||||||
|
PRINTK("LOS_MemAlloc failed in %s \n", __func__);
|
||||||
|
return LOS_NOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the semIndexArray with the real index. */
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) {
|
||||||
|
semNode = GET_SEM(i);
|
||||||
|
semDebug = &g_semDebugArray[i];
|
||||||
|
if ((semNode->semStat != LOS_USED) || (semDebug->creator == NULL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*(semIndexArray + count) = i;
|
||||||
|
count++;
|
||||||
|
/* if the count is touched usedSemCnt break. */
|
||||||
|
if (count >= usedSemCnt) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
OsSemSort(semIndexArray, count);
|
||||||
|
|
||||||
|
/* free the index array. */
|
||||||
|
(VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, semIndexArray);
|
||||||
|
}
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LOSCFG_SHELL
|
||||||
|
STATIC UINT32 OsSemInfoOutput(size_t semId) //用于输出信号量信息//
|
||||||
|
{
|
||||||
|
UINT32 loop, semCnt, intSave;
|
||||||
|
LosSemCB *semCB = NULL;
|
||||||
|
LosSemCB semNode = {0};
|
||||||
|
|
||||||
|
if (semId == OS_ALL_SEM_MASK) {
|
||||||
|
for (loop = 0, semCnt = 0; loop < LOSCFG_BASE_IPC_SEM_LIMIT; loop++) {
|
||||||
|
semCB = GET_SEM(loop);
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
if (semCB->semStat == LOS_USED) {
|
||||||
|
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
semCnt++;
|
||||||
|
PRINTK("\r\n SemID Count\n ---------- -----\n");
|
||||||
|
PRINTK(" 0x%08x %u\n", semNode.semId, semNode.semCount);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
}
|
||||||
|
PRINTK(" SemUsingNum : %u\n\n", semCnt);
|
||||||
|
return LOS_OK;
|
||||||
|
} else {
|
||||||
|
semCB = GET_SEM(semId);
|
||||||
|
SCHEDULER_LOCK(intSave);
|
||||||
|
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
|
||||||
|
SCHEDULER_UNLOCK(intSave);
|
||||||
|
if ((semNode.semId != semId) || (semNode.semStat != LOS_USED)) {
|
||||||
|
PRINTK("\nThe semaphore is not in use!\n");
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTK("\r\n SemID Count\n ---------- -----\n");
|
||||||
|
PRINTK(" 0x%08x 0x%u\n", semNode.semId, semNode.semCount);
|
||||||
|
|
||||||
|
if (LOS_ListEmpty(&semNode.semList)) {
|
||||||
|
PRINTK("No task is pended on this semaphore!\n");
|
||||||
|
return LOS_OK;
|
||||||
|
} else {
|
||||||
|
OsSemPendedTaskNamePrint(semCB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//用于获取信号量信息//
|
||||||
|
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdSemInfoGet(UINT32 argc, const CHAR **argv)
|
||||||
|
{
|
||||||
|
size_t semId;
|
||||||
|
CHAR *endPtr = NULL;
|
||||||
|
UINT32 ret;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
PRINTK("\nUsage: sem [fulldata|ID]\n");
|
||||||
|
return OS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
semId = OS_ALL_SEM_MASK;
|
||||||
|
} else {
|
||||||
|
if (strcmp(argv[0], "fulldata") == 0) {
|
||||||
|
ret = OsSemInfoGetFullData();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
semId = strtoul(argv[0], &endPtr, 0);
|
||||||
|
if ((*endPtr != 0) || (GET_SEM_INDEX(semId) >= LOSCFG_BASE_IPC_SEM_LIMIT)) {
|
||||||
|
PRINTK("\nsem ID can't access %s.\n", argv[0]);
|
||||||
|
return OS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = OsSemInfoOutput(semId);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELLCMD_ENTRY(sem_shellcmd, CMD_TYPE_EX, "sem", 1, (CmdCallBackFunc)OsShellCmdSemInfoGet);
|
||||||
|
#endif /* LOSCFG_SHELL */
|
||||||
|
#endif /* LOSCFG_DEBUG_SEMAPHORE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
Loading…
Reference in new issue