/********************************************************************************************************* ** 函数名称: _SchedTick ** 功能描述: 时间片处理 (tick 中断服务程序中被调用, 进入内核且关闭中断状态) ** 输 入 : NONE ** 输 出 : NONE ** 全局变量: ** 调用模块: *********************************************************************************************************/ VOID _SchedTick (VOID) { REGISTER PLW_CLASS_CPU pcpu; REGISTER PLW_CLASS_TCB ptcb; UINT8 ucPriority; INT i; #if LW_CFG_SMP_EN > 0 for (i = 0; i < LW_NCPUS; i++) { #else i = 0; #endif /* LW_CFG_SMP_EN */ pcpu = LW_CPU_GET(i); if (LW_CPU_IS_ACTIVE(pcpu)) { /* CPU 必须激活 */ ptcb = pcpu->CPU_ptcbTCBCur; if (ptcb->TCB_ucSchedPolicy == LW_OPTION_SCHED_RR) { /* round-robin 线程 */ if (ptcb->TCB_usSchedCounter == 0) { /* 时间片已经耗尽 */ if (LW_CAND_ROT(pcpu) == LW_FALSE) { if (_SchedSeekPriority(pcpu, &ucPriority) && /* 就绪未运行任务的最高优先级 */ LW_PRIO_IS_HIGH_OR_EQU(ucPriority, ptcb->TCB_ucPriority)) { LW_CAND_ROT(pcpu) = LW_TRUE; /* 下次调度时检查轮转 */ } } } else { ptcb->TCB_usSchedCounter--; } } } #if LW_CFG_SMP_EN > 0 } #endif /* LW_CFG_SMP_EN */ }
LW_API ULONG API_CpuDown (ULONG ulCPUId) { INTREG iregInterLevel; PLW_CLASS_CPU pcpu; if ((ulCPUId == 0) || (ulCPUId >= LW_NCPUS)) { _ErrorHandle(EINVAL); return (EINVAL); } __KERNEL_ENTER(); pcpu = LW_CPU_GET(ulCPUId); if (!LW_CPU_IS_ACTIVE(pcpu) || (LW_CPU_GET_IPI_PEND2(pcpu) & LW_IPI_DOWN_MSK)) { __KERNEL_EXIT(); return (ERROR_NONE); } LW_SPIN_LOCK_QUICK(&pcpu->CPU_slIpi, &iregInterLevel); LW_CPU_ADD_IPI_PEND2(pcpu, LW_IPI_DOWN_MSK); LW_SPIN_UNLOCK_QUICK(&pcpu->CPU_slIpi, iregInterLevel); _ThreadOffAffinity(pcpu); /* 关闭与此 CPU 有关的亲和度 */ __KERNEL_EXIT(); _SmpSendIpi(ulCPUId, LW_IPI_DOWN, 0, LW_FALSE); /* 使用核间中断通知 CPU 停止 */ return (ERROR_NONE); }
/********************************************************************************************************* ** 函数名称: _ReadyTableDel ** 功能描述: 指定线程退出就绪表 ** 输 入 : ptcb 线程控制块 ** 输 出 : NONE ** 全局变量: ** 调用模块: *********************************************************************************************************/ VOID _ReadyTableDel (PLW_CLASS_TCB ptcb) { PLW_CLASS_PCBBMAP ppcbbmap; #if LW_CFG_SMP_EN > 0 if (ptcb->TCB_bCPULock) { ppcbbmap = LW_CPU_RDY_PCBBMAP(LW_CPU_GET(ptcb->TCB_ulCPULock)); } else #endif /* LW_CFG_SMP_EN > 0 */ { ppcbbmap = LW_GLOBAL_RDY_PCBBMAP(); } _BitmapDel(&ppcbbmap->PCBM_bmap, ptcb->TCB_ucPriority); }
VOID _SchedYield (PLW_CLASS_TCB ptcb, PLW_CLASS_PCB ppcb) { UINT8 ucPriority; REGISTER PLW_CLASS_CPU pcpu; if (__LW_THREAD_IS_RUNNING(ptcb)) { /* 必须正在执行 */ pcpu = LW_CPU_GET_CUR(); if (_SchedSeekPriority(pcpu, &ucPriority) && /* 就绪未运行任务的最高优先级 */ LW_PRIO_IS_HIGH_OR_EQU(ucPriority, ptcb->TCB_ucPriority)) { ptcb->TCB_usSchedCounter = 0; /* 没收剩余时间片 */ LW_CAND_ROT(LW_CPU_GET(ptcb->TCB_ulCPUId)) = LW_TRUE; /* 下次调度时检查轮转 */ } } }
/********************************************************************************************************* ** 函数名称: API_KernelTicksContext ** 功能描述: 处理系统时钟中断. (此函数必须在中断中被调用) ** 输 入 : ** 输 出 : ** 全局变量: ** 调用模块: ** 注 意 : vprocTickHook() 可能会激活新的任务, 会在中断退出时会尝试调度. 所以这里允许在 QUICK 操作中打开中断. API 函数 *********************************************************************************************************/ LW_API VOID API_KernelTicksContext (VOID) { INTREG iregInterLevel; REGISTER INT i; PLW_CLASS_CPU pcpu; PLW_CLASS_TCB ptcb; LW_SPIN_KERN_LOCK_QUICK(&iregInterLevel); /* 锁定内核并关闭中断 */ #if LW_CFG_RTC_EN > 0 __kernelTODUpdate(); /* 更新 TOD 时间 */ #endif /* LW_CFG_RTC_EN > 0 */ __kernelTickUpdate(); /* 更新 TICK 时间 */ KN_INT_ENABLE(iregInterLevel); /* 允许其他中断进入 */ #if LW_CFG_SMP_EN > 0 for (i = 0; i < LW_NCPUS; i++) { /* 遍历所有的核 */ #else i = 0; #endif /* LW_CFG_SMP_EN */ pcpu = LW_CPU_GET(i); if (LW_CPU_IS_ACTIVE(pcpu)) { /* CPU 必须被激活 */ ptcb = pcpu->CPU_ptcbTCBCur; ptcb->TCB_ulCPUTicks++; if (pcpu->CPU_iKernelCounter) { ptcb->TCB_ulCPUKernelTicks++; } __LW_TICK_CPUUSAGE_UPDATE(ptcb, pcpu); /* 更新所有 CPU 利用率 */ #if LW_CFG_MODULELOADER_EN > 0 vprocTickHook(ptcb, pcpu); /* 测算进程执行时间 */ #endif } #if LW_CFG_SMP_EN > 0 } #endif /* LW_CFG_SMP_EN */ iregInterLevel = KN_INT_DISABLE(); /* 关闭中断 */ _SchedTick(); /* 处理所有 CPU 线程的时间片 */ LW_SPIN_KERN_UNLOCK_QUICK(iregInterLevel); /* 退出内核并打开中断 */ }
/********************************************************************************************************* ** 函数名称: _PriorityInit ** 功能描述: 初始化优先级控制块. ** 输 入 : NONE ** 输 出 : NONE ** 全局变量: ** 调用模块: *********************************************************************************************************/ VOID _PriorityInit (VOID) { REGISTER ULONG i; #if LW_CFG_SMP_EN > 0 REGISTER ULONG j; for (i = 0; i < LW_CFG_MAX_PROCESSORS; i++) { for (j = 0; j < (LW_PRIO_LOWEST + 1); j++) { LW_CPU_RDY_PPCB(LW_CPU_GET(i), j)->PCB_ucPriority = (UINT8)j; } } #endif /* LW_CFG_SMP_EN > 0 */ for (i = 0; i < (LW_PRIO_LOWEST + 1); i++) { LW_GLOBAL_RDY_PPCB(i)->PCB_ucPriority = (UINT8)i; } }
/********************************************************************************************************* ** 函数名称: API_CpuIsUp ** 功能描述: 指定 CPU 是否启动. ** 输 入 : ulCPUId CPU ID ** 输 出 : ERROR ** 全局变量: ** 调用模块: API 函数 *********************************************************************************************************/ LW_API BOOL API_CpuIsUp (ULONG ulCPUId) { PLW_CLASS_CPU pcpu; if (ulCPUId >= LW_NCPUS) { _ErrorHandle(EINVAL); return (LW_FALSE); } KN_SMP_MB(); pcpu = LW_CPU_GET(ulCPUId); if (LW_CPU_IS_ACTIVE(pcpu)) { return (LW_TRUE); } else { return (LW_FALSE); } }
/********************************************************************************************************* ** 函数名称: _SmpSendIpi ** 功能描述: 发送一个除自定义以外的核间中断给指定的 CPU 关中断情况下被调用, 如果需要等待, 则必须保证其他 CPU 已经运行. ** 输 入 : ulCPUId CPU ID ** ulIPIVec 核间中断类型 (除自定义类型中断以外) ** iWait 是否等待处理结束 (LW_IPI_SCHED 绝不允许等待, 否则会死锁) ** 输 出 : NONE ** 全局变量: ** 调用模块: *********************************************************************************************************/ VOID _SmpSendIpi (ULONG ulCPUId, ULONG ulIPIVec, INT iWait) { PLW_CLASS_CPU pcpuDst = LW_CPU_GET(ulCPUId); ULONG ulMask = (ULONG)(1 << ulIPIVec); if (!LW_CPU_IS_ACTIVE(pcpuDst)) { /* CPU 必须被激活 */ return; } LW_SPIN_LOCK_IGNIRQ(&pcpuDst->CPU_slIpi); /* 锁定目标 CPU */ LW_CPU_ADD_IPI_PEND(ulCPUId, ulMask); /* 添加 PEND 位 */ LW_SPIN_UNLOCK_IGNIRQ(&pcpuDst->CPU_slIpi); /* 解锁目标 CPU */ archMpInt(ulCPUId); if (iWait && (ulIPIVec != LW_IPI_SCHED)) { while (LW_CPU_GET_IPI_PEND(ulCPUId) & ulMask) { /* 等待结束 */ LW_SPINLOCK_DELAY(); } } }
/********************************************************************************************************* ** 函数名称: _SmpCallIpi ** 功能描述: 发送一个自定义核间中断给指定的 CPU 关中断情况下被调用, 如果需要等待, 则必须保证其他 CPU 已经运行. ** 输 入 : ulCPUId CPU ID ** pipim 核间中断参数 ** 输 出 : 调用返回值 ** 全局变量: ** 调用模块: *********************************************************************************************************/ static INT _SmpCallIpi (ULONG ulCPUId, PLW_IPI_MSG pipim) { PLW_CLASS_CPU pcpuDst = LW_CPU_GET(ulCPUId); if (!LW_CPU_IS_ACTIVE(pcpuDst)) { /* CPU 必须被激活 */ return (ERROR_NONE); } LW_SPIN_LOCK_IGNIRQ(&pcpuDst->CPU_slIpi); /* 锁定目标 CPU */ _List_Ring_Add_Last(&pipim->IPIM_ringManage, &pcpuDst->CPU_pringMsg); pcpuDst->CPU_uiMsgCnt++; LW_CPU_ADD_IPI_PEND(ulCPUId, LW_IPI_CALL_MSK); LW_SPIN_UNLOCK_IGNIRQ(&pcpuDst->CPU_slIpi); /* 解锁目标 CPU */ archMpInt(ulCPUId); while (pipim->IPIM_iWait) { /* 等待结束 */ LW_SPINLOCK_DELAY(); } return (pipim->IPIM_iRet); }
/********************************************************************************************************* ** 函数名称: API_CpuUp ** 功能描述: 开启一个 CPU. (非 0 号 CPU) ** 输 入 : ulCPUId CPU ID ** 输 出 : ERROR ** 全局变量: ** 调用模块: API 函数 *********************************************************************************************************/ LW_API ULONG API_CpuUp (ULONG ulCPUId) { INTREG iregInterLevel; PLW_CLASS_CPU pcpu; if ((ulCPUId == 0) || (ulCPUId >= LW_NCPUS)) { _ErrorHandle(EINVAL); return (EINVAL); } KN_SMP_MB(); pcpu = LW_CPU_GET(ulCPUId); if (LW_CPU_IS_ACTIVE(pcpu) || (LW_CPU_GET_IPI_PEND2(pcpu) & LW_IPI_DOWN_MSK)) { return (ERROR_NONE); } iregInterLevel = KN_INT_DISABLE(); bspCpuUp(ulCPUId); KN_INT_ENABLE(iregInterLevel); return (ERROR_NONE); }
/********************************************************************************************************* ** 函数名称: _ThreadStatusChange ** 功能描述: 改变线程状态 (进入内核状态被调用) ** 输 入 : ptcb 线程控制块 ** uiStatusReq 状态 (LW_TCB_REQ_SUSPEND / LW_TCB_REQ_WDEATH / LW_TCB_REQ_STOP) ** 输 出 : ERROR ** 全局变量: ** 调用模块: ** 注 意 : 此函数已经预置的阻塞点, 最后一次退出内核时, 将阻塞等待目标线程状态改变完毕. *********************************************************************************************************/ ULONG _ThreadStatusChange (PLW_CLASS_TCB ptcb, UINT uiStatusReq) { INTREG iregInterLevel; PLW_CLASS_PCB ppcb; PLW_CLASS_TCB ptcbCur; iregInterLevel = KN_INT_DISABLE(); /* 关闭中断 */ LW_TCB_GET_CUR(ptcbCur); #if LW_CFG_SMP_EN > 0 if (ptcb == ptcbCur) { /* 改变自己的状态 */ goto __change1; } else if (!__LW_THREAD_IS_READY(ptcb)) { /* 任务没有就绪 */ goto __change2; } else { /* 目标任务处于就绪状态 */ if (LW_CPU_GET_CUR_NESTING()) { KN_INT_ENABLE(iregInterLevel); /* 打开中断 */ return (ERROR_KERNEL_IN_ISR); /* 中断状态下无法完成此工作 */ } if (!__LW_THREAD_IS_RUNNING(ptcb)) { /* 目标任务不是正在执行 */ ppcb = _GetPcb(ptcb); __DEL_FROM_READY_RING(ptcb, ppcb); /* 从就绪表中删除 */ goto __change2; } else { /* 目标任务正在执行 */ _SmpUpdateIpi(LW_CPU_GET(ptcb->TCB_ulCPUId)); /* 发送核间中断通知改变状态 */ _ThreadWaitStatus(ptcbCur, ptcb, uiStatusReq); /* 设置等待对方完成状态 */ } KN_INT_ENABLE(iregInterLevel); /* 打开中断 */ return (ERROR_NONE); /* 退出内核时开始等待 */ } __change1: #endif /* LW_CFG_SMP_EN */ if (__LW_THREAD_IS_READY(ptcb)) { ppcb = _GetPcb(ptcb); __DEL_FROM_READY_RING(ptcb, ppcb); /* 从就绪表中删除 */ } #if LW_CFG_SMP_EN > 0 __change2: #endif /* LW_CFG_SMP_EN */ ptcbCur->TCB_uiStatusChangeReq = 0; /* 状态修改操作执行成功 */ switch (uiStatusReq) { case LW_TCB_REQ_SUSPEND: ptcb->TCB_ulSuspendNesting++; ptcb->TCB_usStatus |= LW_THREAD_STATUS_SUSPEND; break; case LW_TCB_REQ_STOP: ptcb->TCB_ulStopNesting++; ptcb->TCB_usStatus |= LW_THREAD_STATUS_STOP; break; case LW_TCB_REQ_WDEATH: ptcb->TCB_usStatus |= LW_THREAD_STATUS_WDEATH; break; } KN_INT_ENABLE(iregInterLevel); return (ERROR_NONE); }