Dio 1 year ago
parent 97e95790e5
commit 48598e1fa9

@ -238,7 +238,373 @@ OUT:
}
VOID OsLockDepRecord(SPIN_LOCK_S *lock)
{/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* 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_base.h"
#include "los_spinlock.h"
#include "los_task_pri.h"
#include "los_printf_pri.h"
#include "los_atomic.h"
#include "los_exc.h"
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP
#define PRINT_BUF_SIZE 256
#define LOCKDEP_GET_NAME(lockDep, index) (((SPIN_LOCK_S *)((lockDep)->heldLocks[(index)].lockPtr))->name)
#define LOCKDEP_GET_ADDR(lockDep, index) ((lockDep)->heldLocks[(index)].lockAddr)
STATIC Atomic g_lockdepAvailable = 1;
/* atomic insurance for lockdep check */
STATIC INLINE VOID OsLockDepRequire(UINT32 *intSave)
{
*intSave = LOS_IntLock();
while (LOS_AtomicCmpXchg32bits(&g_lockdepAvailable, 0, 1)) {
/* busy waiting */
}
}
STATIC INLINE VOID OsLockDepRelease(UINT32 intSave)
{
LOS_AtomicSet(&g_lockdepAvailable, 1);
LOS_IntRestore(intSave);
}
STATIC INLINE UINT64 OsLockDepGetCycles(VOID)
{
UINT32 high, low;
LOS_GetCpuCycle(&high, &low);
/* combine cycleHi and cycleLo into 8 bytes cycles */
return (((UINT64)high << 32) + low); // 32 bits for lower half of UINT64
}
STATIC INLINE CHAR *OsLockDepErrorStringGet(enum LockDepErrType type)
{
CHAR *errorString = NULL;
switch (type) {
case LOCKDEP_ERR_DOUBLE_LOCK:
errorString = "double lock";
break;
case LOCKDEP_ERR_DEAD_LOCK:
errorString = "dead lock";
break;
case LOCKDEP_ERR_UNLOCK_WITOUT_LOCK:
errorString = "unlock without lock";
break;
case LOCKDEP_ERR_OVERFLOW:
errorString = "lockdep overflow";
break;
default:
errorString = "unknown error code";
break;
}
return errorString;
}
WEAK VOID OsLockDepPanic(enum LockDepErrType errType)
{
/* halt here */
(VOID)errType;
(VOID)LOS_IntLock();
OsBackTrace();
while (1) {}
}
STATIC VOID OsLockDepPrint(const CHAR *fmt, va_list ap)
{
UINT32 len;
CHAR buf[PRINT_BUF_SIZE] = {0};
len = vsnprintf_s(buf, PRINT_BUF_SIZE, PRINT_BUF_SIZE - 1, fmt, ap);
if ((len == -1) && (*buf == '\0')) {
/* parameter is illegal or some features in fmt dont support */
UartPuts("OsLockDepPrint is error\n", strlen("OsLockDepPrint is error\n"), 0);
return;
}
*(buf + len) = '\0';
UartPuts(buf, len, 0);
}
STATIC VOID OsPrintLockDepInfo(const CHAR *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
OsLockDepPrint(fmt, ap);
va_end(ap);
}
STATIC VOID OsLockDepDumpLock(const LosTaskCB *task, const SPIN_LOCK_S *lock,
const VOID *requestAddr, enum LockDepErrType errType)
{
INT32 i;
const LockDep *lockDep = &task->lockDep;
const LosTaskCB *temp = task;
OsPrintLockDepInfo("lockdep check failed\n");
OsPrintLockDepInfo("error type : %s\n", OsLockDepErrorStringGet(errType));
OsPrintLockDepInfo("request addr : 0x%x\n", requestAddr);
while (1) {
OsPrintLockDepInfo("task name : %s\n", temp->taskName);
OsPrintLockDepInfo("task id : %u\n", temp->taskID);
OsPrintLockDepInfo("cpu num : %u\n", temp->currCpu);
OsPrintLockDepInfo("start dumping lockdep information\n");
for (i = 0; i < lockDep->lockDepth; i++) {
if (lockDep->heldLocks[i].lockPtr == lock) {
OsPrintLockDepInfo("[%d] %s <-- addr:0x%x\n", i, LOCKDEP_GET_NAME(lockDep, i),
LOCKDEP_GET_ADDR(lockDep, i));
} else {
OsPrintLockDepInfo("[%d] %s \n", i, LOCKDEP_GET_NAME(lockDep, i));
}
}
OsPrintLockDepInfo("[%d] %s <-- now\n", i, lock->name);
if (errType == LOCKDEP_ERR_DEAD_LOCK) {
temp = lock->owner;
lock = temp->lockDep.waitLock;
lockDep = &temp->lockDep;
}
if (temp == task) {
break;
}
}
}
STATIC BOOL OsLockDepCheckDependency(const LosTaskCB *current, LosTaskCB *lockOwner)
{
BOOL checkResult = TRUE;
SPIN_LOCK_S *lockTemp = NULL;
do {
if (current == lockOwner) {
checkResult = FALSE;
return checkResult;
}
if (lockOwner->lockDep.waitLock != NULL) {
lockTemp = lockOwner->lockDep.waitLock;
lockOwner = lockTemp->owner;
} else {
break;
}
} while (lockOwner != SPINLOCK_OWNER_INIT);
return checkResult;
}
VOID OsLockDepCheckIn(SPIN_LOCK_S *lock)
{
UINT32 intSave;
enum LockDepErrType checkResult = LOCKDEP_SUCCESS;
VOID *requestAddr = (VOID *)__builtin_return_address(1);
LosTaskCB *current = OsCurrTaskGet();
LockDep *lockDep = &current->lockDep;
LosTaskCB *lockOwner = NULL;
OsLockDepRequire(&intSave);
if (lockDep->lockDepth >= (INT32)MAX_LOCK_DEPTH) {
checkResult = LOCKDEP_ERR_OVERFLOW;
goto OUT;
}
lockOwner = lock->owner;
/* not owned by any tasks yet, not doing following checks */
if (lockOwner == SPINLOCK_OWNER_INIT) {
goto OUT;
}
if (current == lockOwner) {
checkResult = LOCKDEP_ERR_DOUBLE_LOCK;
goto OUT;
}
if (OsLockDepCheckDependency(current, lockOwner) != TRUE) {
checkResult = LOCKDEP_ERR_DEAD_LOCK;
goto OUT;
}
OUT:
if (checkResult == LOCKDEP_SUCCESS) {
/*
* though the check may succeed, the waitLock still need to be set.
* because the OsLockDepCheckIn and OsLockDepRecord is not strictly multi-core
* sequential, there would be more than two tasks can pass the checking, but
* only one task can successfully obtain the lock.
*/
lockDep->waitLock = lock;
lockDep->heldLocks[lockDep->lockDepth].lockAddr = requestAddr;
lockDep->heldLocks[lockDep->lockDepth].waitTime = OsLockDepGetCycles(); /* start time */
OsLockDepRelease(intSave);
return;
}
OsLockDepDumpLock(current, lock, requestAddr, checkResult);
OsLockDepRelease(intSave);
OsLockDepPanic(checkResult);
}
VOID OsLockDepRecord(SPIN_LOCK_S *lock)
{
UINT32 intSave;
UINT64 cycles;
LosTaskCB *current = OsCurrTaskGet();
LockDep *lockDep = &current->lockDep;
HeldLocks *heldlock = &lockDep->heldLocks[lockDep->lockDepth];
OsLockDepRequire(&intSave);
/*
* OsLockDepCheckIn records start time t1, after the lock is obtained, we
* get the time t2, (t2 - t1) is the time of waiting for the lock
*/
cycles = OsLockDepGetCycles();
heldlock->waitTime = cycles - heldlock->waitTime;
heldlock->holdTime = cycles;
/* record lock info */
lock->owner = current;
lock->cpuid = ArchCurrCpuid();
/* record lockdep info */
heldlock->lockPtr = lock;
lockDep->lockDepth++;
lockDep->waitLock = NULL;
OsLockDepRelease(intSave);
}
VOID OsLockDepCheckOut(SPIN_LOCK_S *lock)
{
UINT32 intSave;
INT32 depth;
enum LockDepErrType checkResult;
VOID *requestAddr = (VOID *)__builtin_return_address(1);
LosTaskCB *current = OsCurrTaskGet();
LosTaskCB *owner = NULL;
LockDep *lockDep = NULL;
HeldLocks *heldlocks = NULL;
OsLockDepRequire(&intSave);
owner = lock->owner;
if (owner == SPINLOCK_OWNER_INIT) {
checkResult = LOCKDEP_ERR_UNLOCK_WITOUT_LOCK;
OsLockDepDumpLock(current, lock, requestAddr, checkResult);
OsLockDepRelease(intSave);
OsLockDepPanic(checkResult);
return;
}
lockDep = &owner->lockDep;
heldlocks = &lockDep->heldLocks[0];
depth = lockDep->lockDepth;
/* find the lock position */
while (--depth >= 0) {
if (heldlocks[depth].lockPtr == lock) {
break;
}
}
LOS_ASSERT(depth >= 0);
/* record lock holding time */
heldlocks[depth].holdTime = OsLockDepGetCycles() - heldlocks[depth].holdTime;
/* if unlock an older lock, needs move heldLock records */
while (depth < lockDep->lockDepth - 1) {
lockDep->heldLocks[depth] = lockDep->heldLocks[depth + 1];
depth++;
}
lockDep->lockDepth--;
lock->cpuid = (UINT32)(-1);
lock->owner = SPINLOCK_OWNER_INIT;
OsLockDepRelease(intSave);
}
VOID OsLockdepClearSpinlocks(VOID)
{
LosTaskCB *task = OsCurrTaskGet();
LockDep *lockDep = &task->lockDep;
SPIN_LOCK_S *lock = NULL;
/*
* Unlock spinlocks that running task has held.
* lockDepth will decrease after each spinlock is unlockded.
*/
while (lockDep->lockDepth) {
lock = lockDep->heldLocks[lockDep->lockDepth - 1].lockPtr;
LOS_SpinUnlock(lock);
}
}
#else /* LOSCFG_KERNEL_SMP_LOCKDEP */
VOID OsLockDepCheckIn(SPIN_LOCK_S *lock)
{
(VOID)lock;
return;
}
VOID OsLockDepRecord(SPIN_LOCK_S *lock)
{
(VOID)lock;
return;
}
VOID OsLockDepCheckOut(SPIN_LOCK_S *lock)
{
(VOID)lock;
return;
}
VOID OsLockdepClearSpinlocks(VOID)
{
return;
}
#endif
UINT32 intSave;
UINT64 cycles;
LosTaskCB *current = OsCurrTaskGet();

@ -1,3 +1,32 @@
/*!
* @file los_mp.c
* @brief
* @link
* @verbatim
CPU3(SMP+AMP+BMP) 鸿 SMP
Asymmetric multiprocessingAMPCPU
instantiation
Symmetric multiprocessingSMP
CPU
Bound multiprocessingBMP
CPU
线
PIC(Programmable Interrupt ControllerPIC
线线(Inter-Processor Interrupts,IPI
SGI:(Software Generated Interrupt)arm
SGI16,ID0~ID15
* @endverbatim
* @version
* @author weharmonyos.com | 鸿 |
* @date 2021-11-18
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
@ -36,43 +65,43 @@
#include "los_swtmr.h"
#include "los_task_pri.h"
#ifdef LOSCFG_KERNEL_SMP
#ifdef LOSCFG_KERNEL_SMP
//给参数CPU发送调度信号
#ifdef LOSCFG_KERNEL_SMP_CALL
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_mpCallSpin);
#define MP_CALL_LOCK(state) LOS_SpinLockSave(&g_mpCallSpin, &(state))
#define MP_CALL_UNLOCK(state) LOS_SpinUnlockRestore(&g_mpCallSpin, (state))
#endif
VOID LOS_MpSchedule(UINT32 target)
VOID LOS_MpSchedule(UINT32 target)//target每位对应CPU core
{
UINT32 cpuid = ArchCurrCpuid();
target &= ~(1U << cpuid);
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);
target &= ~(1U << cpuid);//获取除了自身之外的其他CPU
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);//向目标CPU发送调度信号,核间中断(Inter-Processor Interrupts),IPI
}
///硬中断唤醒处理函数
VOID OsMpWakeHandler(VOID)
{
/* generic wakeup ipi, do nothing */
}
///硬中断调度处理函数
VOID OsMpScheduleHandler(VOID)
{
{//将调度标志设置为与唤醒功能不同,这样就可以在硬中断结束时触发调度程序。
/*
* set schedule flag to differ from wake function,
* so that the scheduler can be triggered at the end of irq.
*/
OsSchedRunqueuePendingSet();
}
///硬中断暂停处理函数
VOID OsMpHaltHandler(VOID)
{
(VOID)LOS_IntLock();
OsPercpuGet()->excFlag = CPU_HALT;
OsPercpuGet()->excFlag = CPU_HALT;//让当前Cpu停止工作
while (1) {}
while (1) {}//陷入空循环,也就是空闲状态
}
///MP定时器处理函数, 递归检查所有可用任务
VOID OsMpCollectTasks(VOID)
{
LosTaskCB *taskCB = NULL;
@ -80,19 +109,19 @@ VOID OsMpCollectTasks(VOID)
UINT32 ret;
/* recursive checking all the available task */
for (; taskID <= g_taskMaxNum; taskID++) {
for (; taskID <= g_taskMaxNum; taskID++) { //递归检查所有可用任务
taskCB = &g_taskCBArray[taskID];
if (OsTaskIsUnused(taskCB) || OsTaskIsRunning(taskCB)) {
continue;
}
/*
/* 虽然任务状态不是原子的,但此检查可能成功,但无法完成删除,此删除将在下次运行之前处理
* though task status is not atomic, this check may success but not accomplish
* the deletion; this deletion will be handled until the next run.
*/
if (taskCB->signal & SIGNAL_KILL) {
ret = LOS_TaskDelete(taskID);
if (taskCB->signal & SIGNAL_KILL) {//任务收到被干掉信号
ret = LOS_TaskDelete(taskID);//干掉任务,回归任务池
if (ret != LOS_OK) {
PRINT_WARN("GC collect task failed err:0x%x\n", ret);
}
@ -101,6 +130,17 @@ VOID OsMpCollectTasks(VOID)
}
#ifdef LOSCFG_KERNEL_SMP_CALL
/*!
* @brief OsMpFuncCall
* CPUfuncLink, ? ?
* \n CPU ab,b, ?
* @param args
* @param func
* @param target
* @return
*
* @see
*/
VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
{
UINT32 index;
@ -110,13 +150,13 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
return;
}
if (!(target & OS_MP_CPU_ALL)) {
if (!(target & OS_MP_CPU_ALL)) {//检查目标CPU是否正确
return;
}
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {//遍历所有核
if (CPUID_TO_AFFI_MASK(index) & target) {
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));//从内核空间 分配回调结构体
if (mpCallFunc == NULL) {
PRINT_ERR("smp func call malloc failed\n");
return;
@ -125,59 +165,66 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
mpCallFunc->args = args;
MP_CALL_LOCK(intSave);
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));//将回调结构体挂入链表尾部
MP_CALL_UNLOCK(intSave);
}
}
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);//向目标CPU发起核间中断
}
/*!
* @brief OsMpFuncCallHandler
* CPU
* @return
*
* @see
*/
VOID OsMpFuncCallHandler(VOID)
{
UINT32 intSave;
UINT32 cpuid = ArchCurrCpuid();
UINT32 cpuid = ArchCurrCpuid();//获取当前CPU
LOS_DL_LIST *list = NULL;
MpCallFunc *mpCallFunc = NULL;
MP_CALL_LOCK(intSave);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);
LOS_ListDelete(list);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {//遍历回调函数链表,知道为空
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);//获取链表第一个数据
LOS_ListDelete(list);//将自己从链表上摘除
MP_CALL_UNLOCK(intSave);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);
mpCallFunc->func(mpCallFunc->args);
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);//获取回调函数
mpCallFunc->func(mpCallFunc->args);//获取参数并回调该函数
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);//释放回调函数内存
MP_CALL_LOCK(intSave);
}
MP_CALL_UNLOCK(intSave);
}
/// CPU层级的回调模块初始化
VOID OsMpFuncCallInit(VOID)
{
UINT32 index;
/* init funclink for each core */
/* init funclink for each core | 为每个CPU核整一个回调函数链表*/
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
LOS_ListInit(&g_percpu[index].funcLink);
LOS_ListInit(&g_percpu[index].funcLink);//链表初始化
}
}
#endif /* LOSCFG_KERNEL_SMP_CALL */
//MP(multiprocessing) 多核处理器初始化
UINT32 OsMpInit(VOID)
{
UINT16 swtmrId;
(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD,
(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);
(VOID)LOS_SwtmrStart(swtmrId);
(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD, //创建一个周期性,持续时间为 100个tick的定时器
(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);//OsMpCollectTasks为超时回调函数
(VOID)LOS_SwtmrStart(swtmrId);//开始定时任务
#ifdef LOSCFG_KERNEL_SMP_CALL
OsMpFuncCallInit();
#endif
return LOS_OK;
}
LOS_MODULE_INIT(OsMpInit, LOS_INIT_LEVEL_KMOD_TASK);
LOS_MODULE_INIT(OsMpInit, LOS_INIT_LEVEL_KMOD_TASK);//多处理器模块初始化
#endif

@ -33,7 +33,7 @@
#include "los_printf.h"
#ifdef LOSCFG_KERNEL_SMP
Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];
Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM]; ///< CPU池,池大小由CPU核数决定
VOID OsAllCpuStatusOutput(VOID)
{

Loading…
Cancel
Save