xv6在sleep和wakeup的时候会发生进程切换,而且会周期性地在当进程在用户空间时发生进程切换。
上下文切换过程
上图展示了进程切换时的上下文切换的过程,首先一个用户进程通过中断或者系统调用陷入内核,此时发生用户态和内核态的切换,进程切换到自己的内核栈,再接着切换到上下文切换到调度器专属的内核栈,最后从调度器的内核栈切换到另一个用户进程的内核栈,最后从该内核栈返回用户态,即完成切换到了另一个用户进程。
在如下的sched函数中,就发生了上述中的过程,在sched中调用了swtch函数,可以看到传入swtch函数的参数有&p->context和mycpu()->scheduler,前者代表当前进程的上下文,而后者代表了当前cpu所对应的调度器的上下文。
// Enter scheduler. Must hold only ptable.lock
// and have changed proc->state. Saves and restores
// intena because intena is a property of this
// kernel thread, not this CPU. It should
// be proc->intena and proc->ncli, but that would
// break in the few places where a lock is held but
// there's no process.
void
sched(void)
{
int intena;
struct proc *p = myproc();
if(!holding(&ptable.lock))
panic("sched ptable.lock");
if(mycpu()->ncli != 1)
panic("sched locks");
if(p->state == RUNNING)
panic("sched running");
if(readeflags()&FL_IF)
panic("sched interruptible");
intena = mycpu()->intena;
swtch(&p->context, mycpu()->scheduler);
mycpu