我无法理解 xv6 中的这行代码
I can't understand this line of code in xv6
尽管查阅了文档,我仍然无法理解这一行:swtch(&c->scheduler, &p->context);
。
我的问题:我知道这一行是切换p->context,包括save registers和restore registers,但是我看不懂这个过程中pc
的变化,就是什么执行顺序这个代码? swtch(&c->scheduler, &p->context);
执行完后,是不是马上执行c->proc = 0;
,那么执行c->proc=p;
的效果就消失了?我现在很困惑。
代码link:https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/proc.c
第 456 行
*// Per-CPU process scheduler.*
*// Each CPU calls scheduler() after setting itself up.*
*// Scheduler never returns. It loops, doing:*
*// - choose a process to run.*
*// - swtch to start running that process.*
*// - eventually that process transfers control*
*// via swtch back to the scheduler.*
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for(;;){
*// Avoid deadlock by ensuring that devices can interrupt.*
intr_on();
int found = 0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
*// Switch to chosen process. It is the process's job*
*// to release its lock and then reacquire it*
*// before jumping back to us.*
p->state = RUNNING;
c->proc = p;
swtch(&c->scheduler, &p->context);
*// Process is done running for now.*
*// It should have changed its p->state before coming back.*
c->proc = 0;
found = 1;
}
release(&p->lock);
}
if(found == 0){
intr_on();
asm volatile("wfi");
}
}
}
从字面上看,这是一段令人困惑的代码,其原始作者在评论中写道“你不应该理解这个”,所以不要因为不理解它而难过。
您可能错过的关键是 p->context
包含一个地址,其中 swtch
用于恢复进程 p
的执行。例如,它的设置是 here:
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
因此,当调度程序调用 swtch 时,它实际上是在对 p->context.ra
指向的任何内容进行间接函数调用。该代码将无限期执行,然后最终(有点)return 到 swtch,return 到调度程序,调度程序继续 c->proc = 0
。
(在上面的句子中,“有点”和“有效”这两个词做了很多工作。要了解隐藏在这些词后面的是什么,接下来你应该阅读的是 coroutines .)
尽管查阅了文档,我仍然无法理解这一行:swtch(&c->scheduler, &p->context);
。
我的问题:我知道这一行是切换p->context,包括save registers和restore registers,但是我看不懂这个过程中pc
的变化,就是什么执行顺序这个代码? swtch(&c->scheduler, &p->context);
执行完后,是不是马上执行c->proc = 0;
,那么执行c->proc=p;
的效果就消失了?我现在很困惑。
代码link:https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/proc.c 第 456 行
*// Per-CPU process scheduler.*
*// Each CPU calls scheduler() after setting itself up.*
*// Scheduler never returns. It loops, doing:*
*// - choose a process to run.*
*// - swtch to start running that process.*
*// - eventually that process transfers control*
*// via swtch back to the scheduler.*
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for(;;){
*// Avoid deadlock by ensuring that devices can interrupt.*
intr_on();
int found = 0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
*// Switch to chosen process. It is the process's job*
*// to release its lock and then reacquire it*
*// before jumping back to us.*
p->state = RUNNING;
c->proc = p;
swtch(&c->scheduler, &p->context);
*// Process is done running for now.*
*// It should have changed its p->state before coming back.*
c->proc = 0;
found = 1;
}
release(&p->lock);
}
if(found == 0){
intr_on();
asm volatile("wfi");
}
}
}
从字面上看,这是一段令人困惑的代码,其原始作者在评论中写道“你不应该理解这个”,所以不要因为不理解它而难过。
您可能错过的关键是 p->context
包含一个地址,其中 swtch
用于恢复进程 p
的执行。例如,它的设置是 here:
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
因此,当调度程序调用 swtch 时,它实际上是在对 p->context.ra
指向的任何内容进行间接函数调用。该代码将无限期执行,然后最终(有点)return 到 swtch,return 到调度程序,调度程序继续 c->proc = 0
。
(在上面的句子中,“有点”和“有效”这两个词做了很多工作。要了解隐藏在这些词后面的是什么,接下来你应该阅读的是 coroutines .)