上下文切换的具体步骤
场景:进程A下CPU,进程B上CPU
1. 保存进程A的上下文环境(程序计数器,程序状态字,其他寄存器…)
2. 用新状态和其他相关信息更新进程A的PCB
3. 把进程A移至合适的队列(就绪,阻塞…)
4. 将进程B的状态设置为运行态
5. 从进程B的PCB中恢复上下文(程序计数器,程序状态字,其他寄存器…)
Ref: 陈奶奶2018.3.29的课件
上下文切换的代码实现
schedule 调度函数
// Ref: linux-2.6.0\kernel\sched.c
/*
* schedule() is the main scheduler function.
*/
asmlinkage void schedule(void)
{
task_t *prev, *next;
runqueue_t *rq;
prio_array_t *array;
struct list_head *queue;
unsigned long long now;
unsigned long run_time;
int idx;
/*
* Test if we are atomic. Since do_exit() needs to call into
* schedule() atomically, we ignore that path for now.
* Otherwise, whine if we are scheduling when we should not be.
*/
if (likely(!(current->state & (TASK_DEAD | TASK_ZOMBIE)))) {
if (unlikely(in_atomic())) {
printk(KERN_ERR "bad: scheduling while atomic!\n");
dump_stack();
}
}
need_resched:
preempt_disable();
prev = current;
rq = this_rq();
release_kernel_lock(prev);
now = sched_clock();
if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG))
run_time = now - prev->timestamp;
else
run_time = NS_MAX_SLEEP_AVG;
/*
* Tasks with interactive credits get charged less run_time
* at high sleep_avg to delay them losing their interactive
* status
*/
if (HIGH_CREDIT(prev))
run_time /= (CURRENT_BONUS(prev) ? : 1);
spin_lock_irq(&rq->lock);
/*
* if entering off of a kernel preemption go straight
* to picking the next task.
*/
if (unlikely(preempt_count() & PREEMPT_ACTIVE))
goto pick_next_task;
switch (prev->state) {
case TASK_INTERRUPTIBLE:
if (unlikely(signal_pending(prev))) {
prev->