los_sched.c 42.5 KB
Newer Older
1
/*
2 3
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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.
 */

32
#include "los_sched_pri.h"
33
#include "los_hw_pri.h"
34
#include "los_task_pri.h"
35
#include "los_process_pri.h"
36
#include "los_arch_mmu.h"
37
#include "los_hook.h"
38 39 40
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
41 42
#include "los_hw_tick_pri.h"
#include "los_tick_pri.h"
43
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
44 45 46 47 48 49 50 51 52 53 54
#include "los_stackinfo_pri.h"
#endif
#include "los_mp.h"
#ifdef LOSCFG_SCHED_DEBUG
#include "los_stat_pri.h"
#endif



#define OS_32BIT_MAX               0xFFFFFFFFUL
#define OS_SCHED_FIFO_TIMEOUT      0x7FFFFFFF
55
#define OS_PRIORITY_QUEUE_NUM      32	///< 就绪队列数量
56
#define PRIQUEUE_PRIOR0_BIT        0x80000000U
57 58 59
#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) ///< 最大,最小二者差
60 61 62
#define OS_SCHED_READY_MAX         30
#define OS_TIME_SLICE_MIN          (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */

63 64 65 66 67
/// 调度队列
typedef struct {
    LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM];///< 各优先级任务调度队列,默认32级
    UINT32      readyTasks[OS_PRIORITY_QUEUE_NUM]; ///< 各优先级就绪任务数
    UINT32      queueBitmap; ///< 任务优先级调度位图
68 69
} SchedQueue;

70 71
/// 调度器
typedef struct {
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
72 73 74 75
    SchedQueue queueList[OS_PRIORITY_QUEUE_NUM];//进程优先级调度队列,默认32级
    UINT32     queueBitmap;//进程优先级调度位图
    SchedScan  taskScan;//函数指针,扫描任务
    SchedScan  swtmrScan;//函数指针,扫描定时器
76 77
} Sched;

鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
78
STATIC Sched *g_sched = NULL;//全局调度器
79
STATIC UINT64 g_schedTickMaxResponseTime;
80
UINT64 g_sysSchedStartTime = OS_64BIT_MAX;
81 82 83 84 85 86 87 88 89 90

#ifdef LOSCFG_SCHED_TICK_DEBUG
#define OS_SCHED_DEBUG_DATA_NUM  1000
typedef struct {
    UINT32 tickResporeTime[OS_SCHED_DEBUG_DATA_NUM];
    UINT32 index;
    UINT32 setTickCount;
    UINT64 oldResporeTime;
} SchedTickDebug;
STATIC SchedTickDebug *g_schedTickDebug = NULL;
91

92
STATIC UINT32 OsSchedDebugInit(VOID)
93
{
94 95 96 97
    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;
98 99
    }

100 101 102
    (VOID)memset_s(g_schedTickDebug, size, 0, size);
    return LOS_OK;
}
103

104 105 106 107
VOID OsSchedDebugRecordData(VOID)
{
    SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
    if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
108
        UINT64 currTime = OsGetCurrSchedTimeCycle();
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        schedDebug->tickResporeTime[schedDebug->index] = currTime - schedDebug->oldResporeTime;
        schedDebug->oldResporeTime = currTime;
        schedDebug->index++;
    }
}

SchedTickDebug *OsSchedDebugGet(VOID)
{
    return g_schedTickDebug;
}

UINT32 OsShellShowTickRespo(VOID)
{
    UINT32 intSave;
    UINT16 cpu;
124
    UINT64 allTime;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

    UINT32 tickSize = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
    SchedTickDebug *schedDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem1, tickSize);
    if (schedDebug == NULL) {
        return LOS_NOK;
    }

    UINT32 sortLinkNum[LOSCFG_KERNEL_CORE_NUM];
    SCHEDULER_LOCK(intSave);
    (VOID)memcpy_s((CHAR *)schedDebug, tickSize, (CHAR *)OsSchedDebugGet(), tickSize);
    (VOID)memset_s((CHAR *)OsSchedDebugGet(), tickSize, 0, tickSize);
    for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
        sortLinkNum[cpu] = OsPercpuGetByID(cpu)->taskSortLink.nodeNum + OsPercpuGetByID(cpu)->swtmrSortLink.nodeNum;
    }
    SCHEDULER_UNLOCK(intSave);

    for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
        SchedTickDebug *schedData = &schedDebug[cpu];
        PRINTK("cpu : %u sched data num : %u set time count : %u SortMax : %u\n",
               cpu, schedData->index, schedData->setTickCount, sortLinkNum[cpu]);
        UINT32 *data = schedData->tickResporeTime;
146 147 148
        allTime = 0;
        for (UINT32 i = 1; i < schedData->index; i++) {
            allTime += data[i];
149 150
            UINT32 timeUs = (data[i] * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
            PRINTK("     %u(%u)", timeUs, timeUs / OS_US_PER_TICK);
151
            if ((i != 0) && ((i % 5) == 0)) { /* A row of 5 data */
152 153 154 155
                PRINTK("\n");
            }
        }

156 157
        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));
158 159 160 161 162 163 164 165 166 167 168 169
    }

    (VOID)LOS_MemFree(m_aucSysMem1, schedDebug);
    return LOS_OK;
}

#else

UINT32 OsShellShowTickRespo(VOID)
{
    return LOS_NOK;
}
170
#endif
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194

#ifdef LOSCFG_SCHED_DEBUG
UINT32 OsShellShowSchedParam(VOID)
{
    UINT64 averRunTime;
    UINT64 averTimeSlice;
    UINT64 averSchedWait;
    UINT64 averPendTime;
    UINT32 intSave;
    UINT32 size = g_taskMaxNum * sizeof(LosTaskCB);
    LosTaskCB *taskCBArray = LOS_MemAlloc(m_aucSysMem1, size);
    if (taskCBArray == NULL) {
        return LOS_NOK;
    }

    SCHEDULER_LOCK(intSave);
    (VOID)memcpy_s(taskCBArray, size, g_taskCBArray, size);
    SCHEDULER_UNLOCK(intSave);
    PRINTK("  Tid    AverRunTime(us)    SwitchCount  AverTimeSlice(us)    TimeSliceCount  AverReadyWait(us)  "
           "AverPendTime(us)  TaskName \n");
    for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
        LosTaskCB *taskCB = taskCBArray + tid;
        if (OsTaskIsUnused(taskCB)) {
            continue;
195
        }
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

        averRunTime = 0;
        averTimeSlice = 0;
        averPendTime = 0;
        averSchedWait = 0;

        if (taskCB->schedStat.switchCount >= 1) {
            averRunTime = taskCB->schedStat.runTime / taskCB->schedStat.switchCount;
            averRunTime = (averRunTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
        }

        if (taskCB->schedStat.timeSliceCount > 1) {
            averTimeSlice = taskCB->schedStat.timeSliceTime / (taskCB->schedStat.timeSliceCount - 1);
            averTimeSlice = (averTimeSlice * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
        }

        if (taskCB->schedStat.pendCount > 1) {
            averPendTime = taskCB->schedStat.pendTime / taskCB->schedStat.pendCount;
            averPendTime = (averPendTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
        }

        if (taskCB->schedStat.waitSchedCount > 0) {
            averSchedWait = taskCB->schedStat.waitSchedTime / taskCB->schedStat.waitSchedCount;
            averSchedWait = (averSchedWait * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
        }

        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);
226
    }
227 228 229 230 231 232 233 234 235 236 237 238

    (VOID)LOS_MemFree(m_aucSysMem1, taskCBArray);

    return LOS_OK;
}

#else

UINT32 OsShellShowSchedParam(VOID)
{
    return LOS_NOK;
}
239
#endif
240
///< 设置节拍器类型
241 242 243 244 245 246 247 248 249 250 251 252
UINT32 OsSchedSetTickTimerType(UINT32 timerType)
{
    switch (timerType) {
        case 32: /* 32 bit timer */
            g_schedTickMaxResponseTime = OS_32BIT_MAX;
            break;
        case 64: /* 64 bit timer */
            g_schedTickMaxResponseTime = OS_64BIT_MAX;
            break;
        default:
            PRINT_ERR("Unsupported Tick Timer type, The system only supports 32 and 64 bit tick timers\n");
            return LOS_NOK;
253 254
    }

255 256
    return LOS_OK;
}
257
/// 设置调度开始时间
258 259
STATIC VOID OsSchedSetStartTime(UINT64 currCycle)
{
260
    if (g_sysSchedStartTime == OS_64BIT_MAX) {
261 262 263
        g_sysSchedStartTime = currCycle;
    }
}
264
/// 更新时间片
265 266
STATIC INLINE VOID OsTimeSliceUpdate(LosTaskCB *taskCB, UINT64 currTime)
{
267
    LOS_ASSERT(currTime >= taskCB->startTime); //断言参数时间必须大于开始时间
268

269
    INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime);//计算增加的时间
270

271 272
    LOS_ASSERT(incTime >= 0);

273 274
    if (taskCB->policy == LOS_SCHED_RR) {//抢占调度
        taskCB->timeSlice -= incTime; //任务的时间片减少
275 276 277
#ifdef LOSCFG_SCHED_DEBUG
        taskCB->schedStat.timeSliceRealTime += incTime;
#endif
278
    }
279 280
    taskCB->irqUsedTime = 0;//中断时间置0
    taskCB->startTime = currTime;//重新设置开始时间
281 282 283 284

#ifdef LOSCFG_SCHED_DEBUG
    taskCB->schedStat.allRuntime += incTime;
#endif
285
}
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
STATIC INLINE VOID OsSchedTickReload(Percpu *currCpu, UINT64 nextResponseTime, UINT32 responseID, BOOL isTimeSlice)
{
    UINT64 currTime, nextExpireTime;
    UINT32 usedTime;

    currTime = OsGetCurrSchedTimeCycle();
    if (currCpu->tickStartTime != 0) {
        usedTime = currTime - currCpu->tickStartTime;
        currCpu->tickStartTime = 0;
    } else {
        usedTime = 0;
    }

    if ((nextResponseTime > usedTime) && ((nextResponseTime - usedTime) > OS_TICK_RESPONSE_PRECISION)) {
        nextResponseTime -= usedTime;
    } else {
        nextResponseTime = OS_TICK_RESPONSE_PRECISION;
    }

    nextExpireTime = currTime + nextResponseTime;
    if (nextExpireTime >= currCpu->responseTime) {
        return;
    }

    if (isTimeSlice) {
        /* The expiration time of the current system is the thread's slice expiration time */
        currCpu->responseID = responseID;
    } else {
        currCpu->responseID = OS_INVALID_VALUE;
    }

    currCpu->responseTime = nextExpireTime;
    HalClockTickTimerReload(nextResponseTime);

#ifdef LOSCFG_SCHED_TICK_DEBUG
    SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
    if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
        schedDebug->setTickCount++;
    }
#endif
}
328
/// 设置下一个到期时间
329 330
STATIC INLINE VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID,
                                            UINT64 taskEndTime, UINT32 oldResponseID)
331
{
332 333 334 335 336
    UINT64 nextExpireTime = OsGetNextExpireTime(startTime);
    Percpu *currCpu = OsPercpuGet();
    UINT64 nextResponseTime;
    BOOL isTimeSlice = FALSE;

337
    currCpu->schedFlag &= ~INT_PEND_TICK;
338 339 340 341
    if (currCpu->responseID == oldResponseID) {
        /* This time has expired, and the next time the theory has expired is infinite */
        currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
    }
342

343 344 345
    /* The current thread's time slice has been consumed, but the current system lock task cannot
     * trigger the schedule to release the CPU
     */
346
    if ((nextExpireTime > taskEndTime) && ((nextExpireTime - taskEndTime) > OS_SCHED_MINI_PERIOD)) {
347 348 349
        nextExpireTime = taskEndTime;
        isTimeSlice = TRUE;
    }
350

351 352
    if ((currCpu->responseTime > nextExpireTime) &&
        ((currCpu->responseTime - nextExpireTime) >= OS_TICK_RESPONSE_PRECISION)) {
353
        nextResponseTime = nextExpireTime - startTime;
354
        if (nextResponseTime > g_schedTickMaxResponseTime) {
355 356 357 358
            nextResponseTime = g_schedTickMaxResponseTime;
        }
    } else {
        /* There is no point earlier than the current expiration date */
359
        currCpu->tickStartTime = 0;
360 361 362
        return;
    }

363
    OsSchedTickReload(currCpu, nextResponseTime, responseID, isTimeSlice);
364
}
365

366 367 368
VOID OsSchedUpdateExpireTime(UINT64 startTime)
{
    UINT64 endTime;
369
    Percpu *cpu = OsPercpuGet();
370
    LosTaskCB *runTask = OsCurrTaskGet();
371

372 373 374 375 376
    if (!OS_SCHEDULER_ACTIVE || OS_INT_ACTIVE) {
        cpu->schedFlag |= INT_PEND_TICK;
        return;
    }

377 378 379 380 381 382
    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);
        endTime = startTime + timeSlice;
    } else {
383
        endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
384 385 386 387
    }

    OsSchedSetNextExpireTime(startTime, runTask->taskID, endTime, runTask->taskID);
}
388
/// 计算时间片
389 390
STATIC INLINE UINT32 OsSchedCalculateTimeSlice(UINT16 proPriority, UINT16 priority)
{
391 392
    UINT32 retTime;
    UINT32 readyTasks;
393

394
    SchedQueue *queueList = &g_sched->queueList[proPriority];//拿到优先级调度队列
395 396
    readyTasks = queueList->readyTasks[priority];
    if (readyTasks > OS_SCHED_READY_MAX) {
397 398
        return OS_SCHED_TIME_SLICES_MIN;
    }
399 400
    retTime = ((OS_SCHED_READY_MAX - readyTasks) * OS_SCHED_TIME_SLICES_DIFF) / OS_SCHED_READY_MAX;
    return (retTime + OS_SCHED_TIME_SLICES_MIN);
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
}

STATIC INLINE VOID OsSchedPriQueueEnHead(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
    SchedQueue *queueList = &g_sched->queueList[proPriority];
    LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
    UINT32 *bitMap = &queueList->queueBitmap;

    /*
     * Task control blocks are inited as zero. And when task is deleted,
     * and at the same time would be deleted from priority queue or
     * other lists, task pend node will restored as zero.
     */
    LOS_ASSERT(priqueueItem->pstNext == NULL);

    if (*bitMap == 0) {
        g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
    }

    if (LOS_ListEmpty(&priQueueList[priority])) {
        *bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
    }

    LOS_ListHeadInsert(&priQueueList[priority], priqueueItem);
    queueList->readyTasks[priority]++;
}

STATIC INLINE VOID OsSchedPriQueueEnTail(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
    SchedQueue *queueList = &g_sched->queueList[proPriority];
    LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
    UINT32 *bitMap = &queueList->queueBitmap;

    /*
     * Task control blocks are inited as zero. And when task is deleted,
     * and at the same time would be deleted from priority queue or
     * other lists, task pend node will restored as zero.
     */
    LOS_ASSERT(priqueueItem->pstNext == NULL);

    if (*bitMap == 0) {
        g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
    }

    if (LOS_ListEmpty(&priQueueList[priority])) {
        *bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
    }

    LOS_ListTailInsert(&priQueueList[priority], priqueueItem);
    queueList->readyTasks[priority]++;
}

STATIC INLINE VOID OsSchedPriQueueDelete(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
{
    SchedQueue *queueList = &g_sched->queueList[proPriority];
    LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
    UINT32 *bitMap = &queueList->queueBitmap;

    LOS_ListDelete(priqueueItem);
    queueList->readyTasks[priority]--;
    if (LOS_ListEmpty(&priQueueList[priority])) {
        *bitMap &= ~(PRIQUEUE_PRIOR0_BIT >> priority);
    }

    if (*bitMap == 0) {
        g_sched->queueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> proPriority);
    }
}

STATIC INLINE VOID OsSchedWakePendTimeTask(UINT64 currTime, LosTaskCB *taskCB, BOOL *needSchedule)
{
#ifndef LOSCFG_SCHED_DEBUG
    (VOID)currTime;
#endif

    LOS_SpinLock(&g_taskSpin);
    UINT16 tempStatus = taskCB->taskStatus;
    if (tempStatus & (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) {
        taskCB->taskStatus &= ~(OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY);
        if (tempStatus & OS_TASK_STATUS_PENDING) {
            taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
            LOS_ListDelete(&taskCB->pendList);
            taskCB->taskMux = NULL;
            OsTaskWakeClearPendMask(taskCB);
        }

        if (!(tempStatus & OS_TASK_STATUS_SUSPENDED)) {
#ifdef LOSCFG_SCHED_DEBUG
            taskCB->schedStat.pendTime += currTime - taskCB->startTime;
            taskCB->schedStat.pendCount++;
#endif
            OsSchedTaskEnQueue(taskCB);
            *needSchedule = TRUE;
        }
    }

    LOS_SpinUnlock(&g_taskSpin);
}
499
///扫描那些处于等待状态的任务是否时间到了
500 501 502 503
STATIC INLINE BOOL OsSchedScanTimerList(VOID)
{
    Percpu *cpu = OsPercpuGet();
    BOOL needSchedule = FALSE;
504
    SortLinkAttribute *taskSortLink = &OsPercpuGet()->taskSortLink;//获取本CPU核上挂的所有等待的任务排序链表
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
    LOS_DL_LIST *listObject = &taskSortLink->sortLink;
    /*
     * When task is pended with timeout, the task block is on the timeout sortlink
     * (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken
     * up by either timeout or corresponding ipc it's waiting.
     *
     * Now synchronize sortlink preocedure is used, therefore the whole task scan needs
     * to be protected, preventing another core from doing sortlink deletion at same time.
     */
    LOS_SpinLock(&cpu->taskSortLinkSpin);

    if (LOS_ListEmpty(listObject)) {
        LOS_SpinUnlock(&cpu->taskSortLinkSpin);
        return needSchedule;
    }

521
    SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);//获取每个优先级上的任务链表头节点
522
    UINT64 currTime = OsGetCurrSchedTimeCycle();
523
    while (sortList->responseTime <= currTime) {//
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
        LosTaskCB *taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);
        OsDeleteNodeSortLink(taskSortLink, &taskCB->sortList);
        LOS_SpinUnlock(&cpu->taskSortLinkSpin);

        OsSchedWakePendTimeTask(currTime, taskCB, &needSchedule);

        LOS_SpinLock(&cpu->taskSortLinkSpin);
        if (LOS_ListEmpty(listObject)) {
            break;
        }

        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    }

    LOS_SpinUnlock(&cpu->taskSortLinkSpin);

    return needSchedule;
}

543 544 545 546 547 548 549 550 551
/*!
 * @brief OsSchedEnTaskQueue	
 * 添加任务到进程的就绪队列中
 * @param processCB	
 * @param taskCB	
 * @return	
 *
 * @see
 */
552 553
STATIC INLINE VOID OsSchedEnTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
{
554
    LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY));//必须是就绪状态,因为只有就绪状态才能入就绪队列
555 556

    switch (taskCB->policy) {
557 558 559 560 561 562
        case LOS_SCHED_RR: {//抢占式跳读
            if (taskCB->timeSlice > OS_TIME_SLICE_MIN) {//时间片大于最小的时间片 50微妙
                OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority);//插入对应优先级的就绪队列中
            } else {//如果时间片不够了,咋办?
                taskCB->initTimeSlice = OsSchedCalculateTimeSlice(processCB->priority, taskCB->priority);//重新计算时间片
                taskCB->timeSlice = taskCB->initTimeSlice;//
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
                OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority);
#ifdef LOSCFG_SCHED_DEBUG
                taskCB->schedStat.timeSliceTime = taskCB->schedStat.timeSliceRealTime;
                taskCB->schedStat.timeSliceCount++;
#endif
            }
            break;
        }
        case LOS_SCHED_FIFO: {
            /* The time slice of FIFO is always greater than 0 unless the yield is called */
            if ((taskCB->timeSlice > OS_TIME_SLICE_MIN) && (taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
                OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority);
            } else {
                taskCB->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
                taskCB->timeSlice = taskCB->initTimeSlice;
                OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority);
            }
            break;
        }
        case LOS_SCHED_IDLE:
#ifdef LOSCFG_SCHED_DEBUG
            taskCB->schedStat.timeSliceCount = 1;
#endif
            break;
        default:
            LOS_ASSERT(0);
            break;
    }

    taskCB->taskStatus &= ~OS_TASK_STATUS_BLOCKED;
    taskCB->taskStatus |= OS_TASK_STATUS_READY;

    processCB->processStatus &= ~(OS_PROCESS_STATUS_INIT | OS_PROCESS_STATUS_PENDING);
    processCB->processStatus |= OS_PROCESS_STATUS_READY;
    processCB->readyTaskNum++;
}

STATIC INLINE VOID OsSchedDeTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
{
    if (taskCB->policy != LOS_SCHED_IDLE) {
        OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority);
    }
    taskCB->taskStatus &= ~OS_TASK_STATUS_READY;

    processCB->readyTaskNum--;
    if (processCB->readyTaskNum == 0) {
        processCB->processStatus &= ~OS_PROCESS_STATUS_READY;
    }
}
612
/// 将任务从就绪队列中删除
613 614
VOID OsSchedTaskDeQueue(LosTaskCB *taskCB)
{
615
    LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);//通过任务获取所在进程
616

617 618
    if (taskCB->taskStatus & OS_TASK_STATUS_READY) {//任务处于就绪状态
        OsSchedDeTaskQueue(taskCB, processCB);//从该进程的就绪任务队列中删除
619 620
    }

621
    if (processCB->processStatus & OS_PROCESS_STATUS_READY) { //进程处于就绪状态不能删除任务,这是为什么呢 ? @note_thinking 
622 623 624
        return;
    }

625 626
    /* If the current process has only the current thread running,
     * the process becomes blocked after the thread leaves the scheduling queue
627 628
     * 如果当前进程只有当前任务在运行,任务离开调度队列后进程设置为阻塞状态
     * 注意:一个进程下的任务可能同时被多个CPU在并行运行.
629
     */
630 631
    if (OS_PROCESS_GET_RUNTASK_COUNT(processCB->processStatus) == 1) { //根据数量来这只状态,注意 processStatus 承载了两重含义
        processCB->processStatus |= OS_PROCESS_STATUS_PENDING; //将进程状态设为阻塞状态
632 633 634 635 636 637 638 639
    }
}

VOID OsSchedTaskEnQueue(LosTaskCB *taskCB)
{
    LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);
#ifdef LOSCFG_SCHED_DEBUG
    if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
640
        taskCB->startTime = OsGetCurrSchedTimeCycle();
641 642 643 644
    }
#endif
    OsSchedEnTaskQueue(taskCB, processCB);
}
645
/// 任务退出
646 647 648 649
VOID OsSchedTaskExit(LosTaskCB *taskCB)
{
    LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);

650 651 652 653 654 655
    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;////任务贴上非挂起标签
656 657 658 659 660 661 662
    }

    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);
    }
}
663
///通过本函数可以看出 yield 的真正含义是主动让出CPU,那怎么安置自己呢? 跑到末尾重新排队. 真是个活雷锋,好同志啊!!!
664 665 666
VOID OsSchedYield(VOID)
{
    LosTaskCB *runTask = OsCurrTaskGet();
667

668
    runTask->timeSlice = 0;//时间片变成0,代表主动让出运行时间.
669

670
    runTask->startTime = OsGetCurrSchedTimeCycle();//重新获取开始时间
671 672
    OsSchedTaskEnQueue(runTask);//跑队列尾部排队
    OsSchedResched();//发起调度
673
}
674
///延期调度
675 676
VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick)
{
677 678 679
    OsSchedTaskDeQueue(runTask);//将任务从就绪队列中删除
    runTask->taskStatus |= OS_TASK_STATUS_DELAY;//任务状态改成延期
    runTask->waitTimes = tick;//延期节拍数
680

681
    OsSchedResched();//既然本任务延期,就需要发起新的调度.
682
}
683
///任务进入等待链表
684 685
UINT32 OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks, BOOL needSched)
{
686 687
    LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
    OsSchedTaskDeQueue(runTask);//将任务从就绪队列中删除
688

689 690
    runTask->taskStatus |= OS_TASK_STATUS_PENDING;//任务状态改成阻塞
    LOS_ListTailInsert(list, &runTask->pendList);//挂入阻塞链表
691

692 693 694
    if (ticks != LOS_WAIT_FOREVER) {//如果不是永久的等待
        runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;//标记为有时间的阻塞
        runTask->waitTimes = ticks;//要阻塞多久
695 696
    }

697 698
    if (needSched == TRUE) {//是否需要调度
        OsSchedResched();//申请调度,将切换任务上下文
699 700 701 702 703 704 705 706
        if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
            runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
            return LOS_ERRNO_TSK_TIMEOUT;
        }
    }

    return LOS_OK;
}
707
///任务从等待链表中恢复,并从链表中摘除.
708 709 710 711 712 713 714 715 716 717 718 719
VOID OsSchedTaskWake(LosTaskCB *resumedTask)
{
    LOS_ListDelete(&resumedTask->pendList);
    resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING;

    if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
        OsDeleteSortLink(&resumedTask->sortList, OS_SORT_LINK_TASK);
        resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
    }

    if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
#ifdef LOSCFG_SCHED_DEBUG
720
        resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
        resumedTask->schedStat.pendCount++;
#endif
        OsSchedTaskEnQueue(resumedTask);
    }
}

BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 priority)
{
    if (taskCB->policy != policy) {
        taskCB->policy = policy;
        taskCB->timeSlice = 0;
    }

    if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
        OsSchedTaskDeQueue(taskCB);
        taskCB->priority = priority;
        OsSchedTaskEnQueue(taskCB);
        return TRUE;
    }

    taskCB->priority = priority;
742
    OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority); 
743 744 745 746 747 748 749 750 751 752 753
    if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
        OsSchedTaskEnQueue(taskCB);
        return TRUE;
    }

    if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
        return TRUE;
    }

    return FALSE;
}
754
///修改进程调度参数
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
BOOL OsSchedModifyProcessSchedParam(LosProcessCB *processCB, UINT16 policy, UINT16 priority)
{
    LosTaskCB *taskCB = NULL;
    BOOL needSched = FALSE;
    (VOID)policy;

    if (processCB->processStatus & OS_PROCESS_STATUS_READY) {
        LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &processCB->threadSiblingList, LosTaskCB, threadList) {
            if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
                OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority);
                OsSchedPriQueueEnTail(priority, &taskCB->pendList, taskCB->priority);
                needSched = TRUE;
            }
        }
    }

    processCB->priority = priority;
    if (processCB->processStatus & OS_PROCESS_STATUS_RUNNING) {
        needSched = TRUE;
    }

    return needSched;
}

VOID OsSchedTick(VOID)
{
    Sched *sched = g_sched;
    Percpu *currCpu = OsPercpuGet();
    BOOL needSched = FALSE;
784
    LosTaskCB *runTask = OsCurrTaskGet();
785

786
    currCpu->tickStartTime = runTask->irqStartTime;
787 788 789 790 791 792 793 794 795
    if (currCpu->responseID == OS_INVALID_VALUE) {
        if (sched->swtmrScan != NULL) {
            (VOID)sched->swtmrScan();
        }

        needSched = sched->taskScan();

        if (needSched) {
            LOS_MpSchedule(OS_MP_CPU_ALL);
796
            currCpu->schedFlag |= INT_PEND_RESCH;
797 798
        }
    }
799 800
    currCpu->schedFlag |= INT_PEND_TICK;
    currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
801 802
}

803
VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask)
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
{
    idleTask->policy = LOS_SCHED_IDLE;
    idleTask->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
    idleTask->timeSlice = idleTask->initTimeSlice;
    OsSchedTaskEnQueue(idleTask);
}

UINT32 OsSchedSwtmrScanRegister(SchedScan func)
{
    if (func == NULL) {
        return LOS_NOK;
    }

    g_sched->swtmrScan = func;
    return LOS_OK;
}
820
///调度初始化
821 822 823 824 825
UINT32 OsSchedInit(VOID)
{
    UINT16 index, pri;
    UINT32 ret;

鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
826
    g_sched = (Sched *)LOS_MemAlloc(m_aucSysMem0, sizeof(Sched));//分配调度器内存
827 828 829 830 831 832
    if (g_sched == NULL) {
        return LOS_ERRNO_TSK_NO_MEMORY;
    }

    (VOID)memset_s(g_sched, sizeof(Sched), 0, sizeof(Sched));

鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
833
    for (index = 0; index < OS_PRIORITY_QUEUE_NUM; index++) {//初始化进程优先级队列
834
        SchedQueue *queueList = &g_sched->queueList[index];
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
835
        LOS_DL_LIST *priList = &queueList->priQueueList[0];//每个进程优先级都有同样的任务优先级链表
836
        for (pri = 0; pri < OS_PRIORITY_QUEUE_NUM; pri++) {
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
837
            LOS_ListInit(&priList[pri]);//初始化任务优先级链表节点
838 839 840
        }
    }

鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
841 842 843
    for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {//初始化每个CPU核
        Percpu *cpu = OsPercpuGetByID(index);//获取某个CPU信息
        ret = OsSortLinkInit(&cpu->taskSortLink);//初始化任务排序链表
844 845 846 847
        if (ret != LOS_OK) {
            return LOS_ERRNO_TSK_NO_MEMORY;
        }
        cpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
848 849
        LOS_SpinInit(&cpu->taskSortLinkSpin);//自旋锁初始化
        LOS_SpinInit(&cpu->swtmrSortLinkSpin);//操作具体CPU核定时器排序链表
850 851
    }

852
    g_sched->taskScan = OsSchedScanTimerList;//扫描那些处于等待状态的任务是否时间到了
853 854 855 856 857 858 859 860 861

#ifdef LOSCFG_SCHED_TICK_DEBUG
    ret = OsSchedDebugInit();
    if (ret != LOS_OK) {
        return ret;
    }
#endif
    return LOS_OK;
}
862
/// 获取就绪队列中优先级最高的任务
863 864 865 866 867 868
STATIC LosTaskCB *OsGetTopTask(VOID)
{
    UINT32 priority, processPriority;
    UINT32 bitmap;
    LosTaskCB *newTask = NULL;
    UINT32 processBitmap = g_sched->queueBitmap;
869
#ifdef LOSCFG_KERNEL_SMP
870 871 872 873 874 875 876 877 878 879
    UINT32 cpuid = ArchCurrCpuid();
#endif

    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) {
880
#ifdef LOSCFG_KERNEL_SMP
881 882 883
                    if (newTask->cpuAffiMask & (1U << cpuid)) {
#endif
                        goto FIND_TASK;
884
#ifdef LOSCFG_KERNEL_SMP
885 886 887 888 889 890 891 892 893 894 895 896 897 898
                    }
#endif
                }
            bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1));
        }
        processBitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - processPriority - 1));
    }

    newTask = OS_TCB_FROM_TID(OsPercpuGet()->idleTaskID);

FIND_TASK:
    OsSchedDeTaskQueue(newTask, OS_PCB_FROM_PID(newTask->processID));
    return newTask;
}
899
///CPU的调度开始,每个CPU核都会执行这个函数一次.
900 901
VOID OsSchedStart(VOID)
{
902
    UINT32 cpuid = ArchCurrCpuid();//从系统寄存器上获取当前执行的CPU核编号
903 904 905 906
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);

907
    if (cpuid == 0) {
908
    OsTickStart();//开始了属于本核的tick 
909
    }
910

911 912
    LosTaskCB *newTask = OsGetTopTask();//拿一个优先级最高的任务
    LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);//获取该任务的进程实体
913

914
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//变成运行状态,注意此时该任务还没真正的运行
915
    newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;//processStatus 具有两重含义,将它设为正在运行状态,但注意这是在进程的角度,实际上底层还没有切到它运行.
916
    newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);//当前任务的数量也增加一个
917

918
    OsSchedSetStartTime(HalClockGetCycles());//设置调度开始时间
919
    newTask->startTime = OsGetCurrSchedTimeCycle();
920

921
#ifdef LOSCFG_KERNEL_SMP //注意:需要设置当前cpu,以防第一个任务删除可能会失败,因为此标志与实际当前 cpu 不匹配。
922 923 924 925
    /*
     * attention: current cpu needs to be set, in case first task deletion
     * may fail because this flag mismatch with the real current cpu.
     */
926
    newTask->currCpu = cpuid;//设置当前CPU,确保第一个任务由本CPU核执行
927 928 929 930 931 932 933 934 935 936 937 938 939 940
#endif

    OsCurrTaskSet((VOID *)newTask);

    /* System start schedule */
    OS_SCHEDULER_SET(cpuid);

    OsPercpuGet()->responseID = OS_INVALID;
    OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID);

    PRINTK("cpu %d entering scheduler\n", cpuid);
    OsTaskContextLoad(newTask);
}

941
#ifdef LOSCFG_KERNEL_SMP
942 943 944 945 946 947 948 949 950 951
VOID OsSchedToUserReleaseLock(VOID)
{
    /* The scheduling lock needs to be released before returning to user mode */
    LOCKDEP_CHECK_OUT(&g_taskSpin);
    ArchSpinUnlock(&g_taskSpin.rawLock);

    OsPercpuGet()->taskLockCnt--;
}
#endif

952
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
953 954 955 956 957 958 959 960 961 962 963 964
STATIC VOID OsTaskStackCheck(LosTaskCB *runTask, LosTaskCB *newTask)
{
    if (!OS_STACK_MAGIC_CHECK(runTask->topOfStack)) {
        LOS_Panic("CURRENT task ID: %s:%d stack overflow!\n", runTask->taskName, runTask->taskID);
    }

    if (((UINTPTR)(newTask->stackPointer) <= newTask->topOfStack) ||
        ((UINTPTR)(newTask->stackPointer) > (newTask->topOfStack + newTask->stackSize))) {
        LOS_Panic("HIGHEST task ID: %s:%u SP error! StackPointer: %p TopOfStack: %p\n",
                  newTask->taskName, newTask->taskID, newTask->stackPointer, newTask->topOfStack);
    }
}
965 966
#endif

967 968
STATIC INLINE VOID OsSchedSwitchCheck(LosTaskCB *runTask, LosTaskCB *newTask)
{
969
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
970
    OsTaskStackCheck(runTask, newTask);
971 972
#endif /* LOSCFG_BASE_CORE_TSK_MONITOR */
    OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN, newTask, runTask);
973 974 975 976 977 978 979 980 981 982 983 984 985 986
}

STATIC INLINE VOID OsSchedSwitchProcess(LosProcessCB *runProcess, LosProcessCB *newProcess)
{
    runProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_DEC(runProcess->processStatus);
    newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);

    LOS_ASSERT(!(OS_PROCESS_GET_RUNTASK_COUNT(newProcess->processStatus) > LOSCFG_KERNEL_CORE_NUM));
    if (OS_PROCESS_GET_RUNTASK_COUNT(runProcess->processStatus) == 0) {
        runProcess->processStatus &= ~OS_PROCESS_STATUS_RUNNING;
    }

    LOS_ASSERT(!(newProcess->processStatus & OS_PROCESS_STATUS_PENDING));
    newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;
987

988 989 990 991 992 993 994 995 996
#ifdef LOSCFG_KERNEL_VM
    if (OsProcessIsUserMode(newProcess)) {
        LOS_ArchMmuContextSwitch(&newProcess->vmSpace->archMmu);
    }
#endif

    OsCurrProcessSet(newProcess);
}

997 998 999 1000 1001 1002 1003 1004 1005
/*!
 * @brief OsSchedTaskSwitch	实现新老两个任务切换
 *
 * @param newTask 	
 * @param runTask	
 * @return	
 *
 * @see
 */
1006
STATIC VOID OsSchedTaskSwitch(LosTaskCB *runTask, LosTaskCB *newTask)
1007 1008 1009
{
    UINT64 endTime;

1010
    OsSchedSwitchCheck(runTask, newTask);//任务内容检查
1011

1012 1013
    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING; //当前任务去掉正在运行的标签
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;	//新任务贴上正在运行的标签,虽标签贴上了,但目前还是在老任务中跑.
1014

1015
#ifdef LOSCFG_KERNEL_SMP
1016
    /* mask new running task's owner processor */
1017 1018
    runTask->currCpu = OS_TASK_INVALID_CPUID;//褫夺当前任务的CPU使用权
    newTask->currCpu = ArchCurrCpuid(); //标记新任务获取当前CPU使用权
1019 1020
#endif

1021 1022 1023 1024 1025
    OsCurrTaskSet((VOID *)newTask);//设置新任务为当前任务
    LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);//获取新任务所在进程实体
    LosProcessCB *runProcess = OS_PCB_FROM_PID(runTask->processID);//获取老任务所在进程实体
    if (runProcess != newProcess) {//如果不是同一个进程,就需要换行进程上下文,也就是切换MMU,切换进程空间
        OsSchedSwitchProcess(runProcess, newProcess);//切换进程上下文
1026 1027
    }

1028 1029
    if (OsProcessIsUserMode(newProcess)) {//如果是用户模式即应用进程
        OsCurrUserTaskSet(newTask->userArea);//设置用户态栈空间
1030 1031
    }

1032 1033 1034 1035 1036 1037 1038
#ifdef LOSCFG_KERNEL_CPUP
    OsCpupCycleEndStart(runTask->taskID, newTask->taskID);
#endif

#ifdef LOSCFG_SCHED_DEBUG
    UINT64 waitStartTime = newTask->startTime;
#endif
1039 1040 1041
    if (runTask->taskStatus & OS_TASK_STATUS_READY) {//注意老任务可不一定是就绪状态
        /* When a thread enters the ready queue, its slice of time is updated 
		当一个线程(任务)进入就绪队列时,它的时间片被更新 */
1042 1043 1044
        newTask->startTime = runTask->startTime;
    } else {
        /* The currently running task is blocked */
1045
        newTask->startTime = OsGetCurrSchedTimeCycle();//重新获取时间
1046
        /* The task is in a blocking state and needs to update its time slice before pend */
1047 1048
        OsTimeSliceUpdate(runTask, newTask->startTime);//更新时间片
		//两种状态下将老任务放入CPU的工作链表中
1049 1050 1051
        if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
            OsAdd2SortLink(&runTask->sortList, runTask->startTime, runTask->waitTimes, OS_SORT_LINK_TASK);
        }
1052 1053
    }

1054 1055 1056
    if (newTask->policy == LOS_SCHED_RR) {
        endTime = newTask->startTime + newTask->timeSlice;
    } else {
1057
        endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
1058 1059
    }
    OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, endTime, runTask->taskID);
1060

1061 1062 1063 1064 1065 1066
#ifdef LOSCFG_SCHED_DEBUG
    newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime;
    newTask->schedStat.waitSchedCount++;
    runTask->schedStat.runTime = runTask->schedStat.allRuntime;
    runTask->schedStat.switchCount++;
#endif
1067
    /* do the task context switch */
1068
    OsTaskSchedule(newTask, runTask); //执行汇编代码
1069 1070 1071 1072 1073 1074 1075
}

VOID OsSchedIrqEndCheckNeedSched(VOID)
{
    Percpu *percpu = OsPercpuGet();
    LosTaskCB *runTask = OsCurrTaskGet();

1076
    OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());
1077
    if (runTask->timeSlice <= OS_TIME_SLICE_MIN) {
1078
        percpu->schedFlag |= INT_PEND_RESCH;
1079 1080
    }

1081 1082
    if (OsPreemptable() && (percpu->schedFlag & INT_PEND_RESCH)) {
        percpu->schedFlag &= ~INT_PEND_RESCH;
1083 1084 1085 1086 1087 1088 1089

        LOS_SpinLock(&g_taskSpin);

        OsSchedTaskEnQueue(runTask);

        LosTaskCB *newTask = OsGetTopTask();
        if (runTask != newTask) {
1090
            OsSchedTaskSwitch(runTask, newTask);
1091 1092 1093 1094 1095 1096 1097
            LOS_SpinUnlock(&g_taskSpin);
            return;
        }

        LOS_SpinUnlock(&g_taskSpin);
    }

1098 1099 1100
    if (percpu->schedFlag & INT_PEND_TICK) {
        OsSchedUpdateExpireTime(runTask->startTime);
    }
1101
}
1102
/// 申请一次调度
1103 1104 1105
VOID OsSchedResched(VOID)
{
    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
1106
#ifdef LOSCFG_KERNEL_SMP
1107
    LOS_ASSERT(OsPercpuGet()->taskLockCnt == 1); // @note_thinking 为何此处一定得 == 1, 大于1不行吗?  
1108 1109 1110 1111
#else
    LOS_ASSERT(OsPercpuGet()->taskLockCnt == 0);
#endif

1112
    OsPercpuGet()->schedFlag &= ~INT_PEND_RESCH;//去掉标签
1113
    LosTaskCB *runTask = OsCurrTaskGet();
1114
    LosTaskCB *newTask = OsGetTopTask();//获取最高优先级任务
1115 1116 1117 1118
    if (runTask == newTask) {
        return;
    }

1119
    OsSchedTaskSwitch(runTask, newTask);//CPU将真正的换任务执行
1120
}
1121

1122 1123 1124 1125 1126 1127 1128
/*!
 * @brief LOS_Schedule	任务调度主函数
 *
 * @return	
 *
 * @see
 */
1129
VOID LOS_Schedule(VOID)
1130 1131
{
    UINT32 intSave;
1132 1133
    LosTaskCB *runTask = OsCurrTaskGet();

1134 1135
    if (OS_INT_ACTIVE) { //中断发生中...,需停止调度
        OsPercpuGet()->schedFlag |= INT_PEND_RESCH;//贴上原因
1136 1137
        return;
    }
1138

1139
    if (!OsPreemptable()) {//当不可抢占时直接返回
1140 1141 1142
        return;
    }

1143 1144 1145 1146 1147
    /*
     * trigger schedule in task will also do the slice check
     * if neccessary, it will give up the timeslice more in time.
     * otherwhise, there's no other side effects.
     */
1148 1149
    SCHEDULER_LOCK(intSave);

1150
    OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());//更新时间片
1151

1152 1153
    /* add run task back to ready queue | 添加任务到就绪队列*/
    OsSchedTaskEnQueue(runTask); 
1154

1155
    /* reschedule to new thread | 申请调度,CPU可能将换任务执行*/
1156
    OsSchedResched();
1157 1158 1159 1160

    SCHEDULER_UNLOCK(intSave);
}

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
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;

    if (LOS_ListEmpty(lockList)) {
        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));
        if (pendedTask1->priority > runTask->priority) {
            node = lockList->pstNext;
        } else if (pendedTask2->priority <= runTask->priority) {
            node = lockList;
        } else {
            node = OsSchedLockPendFindPosSub(runTask, lockList);
        }
    }

    return node;
1200
}
1201