进程切换
在这一节中我们来看一看进程切换的全过程。
在ucore完成初始化后,ucore内核就没事做了,于是进入了“idle”的状态(这也是我们给第0个进程起名叫idle
的原因)。这是,它会陷入死循环,不断检查自己是否需要调度:
因为我们之前在初始化中把idle
进程的need_resched
设为了1
,所以其总会调用schedule
函数来检查是否有进程可以调度。我们已经初始化了另外一个内核进程,所以调度器发现了这个进程,并且准备调度到这个进程。
我们实现的schedule
函数非常的简单:当需要调度的时候,把当前的进程放在队尾,从队列中取出第一个可以运行的进程,切换到它运行。这就是FIFO调度算法。schedule
函数会调用proc_run
来唤醒选定的进程。proc_run
函数内部如下:
函数中主要进行了三个操作:
将当前运行的进程设置为要切换过去的进程
将页表换成新进程的页表
使用
switch_to
切换到新进程
switch_to
函数如下:
可以看出来这段代码就是将需要保存的寄存器进行保存和调换。在之前我们也已经谈到过了,这里只需要调换被调用者保存寄存器即可。由于我们在初始化时把上下文的ra
寄存器设定成了forkret
函数的入口,所以这里会返回到forkret
函数,进一步进入到forkrets
。forkrets
函数很短:
这里把传进来的参数,也就是进程的中断帧放在了sp
,这样在__trapret
中就可以直接从中断帧里面恢复所有的寄存器啦!我们在初始化的时候对于中断帧做了一点手脚,epc
寄存器指向的是kernel_thread_entry
,s0
寄存器里放的是新进程要执行的函数,s1
寄存器里放的是传给函数的参数。在kernel_thread_entry
函数中:
我们把参数放在了a0
寄存器,并跳转到s0
执行我们指定的函数!这样,一个进程的初始化就完成了。至此,我们实现了基本的进程管理,并且成功创建并切换到了我们的第一个内核进程。
lab4的代码可以在这里找到
最后更新于