You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1216 lines
55 KiB

1 year ago
/*
* 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_sched_pri.h"
#include "los_hw_pri.h"
#include "los_task_pri.h"
#include "los_process_pri.h"
#include "los_arch_mmu.h"
#include "los_hook.h"
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#include "los_hw_tick_pri.h"
#include "los_tick_pri.h"
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
#include "los_stackinfo_pri.h"
#endif
#include "los_mp.h"
#ifdef LOSCFG_SCHED_DEBUG
#include "los_stat_pri.h"
#endif
1 year ago
#define OS_32BIT_MAX 0xFFFFFFFFUL //定义32位操作系统的最大值
#define OS_SCHED_FIFO_TIMEOUT 0x7FFFFFFF //定义FIFO调度器的超时值
#define OS_PRIORITY_QUEUE_NUM 32 //定义优先级队列的数量
#define PRIQUEUE_PRIOR0_BIT 0x80000000U //定义优先级队列中优先级0的最高位
#define OS_SCHED_TIME_SLICES_MIN ((5000 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 定义调度器的最小时间片以纳秒为单位5ms */
#define OS_SCHED_TIME_SLICES_MAX ((LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) //定义调度器的最大时间片(以纳秒为单位)
#define OS_SCHED_TIME_SLICES_DIFF (OS_SCHED_TIME_SLICES_MAX - OS_SCHED_TIME_SLICES_MIN) //定义调度器最大时间片和最小时间片之间的差值
#define OS_SCHED_READY_MAX 30 //定义调度器的最大就绪任务数
#define OS_TIME_SLICE_MIN (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /*定义最小时间片以INT32类型表示单位为50微秒 50us */
//定义调度器队列结构体SchedQueue
1 year ago
typedef struct {
1 year ago
LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM]; // 优先级队列列表
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM]; // 就绪任务数
UINT32 queueBitmap; // 队列位图
1 year ago
} SchedQueue;
1 year ago
//定义调度器结构体Sched
1 year ago
typedef struct {
1 year ago
SchedQueue queueList[OS_PRIORITY_QUEUE_NUM]; // 优先级队列列表
UINT32 queueBitmap; // 队列位图
SchedScan taskScan; // 任务扫描
SchedScan swtmrScan; // 软件定时器扫描
1 year ago
} Sched;
1 year ago
STATIC Sched *g_sched = NULL; //定义全局调度器变量g_sched
STATIC UINT64 g_schedTickMaxResponseTime; //定义调度器tick的最大响应时间
UINT64 g_sysSchedStartTime = OS_64BIT_MAX; //定义系统调度器的起始时间
1 year ago
#ifdef LOSCFG_SCHED_TICK_DEBUG
1 year ago
#define OS_SCHED_DEBUG_DATA_NUM 1000 //定义调度器tick调试数据数量的常量
//定义调度器tick调试数据结构体SchedTickDebug
1 year ago
typedef struct {
1 year ago
UINT32 tickResporeTime[OS_SCHED_DEBUG_DATA_NUM]; // tick响应时间数组
UINT32 index; // 当前数据索引
UINT32 setTickCount; // 设置的tick计数
UINT64 oldResporeTime; // 上一次的响应时间
1 year ago
} SchedTickDebug;
1 year ago
STATIC SchedTickDebug *g_schedTickDebug = NULL; //定义全局调度器tick调试数据变量g_schedTickDebug
1 year ago
1 year ago
//初始化调度器tick调试数据
1 year ago
STATIC UINT32 OsSchedDebugInit(VOID)
{
UINT32 size = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
g_schedTickDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem0, size);
if (g_schedTickDebug == NULL) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
(VOID)memset_s(g_schedTickDebug, size, 0, size);
return LOS_OK;
}
1 year ago
//记录调度器tick调试数据
1 year ago
VOID OsSchedDebugRecordData(VOID)
{
SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
UINT64 currTime = OsGetCurrSchedTimeCycle();
schedDebug->tickResporeTime[schedDebug->index] = currTime - schedDebug->oldResporeTime;
schedDebug->oldResporeTime = currTime;
schedDebug->index++;
}
}
1 year ago
//获取调度器tick调试数据
1 year ago
SchedTickDebug *OsSchedDebugGet(VOID)
{
return g_schedTickDebug;
}
1 year ago
// 显示调度器 tick 响应时间的 Shell 命令函数
1 year ago
UINT32 OsShellShowTickRespo(VOID)
{
1 year ago
UINT32 intSave; // 保存中断状态的变量
UINT16 cpu; // CPU 编号
UINT64 allTime; // 所有时间的总和
1 year ago
1 year ago
// 计算存储调度器调试信息的内存大小
1 year ago
UINT32 tickSize = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
1 year ago
// 在系统内存池中分配存储调度器调试信息的内存
1 year ago
SchedTickDebug *schedDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem1, tickSize);
if (schedDebug == NULL) {
return LOS_NOK;
}
1 year ago
// 创建一个数组来保存每个 CPU 上的任务和软件定时器的排序链表节点数
1 year ago
UINT32 sortLinkNum[LOSCFG_KERNEL_CORE_NUM];
1 year ago
// 禁止调度器调度
1 year ago
SCHEDULER_LOCK(intSave);
1 year ago
// 将调度器调试信息拷贝到 schedDebug 中
1 year ago
(VOID)memcpy_s((CHAR *)schedDebug, tickSize, (CHAR *)OsSchedDebugGet(), tickSize);
1 year ago
// 将调度器调试信息清零
1 year ago
(VOID)memset_s((CHAR *)OsSchedDebugGet(), tickSize, 0, tickSize);
1 year ago
// 计算每个 CPU 上的任务和软件定时器的排序链表节点数
1 year ago
for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
sortLinkNum[cpu] = OsPercpuGetByID(cpu)->taskSortLink.nodeNum + OsPercpuGetByID(cpu)->swtmrSortLink.nodeNum;
}
1 year ago
// 允许调度器调度
1 year ago
SCHEDULER_UNLOCK(intSave);
1 year ago
// 遍历每个 CPU 上的调度器调试信息
1 year ago
for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
1 year ago
SchedTickDebug *schedData = &schedDebug[cpu]; // 获取当前 CPU 的调度器调试信息
// 打印当前 CPU 的调度器调试信息
1 year ago
PRINTK("cpu : %u sched data num : %u set time count : %u SortMax : %u\n",
cpu, schedData->index, schedData->setTickCount, sortLinkNum[cpu]);
1 year ago
UINT32 *data = schedData->tickResporeTime; // 获取当前 CPU 的 tick 响应时间数据
allTime = 0; // 重置总时间
// 遍历 tick 响应时间数据
1 year ago
for (UINT32 i = 1; i < schedData->index; i++) {
1 year ago
allTime += data[i]; // 计算总时间
UINT32 timeUs = (data[i] * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将时间转换为微秒
PRINTK(" %u(%u)", timeUs, timeUs / OS_US_PER_TICK); // 打印时间
if ((i != 0) && ((i % 5) == 0)) { /* A row of 5 data每行显示5个数据 */
PRINTK("\n"); // 换行
1 year ago
}
}
1 year ago
allTime = (allTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将总时间转换为微秒
PRINTK("\nTick Indicates the average response period: %llu(us)\n", allTime / (schedData->index - 1)); //平均响应周期
1 year ago
}
1 year ago
// 释放内存
1 year ago
(VOID)LOS_MemFree(m_aucSysMem1, schedDebug);
1 year ago
1 year ago
return LOS_OK;
}
#else
1 year ago
//显示调度器tick响应时间的Shell命令函数
1 year ago
UINT32 OsShellShowTickRespo(VOID)
{
return LOS_NOK;
}
#endif
1 year ago
//定义调度器调试开关
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
// 显示调度器调度参数的 Shell 命令函数
1 year ago
UINT32 OsShellShowSchedParam(VOID)
{
1 year ago
UINT64 averRunTime; // 平均运行时间
UINT64 averTimeSlice; // 平均时间片
UINT64 averSchedWait; // 平均等待调度时间
UINT64 averPendTime; // 平均挂起时间
UINT32 intSave; // 保存中断状态的变量
UINT32 size = g_taskMaxNum * sizeof(LosTaskCB); // 计算任务控制块数组的大小
LosTaskCB *taskCBArray = LOS_MemAlloc(m_aucSysMem1, size); // 在系统内存池中分配任务控制块数组的内存
1 year ago
if (taskCBArray == NULL) {
return LOS_NOK;
}
1 year ago
SCHEDULER_LOCK(intSave); // 禁止调度器调度
// 将全局的任务控制块数组拷贝到局部数组中
1 year ago
(VOID)memcpy_s(taskCBArray, size, g_taskCBArray, size);
1 year ago
SCHEDULER_UNLOCK(intSave); // 允许调度器调度
// 打印表头
1 year ago
PRINTK(" Tid AverRunTime(us) SwitchCount AverTimeSlice(us) TimeSliceCount AverReadyWait(us) "
"AverPendTime(us) TaskName \n");
1 year ago
// 遍历任务控制块数组
1 year ago
for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
1 year ago
LosTaskCB *taskCB = taskCBArray + tid; // 获取当前任务控制块
// 如果任务控制块未使用,则跳过
1 year ago
if (OsTaskIsUnused(taskCB)) {
continue;
}
1 year ago
averRunTime = 0; // 平均运行时间初始化为0
averTimeSlice = 0; // 平均时间片初始化为0
averPendTime = 0; // 平均挂起时间初始化为0
averSchedWait = 0; // 平均等待调度时间初始化为0
1 year ago
1 year ago
// 计算平均运行时间
1 year ago
if (taskCB->schedStat.switchCount >= 1) {
1 year ago
averRunTime = taskCB->schedStat.runTime / taskCB->schedStat.switchCount; // 平均运行时间 = 运行时间 / 切换次数
averRunTime = (averRunTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将平均运行时间转换为微秒
1 year ago
}
1 year ago
// 计算平均时间片
1 year ago
if (taskCB->schedStat.timeSliceCount > 1) {
1 year ago
averTimeSlice = taskCB->schedStat.timeSliceTime / (taskCB->schedStat.timeSliceCount - 1); // 平均时间片 = 时间片总数 / (时间片个数 - 1)
averTimeSlice = (averTimeSlice * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将平均时间片转换为微秒
1 year ago
}
1 year ago
// 计算平均挂起时间
1 year ago
if (taskCB->schedStat.pendCount > 1) {
1 year ago
averPendTime = taskCB->schedStat.pendTime / taskCB->schedStat.pendCount; // 平均挂起时间 = 挂起时间 / 挂起次数
averPendTime = (averPendTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将平均挂起时间转换为微秒
1 year ago
}
1 year ago
// 计算平均等待调度时间
1 year ago
if (taskCB->schedStat.waitSchedCount > 0) {
1 year ago
averSchedWait = taskCB->schedStat.waitSchedTime / taskCB->schedStat.waitSchedCount; // 平均等待调度时间 = 等待调度时间 / 等待调度次数
averSchedWait = (averSchedWait * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US; // 将平均等待调度时间转换为微秒
1 year ago
}
1 year ago
// 打印任务的调度参数信息
1 year ago
PRINTK("%5u%19llu%15llu%19llu%18llu%19llu%18llu %-32s\n", taskCB->taskID,
averRunTime, taskCB->schedStat.switchCount,
averTimeSlice, taskCB->schedStat.timeSliceCount - 1,
averSchedWait, averPendTime, taskCB->taskName);
}
1 year ago
(VOID)LOS_MemFree(m_aucSysMem1, taskCBArray); // 释放内存
1 year ago
return LOS_OK;
}
#else
1 year ago
1 year ago
UINT32 OsShellShowSchedParam(VOID)
{
1 year ago
return LOS_NOK; // 返回错误码,表示未实现该函数
1 year ago
}
#endif
1 year ago
// 设置调度器的 tick 定时器类型
1 year ago
UINT32 OsSchedSetTickTimerType(UINT32 timerType)
{
switch (timerType) {
1 year ago
case 32: /* 32 位定时器 */
g_schedTickMaxResponseTime = OS_32BIT_MAX; // 设置最大的 tick 响应时间为 32 位定时器的最大值
1 year ago
break;
1 year ago
case 64: /* 64 位定时器 */
g_schedTickMaxResponseTime = OS_64BIT_MAX; // 设置最大的 tick 响应时间为 64 位定时器的最大值
1 year ago
break;
default:
PRINT_ERR("Unsupported Tick Timer type, The system only supports 32 and 64 bit tick timers\n");
1 year ago
return LOS_NOK; // 返回错误码,表示不支持该类型的定时器
1 year ago
}
1 year ago
return LOS_OK; // 返回成功码
1 year ago
}
1 year ago
// 设置调度器的启动时间
1 year ago
STATIC VOID OsSchedSetStartTime(UINT64 currCycle)
{
if (g_sysSchedStartTime == OS_64BIT_MAX) {
1 year ago
g_sysSchedStartTime = currCycle; // 如果系统的调度启动时间未设置,则设置为当前的时钟周期数
1 year ago
}
}
1 year ago
// 更新时间片
1 year ago
STATIC INLINE VOID OsTimeSliceUpdate(LosTaskCB *taskCB, UINT64 currTime)
{
1 year ago
LOS_ASSERT(currTime >= taskCB->startTime); // 断言当前时间大于等于任务的启动时间
1 year ago
1 year ago
INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime); // 计算增加的时间
1 year ago
1 year ago
LOS_ASSERT(incTime >= 0); // 断言增加的时间大于等于0
1 year ago
if (taskCB->policy == LOS_SCHED_RR) {
1 year ago
taskCB->timeSlice -= incTime; // 更新时间片剩余时间
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
taskCB->schedStat.timeSliceRealTime += incTime; // 更新调度统计信息中的实际时间片使用时间
1 year ago
#endif
}
1 year ago
taskCB->irqUsedTime = 0; // 清零中断使用的时间
taskCB->startTime = currTime; // 更新任务的启动时间
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
taskCB->schedStat.allRuntime += incTime; // 更新调度统计信息中的总运行时间
1 year ago
#endif
}
1 year ago
// 重新加载 tick 定时器
1 year ago
STATIC INLINE VOID OsSchedTickReload(Percpu *currCpu, UINT64 nextResponseTime, UINT32 responseID, BOOL isTimeSlice)
{
UINT64 currTime, nextExpireTime;
UINT32 usedTime;
1 year ago
currTime = OsGetCurrSchedTimeCycle(); // 获取当前的调度时间
1 year ago
if (currCpu->tickStartTime != 0) {
1 year ago
usedTime = currTime - currCpu->tickStartTime; // 计算 tick 定时器已经使用的时间
currCpu->tickStartTime = 0; // 清零 tick 定时器的启动时间
1 year ago
} else {
usedTime = 0;
}
if ((nextResponseTime > usedTime) && ((nextResponseTime - usedTime) > OS_TICK_RESPONSE_PRECISION)) {
1 year ago
nextResponseTime -= usedTime; // 减去已经使用的时间,得到下一次 tick 定时器的响应时间
1 year ago
} else {
1 year ago
nextResponseTime = OS_TICK_RESPONSE_PRECISION; // 如果计算出的响应时间小于精度要求,设置为精度要求
1 year ago
}
1 year ago
nextExpireTime = currTime + nextResponseTime; // 计算下一次 tick 定时器的到期时间
1 year ago
if (nextExpireTime >= currCpu->responseTime) {
1 year ago
return; // 如果下一次到期时间大于等于当前的响应时间,直接返回
1 year ago
}
if (isTimeSlice) {
1 year ago
/* 当前系统的到期时间是线程的时间片到期时间 */
currCpu->responseID = responseID; // 设置当前 CPU 的响应 ID
1 year ago
} else {
1 year ago
currCpu->responseID = OS_INVALID_VALUE; // 设置当前 CPU 的响应 ID 为无效值
1 year ago
}
1 year ago
currCpu->responseTime = nextExpireTime; // 更新当前 CPU 的响应时间
HalClockTickTimerReload(nextResponseTime); // 重新加载 tick 定时器
1 year ago
#ifdef LOSCFG_SCHED_TICK_DEBUG
SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
1 year ago
schedDebug->setTickCount++; // 更新调度 tick 调试信息中的设置 tick 数量
1 year ago
}
#endif
}
1 year ago
1 year ago
STATIC INLINE VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID,
UINT64 taskEndTime, UINT32 oldResponseID)
{
1 year ago
UINT64 nextExpireTime = OsGetNextExpireTime(startTime); // 获取下一次到期时间
Percpu *currCpu = OsPercpuGet(); // 获取当前 CPU 的数据结构指针
1 year ago
UINT64 nextResponseTime;
BOOL isTimeSlice = FALSE;
1 year ago
currCpu->schedFlag &= ~INT_PEND_TICK; // 清除调度标志位中的中断挂起标志
1 year ago
if (currCpu->responseID == oldResponseID) {
1 year ago
/* 此次已经到期,下一次理论上到期的时间为无穷大 */
1 year ago
currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
}
1 year ago
/* 当前线程的时间片已经消耗完,但当前系统锁定任务无法触发调度以释放 CPU */
1 year ago
if ((nextExpireTime > taskEndTime) && ((nextExpireTime - taskEndTime) > OS_SCHED_MINI_PERIOD)) {
nextExpireTime = taskEndTime;
1 year ago
isTimeSlice = TRUE; // 设置时间片到期标志
1 year ago
}
if ((currCpu->responseTime > nextExpireTime) &&
((currCpu->responseTime - nextExpireTime) >= OS_TICK_RESPONSE_PRECISION)) {
1 year ago
nextResponseTime = nextExpireTime - startTime; // 计算下一次响应时间
1 year ago
if (nextResponseTime > g_schedTickMaxResponseTime) {
1 year ago
nextResponseTime = g_schedTickMaxResponseTime; // 如果下一次响应时间超过最大响应时间,设置为最大响应时间
1 year ago
}
} else {
1 year ago
/* 没有比当前到期时间更早的点 */
currCpu->tickStartTime = 0; // 清零 tick 定时器的启动时间
1 year ago
return;
}
1 year ago
OsSchedTickReload(currCpu, nextResponseTime, responseID, isTimeSlice); // 重新加载 tick 定时器
1 year ago
}
VOID OsSchedUpdateExpireTime(UINT64 startTime)
{
UINT64 endTime;
1 year ago
Percpu *cpu = OsPercpuGet(); // 获取当前 CPU 的数据结构指针
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务的控制块指针
1 year ago
if (!OS_SCHEDULER_ACTIVE || OS_INT_ACTIVE) {
1 year ago
cpu->schedFlag |= INT_PEND_TICK; // 如果调度器不活跃或者中断活跃,设置调度标志位中的中断挂起标志
1 year ago
return;
}
if (runTask->policy == LOS_SCHED_RR) {
LOS_SpinLock(&g_taskSpin);
INT32 timeSlice = (runTask->timeSlice <= OS_TIME_SLICE_MIN) ? runTask->initTimeSlice : runTask->timeSlice;
LOS_SpinUnlock(&g_taskSpin);
1 year ago
endTime = startTime + timeSlice; // 计算任务的结束时间
1 year ago
} else {
1 year ago
endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION; // 如果不是轮转调度策略,设置结束时间为最大响应时间减去精度要求
1 year ago
}
1 year ago
OsSchedSetNextExpireTime(startTime, runTask->taskID, endTime, runTask->taskID); // 设置下一次到期时间
1 year ago
}
STATIC INLINE UINT32 OsSchedCalculateTimeSlice(UINT16 proPriority, UINT16 priority)
{
UINT32 ratTime, readTasks;
1 year ago
SchedQueue *queueList = &g_sched->queueList[proPriority]; // 获取指定优先级的调度队列
readTasks = queueList->readyTasks[priority]; // 获取指定优先级的就绪任务数量
1 year ago
if (readTasks > OS_SCHED_READY_MAX) {
1 year ago
return OS_SCHED_TIME_SLICES_MIN; // 如果就绪任务数量超过最大限制,返回最小时间片
1 year ago
}
1 year ago
ratTime = ((OS_SCHED_READY_MAX - readTasks) * OS_SCHED_TIME_SLICES_DIFF) / OS_SCHED_READY_MAX; // 计算时间片
return (ratTime + OS_SCHED_TIME_SLICES_MIN); // 返回计算出的时间片
1 year ago
}
STATIC INLINE VOID OsSchedPriQueueEnHead(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
1 year ago
SchedQueue *queueList = &g_sched->queueList[proPriority]; // 获取指定优先级的调度队列
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0]; // 获取指定优先级的优先级队列
UINT32 *bitMap = &queueList->queueBitmap; // 获取位图
1 year ago
/*
1 year ago
*
*
1 year ago
*/
1 year ago
LOS_ASSERT(priqueueItem->pstNext == NULL); // 断言优先级队列项的下一个节点为空
1 year ago
if (*bitMap == 0) {
1 year ago
g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority; // 如果位图为零,设置全局位图中对应的位
1 year ago
}
if (LOS_ListEmpty(&priQueueList[priority])) {
1 year ago
*bitMap |= PRIQUEUE_PRIOR0_BIT >> priority; // 如果指定优先级的优先级队列为空,设置位图中对应的位
1 year ago
}
1 year ago
LOS_ListHeadInsert(&priQueueList[priority], priqueueItem); // 将优先级队列项插入到指定优先级的队列头部
queueList->readyTasks[priority]++; // 增加指定优先级的就绪任务数量
1 year ago
}
STATIC INLINE VOID OsSchedPriQueueEnTail(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
1 year ago
SchedQueue *queueList = &g_sched->queueList[proPriority]; // 获取指定优先级的调度队列
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0]; // 获取指定优先级的优先级队列
UINT32 *bitMap = &queueList->queueBitmap; // 获取位图
1 year ago
/*
1 year ago
*
*
1 year ago
*/
1 year ago
LOS_ASSERT(priqueueItem->pstNext == NULL); // 断言优先级队列项的下一个节点为空
1 year ago
if (*bitMap == 0) {
1 year ago
g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority; // 如果位图为零,设置全局位图中对应的位
1 year ago
}
if (LOS_ListEmpty(&priQueueList[priority])) {
1 year ago
*bitMap |= PRIQUEUE_PRIOR0_BIT >> priority; // 如果指定优先级的优先级队列为空,设置位图中对应的位
1 year ago
}
1 year ago
LOS_ListTailInsert(&priQueueList[priority], priqueueItem); // 将优先级队列项插入到指定优先级的队列尾部
queueList->readyTasks[priority]++; // 增加指定优先级的就绪任务数量
1 year ago
}
STATIC INLINE VOID OsSchedPriQueueDelete(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
1 year ago
SchedQueue *queueList = &g_sched->queueList[proPriority]; // 获取指定优先级的调度队列
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0]; // 获取指定优先级的优先级队列
UINT32 *bitMap = &queueList->queueBitmap; // 获取位图
1 year ago
1 year ago
LOS_ListDelete(priqueueItem); // 从优先级队列中删除优先级队列项
queueList->readyTasks[priority]--; // 减少指定优先级的就绪任务数量
1 year ago
if (LOS_ListEmpty(&priQueueList[priority])) {
1 year ago
*bitMap &= ~(PRIQUEUE_PRIOR0_BIT >> priority); // 如果指定优先级的优先级队列为空,清除位图中对应的位
1 year ago
}
if (*bitMap == 0) {
1 year ago
g_sched->queueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> proPriority); // 如果位图为零,清除全局位图中对应的位
1 year ago
}
}
STATIC INLINE VOID OsSchedWakePendTimeTask(UINT64 currTime, LosTaskCB *taskCB, BOOL *needSchedule)
{
#ifndef LOSCFG_SCHED_DEBUG
(VOID)currTime;
#endif
1 year ago
LOS_SpinLock(&g_taskSpin); // 获取全局任务自旋锁
UINT16 tempStatus = taskCB->taskStatus; // 获取任务的状态
1 year ago
if (tempStatus & (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) {
1 year ago
taskCB->taskStatus &= ~(OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY); // 清除任务的挂起状态和延时状态
1 year ago
if (tempStatus & OS_TASK_STATUS_PENDING) {
#ifdef LOSCFG_KERNEL_LITEIPC
1 year ago
taskCB->ipcStatus &= ~IPC_THREAD_STATUS_PEND; // 清除任务的轻量级 IPC 挂起状态
1 year ago
#endif
1 year ago
taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT; // 设置任务的超时状态
LOS_ListDelete(&taskCB->pendList); // 从挂起任务列表中删除任务
taskCB->taskMux = NULL; // 清除任务的互斥信号量
OsTaskWakeClearPendMask(taskCB); // 清除任务的挂起掩码
1 year ago
}
if (!(tempStatus & OS_TASK_STATUS_SUSPENDED)) {
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
taskCB->schedStat.pendTime += currTime - taskCB->startTime; // 更新任务的挂起时间统计
taskCB->schedStat.pendCount++; // 增加任务的挂起次数统计
1 year ago
#endif
1 year ago
OsSchedTaskEnQueue(taskCB); // 将任务加入调度队列
*needSchedule = TRUE; // 设置需要进行调度
1 year ago
}
}
1 year ago
LOS_SpinUnlock(&g_taskSpin); // 释放全局任务自旋锁
1 year ago
}
STATIC INLINE BOOL OsSchedScanTimerList(VOID)
{
1 year ago
Percpu *cpu = OsPercpuGet(); // 获取当前 CPU 的 Per-CPU 变量
BOOL needSchedule = FALSE; // 标记是否需要进行调度
SortLinkAttribute *taskSortLink = &OsPercpuGet()->taskSortLink; // 获取当前 CPU 的任务排序链表属性
LOS_DL_LIST *listObject = &taskSortLink->sortLink; // 获取当前 CPU 的任务排序链表
1 year ago
/*
1 year ago
*
* ( CPU ) IPC
* IPC
1 year ago
*
1 year ago
* 使
*
1 year ago
*/
1 year ago
LOS_SpinLock(&cpu->taskSortLinkSpin); // 获取当前 CPU 的任务排序链表自旋锁
1 year ago
if (LOS_ListEmpty(listObject)) {
LOS_SpinUnlock(&cpu->taskSortLinkSpin);
return needSchedule;
}
1 year ago
SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); // 获取排序链表的第一个任务节点
UINT64 currTime = OsGetCurrSchedTimeCycle(); // 获取当前调度时间
1 year ago
while (sortList->responseTime <= currTime) {
1 year ago
LosTaskCB *taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList); // 获取任务控制块
OsDeleteNodeSortLink(taskSortLink, &taskCB->sortList); // 从排序链表中删除任务节点
LOS_SpinUnlock(&cpu->taskSortLinkSpin); // 释放当前 CPU 的任务排序链表自旋锁
1 year ago
1 year ago
OsSchedWakePendTimeTask(currTime, taskCB, &needSchedule); // 唤醒被挂起的超时任务
1 year ago
1 year ago
LOS_SpinLock(&cpu->taskSortLinkSpin); // 获取当前 CPU 的任务排序链表自旋锁
1 year ago
if (LOS_ListEmpty(listObject)) {
break;
}
1 year ago
sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); // 获取排序链表的下一个任务节点
1 year ago
}
1 year ago
LOS_SpinUnlock(&cpu->taskSortLinkSpin); // 释放当前 CPU 的任务排序链表自旋锁
1 year ago
1 year ago
return needSchedule; // 返回是否需要进行调度
1 year ago
}
STATIC INLINE VOID OsSchedEnTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
{
1 year ago
LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY)); // 断言任务不处于就绪状态
1 year ago
switch (taskCB->policy) {
case LOS_SCHED_RR: {
1 year ago
if (taskCB->timeSlice > OS_TIME_SLICE_MIN) { // 如果时间片大于最小时间片
OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority); // 将任务加入就绪队列的头部
1 year ago
} else {
1 year ago
taskCB->initTimeSlice = OsSchedCalculateTimeSlice(processCB->priority, taskCB->priority); // 计算任务的初始时间片
taskCB->timeSlice = taskCB->initTimeSlice; // 设置任务的时间片
OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority); // 将任务加入就绪队列的尾部
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
taskCB->schedStat.timeSliceTime = taskCB->schedStat.timeSliceRealTime; // 更新任务的时间片统计
taskCB->schedStat.timeSliceCount++; // 增加任务的时间片计数
1 year ago
#endif
}
break;
}
case LOS_SCHED_FIFO: {
1 year ago
/* FIFO 调度策略的时间片总是大于 0除非调用了 yield */
if ((taskCB->timeSlice > OS_TIME_SLICE_MIN) && (taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) { // 如果时间片大于最小时间片且任务正在运行
OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority); // 将任务加入就绪队列的头部
1 year ago
} else {
1 year ago
taskCB->initTimeSlice = OS_SCHED_FIFO_TIMEOUT; // 设置任务的初始时间片为 FIFO 超时时间
taskCB->timeSlice = taskCB->initTimeSlice; // 设置任务的时间片
OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority); // 将任务加入就绪队列的尾部
1 year ago
}
break;
}
case LOS_SCHED_IDLE:
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
taskCB->schedStat.timeSliceCount = 1; // 设置任务的时间片计数为 1
1 year ago
#endif
break;
default:
1 year ago
LOS_ASSERT(0); // 断言不会执行到这里
1 year ago
break;
}
1 year ago
taskCB->taskStatus &= ~OS_TASK_STATUS_BLOCKED; // 清除任务的阻塞状态
taskCB->taskStatus |= OS_TASK_STATUS_READY; // 设置任务的就绪状态
1 year ago
1 year ago
processCB->processStatus &= ~(OS_PROCESS_STATUS_INIT | OS_PROCESS_STATUS_PENDING); // 清除进程的初始化和挂起状态
processCB->processStatus |= OS_PROCESS_STATUS_READY; // 设置进程的就绪状态
processCB->readyTaskNum++; // 增加进程的就绪任务数
1 year ago
}
STATIC INLINE VOID OsSchedDeTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
{
1 year ago
if (taskCB->policy != LOS_SCHED_IDLE) { // 如果任务的调度策略不是 IDLE
OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority); // 从就绪队列中删除任务
1 year ago
}
1 year ago
taskCB->taskStatus &= ~OS_TASK_STATUS_READY; // 清除任务的就绪状态
1 year ago
1 year ago
processCB->readyTaskNum--; // 减少进程的就绪任务数
1 year ago
if (processCB->readyTaskNum == 0) {
1 year ago
processCB->processStatus &= ~OS_PROCESS_STATUS_READY; // 如果进程的就绪任务数为 0则清除进程的就绪状态
1 year ago
}
}
VOID OsSchedTaskDeQueue(LosTaskCB *taskCB)
{
1 year ago
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); // 获取任务所属进程的控制块
1 year ago
1 year ago
if (taskCB->taskStatus & OS_TASK_STATUS_READY) { // 如果任务处于就绪状态
OsSchedDeTaskQueue(taskCB, processCB); // 从就绪队列中删除任务
1 year ago
}
1 year ago
if (processCB->processStatus & OS_PROCESS_STATUS_READY) { // 如果进程处于就绪状态
1 year ago
return;
}
1 year ago
/* 如果当前进程只有当前线程在运行,
* 线
1 year ago
*/
if (OS_PROCESS_GET_RUNTASK_COUNT(processCB->processStatus) == 1) {
1 year ago
processCB->processStatus |= OS_PROCESS_STATUS_PENDING; // 设置进程的挂起状态
1 year ago
}
}
VOID OsSchedTaskEnQueue(LosTaskCB *taskCB)
{
1 year ago
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); // 获取任务所属进程的控制块
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) { // 如果任务不是正在运行状态
taskCB->startTime = OsGetCurrSchedTimeCycle(); // 记录任务的启动时间
1 year ago
}
#endif
1 year ago
OsSchedEnTaskQueue(taskCB, processCB); // 将任务加入就绪队列
1 year ago
}
VOID OsSchedTaskExit(LosTaskCB *taskCB)
{
1 year ago
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); // 获取任务所属进程的控制块
1 year ago
1 year ago
if (taskCB->taskStatus & OS_TASK_STATUS_READY) { // 如果任务处于就绪状态
OsSchedTaskDeQueue(taskCB); // 从就绪队列中删除任务
processCB->processStatus &= ~OS_PROCESS_STATUS_PENDING; // 清除进程的挂起状态
} else if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) { // 如果任务处于挂起状态
LOS_ListDelete(&taskCB->pendList); // 从挂起队列中删除任务
taskCB->taskStatus &= ~OS_TASK_STATUS_PENDING; // 清除任务的挂起状态
1 year ago
}
1 year ago
if (taskCB->taskStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) { // 如果任务处于延时或等待定时状态
OsDeleteSortLink(&taskCB->sortList, OS_SORT_LINK_TASK); // 从排序链表中删除任务
taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME); // 清除任务的延时和等待定时状态
1 year ago
}
}
VOID OsSchedYield(VOID)
{
1 year ago
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
1 year ago
1 year ago
runTask->timeSlice = 0; // 将任务的时间片设置为 0
1 year ago
1 year ago
runTask->startTime = OsGetCurrSchedTimeCycle(); // 记录任务的启动时间
OsSchedTaskEnQueue(runTask); // 将任务加入就绪队列
OsSchedResched(); // 进行调度
1 year ago
}
VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick)
{
1 year ago
OsSchedTaskDeQueue(runTask); // 从就绪队列中删除任务
runTask->taskStatus |= OS_TASK_STATUS_DELAY; // 设置任务的延时状态
runTask->waitTimes = tick; // 设置任务的等待时间
1 year ago
1 year ago
OsSchedResched(); // 进行调度
1 year ago
}
UINT32 OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks, BOOL needSched)
{
1 year ago
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
OsSchedTaskDeQueue(runTask); // 从就绪队列中删除任务
1 year ago
1 year ago
runTask->taskStatus |= OS_TASK_STATUS_PENDING; // 设置任务的挂起状态
LOS_ListTailInsert(list, &runTask->pendList); // 将任务插入挂起队列的尾部
1 year ago
1 year ago
if (ticks != LOS_WAIT_FOREVER) { // 如果等待时间不是永远
runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME; // 设置任务的等待定时状态
runTask->waitTimes = ticks; // 设置任务的等待时间
1 year ago
}
1 year ago
if (needSched == TRUE) { // 如果需要进行调度
OsSchedResched(); // 进行调度
if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) { // 如果任务超时
runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; // 清除任务的超时状态
return LOS_ERRNO_TSK_TIMEOUT; // 返回超时错误
1 year ago
}
}
1 year ago
return LOS_OK; // 返回成功
1 year ago
}
VOID OsSchedTaskWake(LosTaskCB *resumedTask)
{
1 year ago
LOS_ListDelete(&resumedTask->pendList); // 从挂起队列中删除任务
resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING; // 清除任务的挂起状态
1 year ago
1 year ago
if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) { // 如果任务处于等待定时状态
OsDeleteSortLink(&resumedTask->sortList, OS_SORT_LINK_TASK); // 从排序链表中删除任务
resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME; // 清除任务的等待定时状态
1 year ago
}
1 year ago
if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) { // 如果任务没有被挂起
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->
1 year ago
BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 priority)
{
1 year ago
if (taskCB->policy != policy) { // 如果任务的调度策略与传入的策略不同
taskCB->policy = policy; // 更新任务的调度策略
taskCB->timeSlice = 0; // 将任务的时间片设置为 0
1 year ago
}
1 year ago
if (taskCB->taskStatus & OS_TASK_STATUS_READY) { // 如果任务处于就绪状态
OsSchedTaskDeQueue(taskCB); // 从就绪队列中删除任务
taskCB->priority = priority; // 更新任务的优先级
OsSchedTaskEnQueue(taskCB); // 将任务加入就绪队列
return TRUE; // 返回需要进行调度
1 year ago
}
1 year ago
taskCB->priority = priority; // 更新任务的优先级
OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority); // 调用任务优先级修改的钩子函数
if (taskCB->taskStatus & OS_TASK_STATUS_INIT) { // 如果任务处于初始化状态
OsSchedTaskEnQueue(taskCB); // 将任务加入就绪队列
return TRUE; // 返回需要进行调度
1 year ago
}
1 year ago
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { // 如果任务处于运行状态
return TRUE; // 返回需要进行调度
1 year ago
}
1 year ago
return FALSE; // 返回不需要进行调度
1 year ago
}
BOOL OsSchedModifyProcessSchedParam(LosProcessCB *processCB, UINT16 policy, UINT16 priority)
{
LosTaskCB *taskCB = NULL;
BOOL needSched = FALSE;
1 year ago
(VOID)policy; // 忽略传入的调度策略
1 year ago
1 year ago
if (processCB->processStatus & OS_PROCESS_STATUS_READY) { // 如果进程处于就绪状态
1 year ago
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &processCB->threadSiblingList, LosTaskCB, threadList) {
1 year ago
if (taskCB->taskStatus & OS_TASK_STATUS_READY) { // 如果任务处于就绪状态
OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority); // 从优先级队列中删除任务
OsSchedPriQueueEnTail(priority, &taskCB->pendList, taskCB->priority); // 将任务按照新的优先级插入到优先级队列中
needSched = TRUE; // 需要进行调度
1 year ago
}
}
}
1 year ago
processCB->priority = priority; // 更新进程的优先级
if (processCB->processStatus & OS_PROCESS_STATUS_RUNNING) { // 如果进程处于运行状态
needSched = TRUE; // 需要进行调度
1 year ago
}
1 year ago
return needSched; // 返回是否需要进行调度
1 year ago
}
VOID OsSchedTick(VOID)
{
1 year ago
Sched *sched = g_sched; // 获取全局调度器结构体指针
Percpu *currCpu = OsPercpuGet(); // 获取当前 CPU 的私有数据结构指针
BOOL needSched = FALSE; // 是否需要进行调度
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
currCpu->tickStartTime = runTask->irqStartTime; // 记录当前时钟中断的开始时间
if (currCpu->responseID == OS_INVALID_VALUE) { // 如果当前 CPU 的响应 ID 无效
if (sched->swtmrScan != NULL) { // 如果软件定时器扫描函数不为空
(VOID)sched->swtmrScan(); // 执行软件定时器扫描函数
1 year ago
}
1 year ago
needSched = sched->taskScan(); // 执行任务扫描函数,判断是否需要进行调度
1 year ago
1 year ago
if (needSched) { // 如果需要进行调度
LOS_MpSchedule(OS_MP_CPU_ALL); // 进行多核调度
currCpu->schedFlag |= INT_PEND_RESCH; // 设置调度标志位
1 year ago
}
}
1 year ago
currCpu->schedFlag |= INT_PEND_TICK; // 设置时钟中断调度标志位
currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME; // 设置响应时间的上限
1 year ago
}
VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask)
{
1 year ago
idleTask->policy = LOS_SCHED_IDLE; // 设置空闲任务的调度策略为 LOS_SCHED_IDLE
idleTask->initTimeSlice = OS_SCHED_FIFO_TIMEOUT; // 设置空闲任务的初始时间片
idleTask->timeSlice = idleTask->initTimeSlice; // 设置空闲任务的时间片
OsSchedTaskEnQueue(idleTask); // 将空闲任务加入就绪队列
1 year ago
}
UINT32 OsSchedSwtmrScanRegister(SchedScan func)
{
1 year ago
if (func == NULL) { // 如果传入的函数指针为空
return LOS_NOK; // 返回失败
1 year ago
}
1 year ago
g_sched->swtmrScan = func; // 注册软件定时器扫描函数
return LOS_OK; // 返回成功
1 year ago
}
UINT32 OsSchedInit(VOID)
{
UINT16 index, pri;
UINT32 ret;
1 year ago
g_sched = (Sched *)LOS_MemAlloc(m_aucSysMem0, sizeof(Sched)); // 分配内存给全局调度器结构体指针
if (g_sched == NULL) { // 如果内存分配失败
return LOS_ERRNO_TSK_NO_MEMORY; // 返回内存不足错误
1 year ago
}
1 year ago
(VOID)memset_s(g_sched, sizeof(Sched), 0, sizeof(Sched)); // 将全局调度器结构体清零
1 year ago
1 year ago
for (index = 0; index < OS_PRIORITY_QUEUE_NUM; index++) { // 遍历优先级队列
1 year ago
SchedQueue *queueList = &g_sched->queueList[index];
LOS_DL_LIST *priList = &queueList->priQueueList[0];
1 year ago
for (pri = 0; pri < OS_PRIORITY_QUEUE_NUM; pri++) { // 遍历每个优先级队列的优先级
LOS_ListInit(&priList[pri]); // 初始化优先级队列
1 year ago
}
}
1 year ago
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) { // 遍历每个 CPU 的私有数据结构
Percpu *cpu = OsPercpuGetByID(index); // 获取当前 CPU 的私有数据结构指针
ret = OsSortLinkInit(&cpu->taskSortLink); // 初始化任务排序链表
if (ret != LOS_OK) { // 如果初始化失败
return LOS_ERRNO_TSK_NO_MEMORY; // 返回内存不足错误
1 year ago
}
1 year ago
cpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME; // 设置响应时间的上限
LOS_SpinInit(&cpu->taskSortLinkSpin); // 初始化任务排序链表的自旋锁
LOS_SpinInit(&cpu->swtmrSortLinkSpin); // 初始化软件定时器排序链表的自旋锁
1 year ago
}
1 year ago
g_sched->taskScan = OsSchedScanTimerList; // 设置任务扫描函数为默认的定时器扫描函数
1 year ago
#ifdef LOSCFG_SCHED_TICK_DEBUG
1 year ago
ret = OsSchedDebugInit(); // 初始化调度器的调试功能
if (ret != LOS_OK) { // 如果初始化失败
return ret; // 返回错误码
1 year ago
}
#endif
1 year ago
return LOS_OK; // 返回成功
1 year ago
}
STATIC LosTaskCB *OsGetTopTask(VOID)
{
UINT32 priority, processPriority;
UINT32 bitmap;
LosTaskCB *newTask = NULL;
1 year ago
UINT32 processBitmap = g_sched->queueBitmap; // 获取全局调度器的进程位图
1 year ago
#ifdef LOSCFG_KERNEL_SMP
1 year ago
UINT32 cpuid = ArchCurrCpuid(); // 获取当前 CPU 的 ID
1 year ago
#endif
1 year ago
while (processBitmap) { // 遍历进程位图
processPriority = CLZ(processBitmap); // 获取最高优先级的进程
SchedQueue *queueList = &g_sched->queueList[processPriority]; // 获取对应优先级的队列
bitmap = queueList->queueBitmap; // 获取优先级队列的位图
while (bitmap) { // 遍历优先级队列的位图
priority = CLZ(bitmap); // 获取最高优先级的任务
LOS_DL_LIST_FOR_EACH_ENTRY(newTask, &queueList->priQueueList[priority], LosTaskCB, pendList) {
1 year ago
#ifdef LOSCFG_KERNEL_SMP
1 year ago
if (newTask->cpuAffiMask & (1U << cpuid)) { // 如果任务可以在当前 CPU 上运行
1 year ago
#endif
1 year ago
goto FIND_TASK; // 跳转到找到任务的位置
1 year ago
#ifdef LOSCFG_KERNEL_SMP
}
1 year ago
#endif
}
bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1)); // 清除已经遍历过的位
1 year ago
}
1 year ago
processBitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - processPriority - 1)); // 清除已经遍历过的位
1 year ago
}
1 year ago
newTask = OS_TCB_FROM_TID(OsPercpuGet()->idleTaskID); // 如果没有找到任务,则返回空闲任务
1 year ago
FIND_TASK:
1 year ago
OsSchedDeTaskQueue(newTask, OS_PCB_FROM_PID(newTask->processID)); // 从任务队列中删除任务
return newTask; // 返回找到的任务
1 year ago
}
VOID OsSchedStart(VOID)
{
1 year ago
UINT32 cpuid = ArchCurrCpuid(); // 获取当前 CPU 的 ID
1 year ago
UINT32 intSave;
1 year ago
SCHEDULER_LOCK(intSave); // 锁住调度器
1 year ago
1 year ago
if (cpuid == 0) { // 如果是第一个 CPU
OsTickStart(); // 启动系统时钟中断
1 year ago
}
1 year ago
LosTaskCB *newTask = OsGetTopTask(); // 获取要运行的任务
LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID); // 获取任务所属的进程
1 year ago
1 year ago
newTask->taskStatus |= OS_TASK_STATUS_RUNNING; // 设置任务状态为运行中
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING; // 设置进程状态为运行中
newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus); // 增加进程的运行任务计数
1 year ago
1 year ago
OsSchedSetStartTime(HalClockGetCycles()); // 设置调度器的起始时间
newTask->startTime = OsGetCurrSchedTimeCycle(); // 设置任务的起始时间
1 year ago
#ifdef LOSCFG_KERNEL_SMP
/*
* attention: current cpu needs to be set, in case first task deletion
* may fail because this flag mismatch with the real current cpu.
*/
1 year ago
newTask->currCpu = cpuid; // 设置任务所在的 CPU
1 year ago
#endif
1 year ago
OsCurrTaskSet((VOID *)newTask); // 设置当前任务
1 year ago
/* System start schedule */
1 year ago
OS_SCHEDULER_SET(cpuid); // 设置调度器标志,表示系统已经开始调度
1 year ago
1 year ago
OsPercpuGet()->responseID = OS_INVALID; // 初始化响应 ID
OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID); // 设置下一个任务的到期时间
1 year ago
1 year ago
PRINTK("cpu %d entering scheduler\n", cpuid); // 打印进入调度器的消息
OsTaskContextLoad(newTask); // 加载任务上下文并开始执行任务
1 year ago
}
#ifdef LOSCFG_KERNEL_SMP
VOID OsSchedToUserReleaseLock(VOID)
{
/* The scheduling lock needs to be released before returning to user mode */
1 year ago
LOCKDEP_CHECK_OUT(&g_taskSpin); // 检查任务自旋锁是否正确释放
ArchSpinUnlock(&g_taskSpin.rawLock); // 解锁任务自旋锁
1 year ago
1 year ago
OsPercpuGet()->taskLockCnt--; // 减少任务锁计数
1 year ago
}
#endif
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
STATIC VOID OsTaskStackCheck(LosTaskCB *runTask, LosTaskCB *newTask)
{
1 year ago
if (!OS_STACK_MAGIC_CHECK(runTask->topOfStack)) { // 检查当前运行任务的栈是否溢出
LOS_Panic("CURRENT task ID: %s:%d stack overflow!\n", runTask->taskName, runTask->taskID); // 如果溢出,触发异常并打印错误信息
1 year ago
}
if (((UINTPTR)(newTask->stackPointer) <= newTask->topOfStack) ||
1 year ago
((UINTPTR)(newTask->stackPointer) > (newTask->topOfStack + newTask->stackSize))) { // 检查新任务的栈指针是否合法
1 year ago
LOS_Panic("HIGHEST task ID: %s:%u SP error! StackPointer: %p TopOfStack: %p\n",
1 year ago
newTask->taskName, newTask->taskID, newTask->stackPointer, newTask->topOfStack); // 如果不合法,触发异常并打印错误信息
1 year ago
}
}
#endif
STATIC INLINE VOID OsSchedSwitchCheck(LosTaskCB *runTask, LosTaskCB *newTask)
{
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
1 year ago
OsTaskStackCheck(runTask, newTask); // 检查任务栈的合法性
1 year ago
#endif /* LOSCFG_BASE_CORE_TSK_MONITOR */
1 year ago
OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN, newTask, runTask); // 调用任务切换回调函数
1 year ago
}
STATIC INLINE VOID OsSchedSwitchProcess(LosProcessCB *runProcess, LosProcessCB *newProcess)
{
1 year ago
runProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_DEC(runProcess->processStatus); // 减少当前进程的运行任务计数
newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus); // 增加新进程的运行任务计数
1 year ago
1 year ago
LOS_ASSERT(!(OS_PROCESS_GET_RUNTASK_COUNT(newProcess->processStatus) > LOSCFG_KERNEL_CORE_NUM)); // 断言新进程的运行任务计数不超过 CPU 核心数
if (OS_PROCESS_GET_RUNTASK_COUNT(runProcess->processStatus) == 0) { // 如果当前进程的运行任务计数为 0
runProcess->processStatus &= ~OS_PROCESS_STATUS_RUNNING; // 清除当前进程的运行状态标志
1 year ago
}
1 year ago
LOS_ASSERT(!(newProcess->processStatus & OS_PROCESS_STATUS_PENDING)); // 断言新进程的状态不是挂起状态
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING; // 设置新进程的运行状态标志
1 year ago
#ifdef LOSCFG_KERNEL_VM
1 year ago
if (OsProcessIsUserMode(newProcess)) { // 如果新进程是用户态进程
LOS_ArchMmuContextSwitch(&newProcess->vmSpace->archMmu); // 切换内存管理单元上下文
1 year ago
}
#endif
1 year ago
OsCurrProcessSet(newProcess); // 设置当前进程为新进程
1 year ago
}
STATIC VOID OsSchedTaskSwicth(LosTaskCB *runTask, LosTaskCB *newTask)
{
UINT64 endTime;
1 year ago
OsSchedSwitchCheck(runTask, newTask); // 检查任务切换的相关条件
1 year ago
1 year ago
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING; // 清除当前任务的运行状态标志
newTask->taskStatus |= OS_TASK_STATUS_RUNNING; // 设置新任务的运行状态标志
1 year ago
#ifdef LOSCFG_KERNEL_SMP
/* mask new running task's owner processor */
1 year ago
runTask->currCpu = OS_TASK_INVALID_CPUID; // 设置当前任务的 CPU ID 为无效值
newTask->currCpu = ArchCurrCpuid(); // 设置新任务的 CPU ID 为当前 CPU 的 ID
1 year ago
#endif
1 year ago
OsCurrTaskSet((VOID *)newTask); // 设置当前任务为新任务
LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID); // 获取新任务所属的进程
LosProcessCB *runProcess = OS_PCB_FROM_PID(runTask->processID); // 获取当前任务所属的进程
if (runProcess != newProcess) { // 如果当前任务和新任务所属的进程不同
OsSchedSwitchProcess(runProcess, newProcess); // 进行进程切换
1 year ago
}
1 year ago
if (OsProcessIsUserMode(newProcess)) { // 如果新进程是用户态进程
OsCurrUserTaskSet(newTask->userArea); // 设置当前用户态任务为新任务的用户态区域
1 year ago
}
#ifdef LOSCFG_KERNEL_CPUP
1 year ago
OsCpupCycleEndStart(runTask->taskID, newTask->taskID); // 记录当前任务和新任务的 CPU 周期计数
1 year ago
#endif
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
UINT64 waitStartTime = newTask->startTime; // 保存等待调度的起始时间
1 year ago
#endif
if (runTask->taskStatus & OS_TASK_STATUS_READY) {
/* When a thread enters the ready queue, its slice of time is updated */
1 year ago
newTask->startTime = runTask->startTime; // 如果当前任务是就绪状态,则将新任务的起始时间设置为当前任务的起始时间
1 year ago
} else {
/* The currently running task is blocked */
1 year ago
newTask->startTime = OsGetCurrSchedTimeCycle(); // 如果当前任务是阻塞状态,则将新任务的起始时间设置为当前调度时间
1 year ago
/* The task is in a blocking state and needs to update its time slice before pend */
1 year ago
OsTimeSliceUpdate(runTask, newTask->startTime); // 更新当前任务的时间片
1 year ago
if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
1 year ago
OsAdd2SortLink(&runTask->sortList, runTask->startTime, runTask->waitTimes, OS_SORT_LINK_TASK); // 将当前任务添加到排序链表中
1 year ago
}
}
if (newTask->policy == LOS_SCHED_RR) {
1 year ago
endTime = newTask->startTime + newTask->timeSlice; // 如果新任务是轮转调度策略,则计算新任务的结束时间
1 year ago
} else {
1 year ago
endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION; // 如果新任务不是轮转调度策略,则设置新任务的结束时间为最大响应时间
1 year ago
}
1 year ago
OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, endTime, runTask->taskID); // 设置下一个任务的到期时间
1 year ago
#ifdef LOSCFG_SCHED_DEBUG
1 year ago
newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime; // 更新新任务的等待调度时间
newTask->schedStat.waitSchedCount++; // 增加新任务的等待调度次数
runTask->schedStat.runTime = runTask->schedStat.allRuntime; // 更新当前任务的运行时间
runTask->schedStat.switchCount++; // 增加当前任务的切换次数
1 year ago
#endif
/* do the task context switch */
1 year ago
OsTaskSchedule(newTask, runTask); // 进行任务上下文切换
1 year ago
}
1 year ago
//在切换任务之前它首先调用OsSchedSwitchCheck函数来检查任务切换的相关条件。然后它更新当前任务和新任务的运行状态标志并进行一些其他操作如设置当前任务、进行进程切换、设置用户态任务等。接下来它根据任务的状态更新新任务的起始时间并设置下一个任务的到期时间。最后它调用OsTaskSchedule函数进行任务上下文切换。
1 year ago
VOID OsSchedIrqEndCheckNeedSched(VOID)
{
1 year ago
Percpu *percpu = OsPercpuGet(); // 获取当前 CPU 的数据结构指针
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
1 year ago
1 year ago
OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle()); // 更新当前任务的时间片
if (runTask->timeSlice <= OS_TIME_SLICE_MIN) { // 如果当前任务的时间片小于等于最小时间片
percpu->schedFlag |= INT_PEND_RESCH; // 设置调度标志,表示需要进行任务切换
1 year ago
}
1 year ago
if (OsPreemptable() && (percpu->schedFlag & INT_PEND_RESCH)) { // 如果可以抢占且需要进行任务切换
percpu->schedFlag &= ~INT_PEND_RESCH; // 清除调度标志
1 year ago
1 year ago
LOS_SpinLock(&g_taskSpin); // 获取任务自旋锁
1 year ago
1 year ago
OsSchedTaskEnQueue(runTask); // 将当前任务加入就绪队列
1 year ago
1 year ago
LosTaskCB *newTask = OsGetTopTask(); // 获取优先级最高的任务
if (runTask != newTask) { // 如果当前任务不是优先级最高的任务
OsSchedTaskSwicth(runTask, newTask); // 进行任务切换
LOS_SpinUnlock(&g_taskSpin); // 释放任务自旋锁
1 year ago
return;
}
1 year ago
LOS_SpinUnlock(&g_taskSpin); // 释放任务自旋锁
1 year ago
}
1 year ago
if (percpu->schedFlag & INT_PEND_TICK) { // 如果有时钟中断挂起
OsSchedUpdateExpireTime(runTask->startTime); // 更新任务的到期时间
1 year ago
}
}
VOID OsSchedResched(VOID)
{
1 year ago
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin)); // 断言任务自旋锁已持有
1 year ago
#ifdef LOSCFG_KERNEL_SMP
1 year ago
LOS_ASSERT(OsPercpuGet()->taskLockCnt == 1); // 断言任务锁计数为1
1 year ago
#else
1 year ago
LOS_ASSERT(OsPercpuGet()->taskLockCnt == 0); // 断言任务锁计数为0
1 year ago
#endif
1 year ago
OsPercpuGet()->schedFlag &= ~INT_PEND_RESCH; // 清除调度标志
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
LosTaskCB *newTask = OsGetTopTask(); // 获取优先级最高的任务
if (runTask == newTask) { // 如果当前任务就是优先级最高的任务
1 year ago
return;
}
1 year ago
OsSchedTaskSwicth(runTask, newTask); // 进行任务切换
1 year ago
}
1 year ago
/*这段代码实现了在中断结束时检查是否需要进行任务切换的函数OsSchedIrqEndCheckNeedSched
OsSchedResched
OsSchedIrqEndCheckNeedSched
OsSchedResched1SMP
0SMP
*/
1 year ago
VOID LOS_Schedule(VOID)
{
UINT32 intSave;
1 year ago
LosTaskCB *runTask = OsCurrTaskGet(); // 获取当前运行的任务
1 year ago
1 year ago
if (OS_INT_ACTIVE) { // 如果处于中断上下文
OsPercpuGet()->schedFlag |= INT_PEND_RESCH; // 设置调度标志,表示需要进行任务切换
1 year ago
return;
}
1 year ago
if (!OsPreemptable()) { // 如果不允许抢占
1 year ago
return;
}
/*
* trigger schedule in task will also do the slice check
1 year ago
* if necessary, it will give up the timeslice more in time.
* otherwise, there's no other side effects.
1 year ago
*/
1 year ago
SCHEDULER_LOCK(intSave); // 获取调度器锁,禁止调度器抢占
1 year ago
1 year ago
OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle()); // 更新当前任务的时间片
1 year ago
/* add run task back to ready queue */
1 year ago
OsSchedTaskEnQueue(runTask); // 将当前任务加入就绪队列
1 year ago
/* reschedule to new thread */
1 year ago
OsSchedResched(); // 进行任务切换
1 year ago
1 year ago
SCHEDULER_UNLOCK(intSave); // 释放调度器锁
1 year ago
}
STATIC INLINE LOS_DL_LIST *OsSchedLockPendFindPosSub(const LosTaskCB *runTask, const LOS_DL_LIST *lockList)
{
LosTaskCB *pendedTask = NULL;
LOS_DL_LIST *node = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, lockList, LosTaskCB, pendList) {
if (pendedTask->priority < runTask->priority) {
continue;
} else if (pendedTask->priority > runTask->priority) {
node = &pendedTask->pendList;
break;
} else {
node = pendedTask->pendList.pstNext;
break;
}
}
return node;
}
LOS_DL_LIST *OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList)
{
LOS_DL_LIST *node = NULL;
1 year ago
if (LOS_ListEmpty(lockList)) { // 如果锁的等待队列为空
1 year ago
node = lockList;
} else {
LosTaskCB *pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(lockList));
LosTaskCB *pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(lockList));
1 year ago
if (pendedTask1->priority > runTask->priority) { // 如果最高优先级的等待任务的优先级高于当前任务的优先级
1 year ago
node = lockList->pstNext;
1 year ago
} else if (pendedTask2->priority <= runTask->priority) { // 如果最低优先级的等待任务的优先级小于等于当前任务的优先级
1 year ago
node = lockList;
} else {
1 year ago
node = OsSchedLockPendFindPosSub(runTask, lockList); // 在等待队列中查找当前任务应该插入的位置
1 year ago
}
}
return node;
}
1 year ago
/*LOS_Schedule函数用于触发调度器进行任务切换。在函数中首先判断是否处于中断上下文中
OsSchedResched*/