进程切换
-
P1 进入内核,切换到调度器进程,调度器进程切换到 P2
-
核心函数为 swtch()函数;该函数保存并加载部分寄存器的值(RISC-V 中存在调用者保存并恢复的寄存器(caller-saved registers),不需要保存全部寄存器)
切换过程
-
yield 调用了 sched 函数
-
sched 函数进行合理性检查,最后调用 swtch 函数交换当前进程的上下文和 CPU 调度线程的上下文,返回地址为切换后上下文的 ra 寄存器存的值;实际上是 scheduler 函数
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; } -
调度器找到一个可运行的进程,再次运行 swtch 函数切换上下文, 此时的 ra 寄存器是之前是被定时器中断通过 sched 函数挂起的
void scheduler(void) { struct proc *p; struct cpu *c = mycpu(); c->proc = 0; for(;;){ // The most recent process to run may have had interrupts // turned off; enable them to avoid a deadlock if all // processes are waiting. intr_on(); 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->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); } } } -
第一次切换进程时,构造一个 forkret,allocproc 设置了 ra 和 sp 寄存器,forkret 本身只释放锁,调用 usertrapret