los_sched.c 7.8 KB
Newer Older
1 2 3 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/*
 * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "los_base.h"
#include "los_task_pri.h"
#include "los_percpu_pri.h"
#include "los_hw_pri.h"
#include "los_arch_mmu.h"
#include "los_process_pri.h"
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
//调度算法-进程切换
STATIC VOID OsSchedSwitchProcess(LosProcessCB *runProcess, LosProcessCB *newProcess)
{
    if (runProcess == newProcess) {
        return;
    }

#if (LOSCFG_KERNEL_SMP == YES)
    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) {//获取当前进程的任务数量
#endif
        runProcess->processStatus &= ~OS_PROCESS_STATUS_RUNNING;
        if ((runProcess->threadNumber > 1) && !(runProcess->processStatus & OS_PROCESS_STATUS_READY)) {
            runProcess->processStatus |= OS_PROCESS_STATUS_PEND;
        }
#if (LOSCFG_KERNEL_SMP == YES)
    }
#endif
    LOS_ASSERT(!(newProcess->processStatus & OS_PROCESS_STATUS_PEND));//断言进程不是阻塞状态
    newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;//设置进程状态为运行状态

    if (OsProcessIsUserMode(newProcess)) {//用户模式下切换进程mmu上下文
        LOS_ArchMmuContextSwitch(&newProcess->vmSpace->archMmu);//新进程->虚拟空间中的->Mmu部分入参
    }

#ifdef LOSCFG_KERNEL_CPUP
    OsProcessCycleEndStart(newProcess->processID, OS_PROCESS_GET_RUNTASK_COUNT(runProcess->processStatus) + 1);
#endif /* LOSCFG_KERNEL_CPUP */

    OsCurrProcessSet(newProcess);//将进程置为 g_runProcess

    if ((newProcess->timeSlice == 0) && (newProcess->policy == LOS_SCHED_RR)) {//为用完时间片或初始进程分配时间片
        newProcess->timeSlice = OS_PROCESS_SCHED_RR_INTERVAL;//重新分配时间片,默认 20ms
    }
}
85
//重新调度任务
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
VOID OsSchedResched(VOID)
{
    LosTaskCB *runTask = NULL;
    LosTaskCB *newTask = NULL;
    LosProcessCB *runProcess = NULL;
    LosProcessCB *newProcess = NULL;

    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//必须持有任务自旋锁,自旋锁是不是进程层面去抢锁,而是CPU各自核之间去争夺锁

    if (!OsPreemptableInSched()) {//是否置了重新调度标识位
        return;
    }

    runTask = OsCurrTaskGet();//获取当前任务
    newTask = OsGetTopTask();//获取优先级最最最高的任务

    /* always be able to get one task */
    LOS_ASSERT(newTask != NULL);//不能没有需调度的任务

    if (runTask == newTask) {//当前任务就是最高任务,那还调度个啥的,直接退出.
        return;
    }

    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//当前任务状态位置成不在运行状态
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任务状态位置成在运行状态

112 113
    runProcess = OS_PCB_FROM_PID(runTask->processID);//获取当前进程实体
    newProcess = OS_PCB_FROM_PID(newTask->processID);//获取要切换的进程实体
114

115
    OsSchedSwitchProcess(runProcess, newProcess);//切换进程,里面主要涉及进程空间的切换,即:MMU的上下文切换.
116 117

#if (LOSCFG_KERNEL_SMP == YES)//CPU多核的情况
118 119 120
    /* mask new running task's owner processor *///此处只是贴标签,任务切换期间会有用.
    runTask->currCpu = OS_TASK_INVALID_CPUID;//贴上当前任务不占用CPU标签
    newTask->currCpu = ArchCurrCpuid();//贴上新任务占用CPU的标签
121 122
#endif

123
    (VOID)OsTaskSwitchCheck(runTask, newTask);//切换之前检查新老task
124 125 126 127 128 129 130 131 132

#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
    OsSchedStatistics(runTask, newTask);
#endif

    if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {//没有时间片且是抢占式调度的方式,注意 非抢占式都不需要时间片的.
        newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;//给新任务时间片 默认 20ms
    }

133
    OsCurrTaskSet((VOID*)newTask);//设置新的task为当前任务
134

135 136
    if (OsProcessIsUserMode(newProcess)) {//用户态进程
        OsCurrUserTaskSet(newTask->userArea);//向CP15 (c13, 0, c0, 3) 设置当前线程ID
137 138 139 140 141 142 143 144 145 146 147
    }

    PRINT_TRACE("cpu%d run process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x ->\n"
                "     new process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x!\n",
                ArchCurrCpuid(),
                runProcess->processName, runProcess->processID, runProcess->processStatus,
                runProcess->threadScheduleMap, runTask->taskName,  runTask->taskID, runTask->taskStatus,
                newProcess->processName, newProcess->processID, newProcess->processStatus,
                newProcess->threadScheduleMap, newTask->taskName, newTask->taskID, newTask->taskStatus);

    /* do the task context switch */
148
    OsTaskSchedule(newTask, runTask);//切换任务上下文, 注意OsTaskSchedule是一个汇编函数 见于 los_dispatch.s
149
}
150 151 152 153 154
/******************************************************
   抢占式调度函数
   1.LOS_Schedule会判断是否发生硬件中断
   2.硬件中断处理完成后由汇编调用: ..\arch\arm\arm\src\los_dispatch.S
******************************************************/
155 156 157 158 159
VOID OsSchedPreempt(VOID)
{
    LosTaskCB *runTask = NULL;
    UINT32 intSave;

160
    if (!OsPreemptable()) {//是否允许抢占式调度? 中断发生时是不允许调度的
161 162 163 164 165 166
        return;
    }

    SCHEDULER_LOCK(intSave);

    /* add run task back to ready queue */
167 168
    runTask = OsCurrTaskGet();//当前任务要被重新回到就绪队列
    OS_TASK_SCHED_QUEUE_ENQUEUE(runTask, 0);//参数0代表不改变当前任务的状态,因为任务正在运行,所以将从头部插入
169 170

    /* reschedule to new thread */
171
    OsSchedResched();//执行调度算法
172 173 174 175 176 177 178 179 180

    SCHEDULER_UNLOCK(intSave);
}

#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */