.globl swtch
swtch:
sd ra, 0(a0)
sd sp, 8(a0)
sd s0, 16(a0)
sd s1, 24(a0)
sd s2, 32(a0)
sd s3, 40(a0)
sd s4, 48(a0)
sd s5, 56(a0)
sd s6, 64(a0)
sd s7, 72(a0)
sd s8, 80(a0)
sd s9, 88(a0)
sd s10, 96(a0)
sd s11, 104(a0)
ld ra, 0(a1)
ld sp, 8(a1)
ld s0, 16(a1)
ld s1, 24(a1)
ld s2, 32(a1)
ld s3, 40(a1)
ld s4, 48(a1)
ld s5, 56(a1)
ld s6, 64(a1)
ld s7, 72(a1)
ld s8, 80(a1)
ld s9, 88(a1)
ld s10, 96(a1)
ld s11, 104(a1)
ret
还有进入sched后进程的锁在哪里释放。 如果有人能在这方面帮助我,那就太好了
原谅我糟糕的英语:)
void
sched(void)
{
int intena;
struct proc *p = myproc();
if(!holding(&p->lock))
panic("sched p->lock");
if(mycpu()->noff != 1)
panic("sched locks");
if(p->state == RUNNING)
panic("sched running");
if(intr_get())
panic("sched interruptible");
intena = mycpu()->intena;
swtch(&p->context, &mycpu()->context);
mycpu()->intena = intena;
}
以上代码由MIT 6.s081提供。 sched 首先检查进程锁,因此每次进程调用 sched 函数时,它的锁都必须被锁定。然后,sched调用swtch函数。根据 risc v 调用约定,
&p->context
将存储在 a0 寄存器中,&mycpu()->context
将存储在 a1 寄存器中。
毫无疑问,swtch 函数只是将一些寄存器(ra 存储返回地址,sp 指向当前堆栈和一些通用被调用者保存的寄存器)存储到当前进程的上下文中,加载新的上下文,然后跳转到ra寄存器中存储的地址,如果您熟悉sd、ld、ret指令的用法。
一个自然的问题是,哪个上下文存储在 mycpu()->context 上?让我们快速回顾一下调度程序功能。
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 nproc = 0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state != UNUSED) {
nproc++;
}
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->context, &p->context);
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
}
release(&p->lock);
}
if(nproc <= 2) { // only init and sh exist
intr_on();
asm volatile("wfi");
}
}
}
调度程序函数找到第一个RUNNABLE进程,然后调用swtch,将当前上下文存储到c->context。
因此,ret指令会让程序跳转到调度程序函数,这有助于释放锁并找到新的RUNNABLE进程。