让我们考虑 2 个进程,P1 和 P2。 P2 已经让步,现在你在 P1 中。
现在在 P1 内部调用 yield()。让我们以此为您的上述起点。
从yield()获取ptable.lock后,调用sched(),在sched()内部,你会发现如下语句:
swtch(&p->context, mycpu()->scheduler);
这将从您当前进程的上下文切换到调度程序上下文。
当我这么说时,它会从下面的switchkvm() 内部scheduler() 继续下去
正如您所见,ptable.lock 发布后。接下来它会找到一个RUNNABLE进程并切换到它。所以在一个切换的过程中,下面scheduler()内部的执行一直发生到调用swtch(&(c->scheduler), p->context);
每当 P2 产生时,它都会使用 ptable.lock 并调用 sched()。在 sched() 内部,将调用 swtch 并切换到 scheduler() 的上下文。在 scheduler() 内部,它会从 switchkvm() 开始。
所以yield()内部进程上下文中获取的ptable.lock在scheduler()内部释放。
PS:请原谅我的英语。我不是母语人士。
下面是来自https://github.com/mit-pdos/xv6-public/blob/master/proc.c的代码sn-p
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for(;;){
// Enable interrupts on this processor.
sti();
// Loop over process table looking for process to run.
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->state != RUNNABLE)
continue;
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
switchuvm(p);
p->state = RUNNING;
swtch(&(c->scheduler), p->context);
//------------------------------------------------------------------------------
// This is where a context switch continues from.
switchkvm();
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
}
release(&ptable.lock);
}
}