本篇文章将向大家介绍一下riscv-xv6的进程调度的实现分析。
riscv-xv6进程调度发生的时机:xv6中进程为单线程的,进程是调度的单位。xv6采用的是抢占式时间片轮转(Round Robin)调度,分时系统的时间片到达或与硬件交互过程中需要等待从而阻塞当前进程(如read系统调用将当前进程的状态设为睡眠)让出cpu时需要调度在等待队列中的进程;
进程调度中的几个关键函数:2、scheduler,进程调度器,每个cpu共享这个调度器代码,但有独立运行的调度器,其内部会从进程表里循环遍历查找状态为”RUNNABLE”的进程并调用sched函数进行调度运行(不同CPU对应的调度器通过锁机制实现进程的安全访问),调度器内部执行的swtch函数,此时swtch首先保存cpu里的context状态,也就是当前运行的scheduler的cpu环境上下文,并加载马上在cpu上运行的进程的context上下文到cpu寄存器里。2、调度器外部执行的sched,在sched函数实现内部调用了swtch函数,该函数为当前的进程保存上下文(当前进程准备让出cpu执行,将ra,sp以及cpu的callee registers的寄存器状态保存到进程的结构体的context数据里),并加载cpu结构体数据里的context到cpu的寄存器里(cpu结构体里的context为scheduler函数上次调度进程执行时的上下文环境,从而恢复scheduler调度器的执行上下文,开始进程调度)。sched函数会在几个地方被调用:(1),进程退出,exit函数执行,调度可执行的进程开始运行;(2),进程阻塞到睡眠状态,调度其他进程执行;(3),当分时的定时器中断到来,发生trap时,kerneltrap和usertrap里通过调用yield函数让出当前进程的cpu执行权限(当前进程从RUNNING的状态更新为RUNNABLE的状态,即ready的可调度状态)。
关于sleep和wakeup的分析:1、sleep发生的可能的场合,硬件中断,如读写操作(异步交互通信,以及硬件共享时的竞态条件需要用到的睡眠锁等),需要阻塞进程异步等待消息准备好;2、sleep系统调用,让当前进程等待大约多少时间(可以以tickes的count为参数,可以参考实验[2]);3、wait系统调用,父进程会调用sleep等待子进程结束。wakeup被调用的时候基本为当阻塞的进程满足继续运行的条件,如硬件输入输出相关信息到达,包括定时器时间中断到达(定时器时间中断到达除了会唤醒相关进程到RUNNALBLE状态外,也会调用yield函数调度其他进程开始运行)。相关函数的实现可参考[3]
- [1]、进程调度相关代码参考和分析注释:riscv-xv6中的进程调度机制分析 · Issue #IBK1NI
- [2]、sleep系统调用实验: 实现Sleep — Kindlytree OCW 1.0 文档
- [3]、sleep,wait,wakeup等函数的实现及注释:https://gitee.com/kindlytree/riscv-xv6/issues/IBK1NI#note_36940442_link
Leave a Reply