🐳
uCore OS(on RISC-V64)实验指导书
  • Introduction
  • LAB0:ready~go!
    • 实验目的
    • 实验内容
    • 前导知识
      • 了解uCore
      • 了解RISC-V
      • 了解OS实验
      • 了解实验环境
      • 了解开发调试基本工具
      • 了解硬件模拟器
    • 配置环境
      • 安装虚拟环境
      • 安装开发工具
      • 安装硬件模拟器
      • 安装调试工具
  • LAB0.5:最小可执行内核
    • 实验目的
    • 实验内容
    • 练习
    • 内存布局
    • 链接脚本
    • 真正的入口点
    • 从SBI到stdio
    • 编译运行
    • 项目组成与执行流
  • LAB1:中断机制
    • 实验目的
    • 实验内容
    • 练习
    • RISC-V中断相关
    • 上下文处理
    • 中断处理程序
    • 时钟中断
    • 项目组成与执行流
  • LAB2:物理内存管理
    • 实验目的
    • 实验内容
    • 练习
    • 地址与页表
    • 物理内存探测
    • 以页为单位管理物理内存
    • 页面分配算法
    • 项目组成与执行流
  • LAB3:虚拟内存管理
    • 实验目的
    • 实验内容
    • 练习
    • 页面置换
    • PageFault
    • 使用多级页表
    • 页面置换机制
    • FIFO置换算法
    • 项目组成与执行流
  • LAB4:进程管理
    • 实验目的
    • 实验内容
    • 练习
    • 进程与线程
    • 相关结构体
    • 进程模块初始化
    • 进程切换
    • 项目组成与执行流
  • LAB5:用户程序
    • 实验目的
    • 实验内容
    • 练习
    • 用户进程
    • 用户程序
    • 创建并执行用户进程
    • 系统调用
    • 用户进程的退出和等待
    • 项目组成与执行流
  • LAB6:进程调度
    • 实验目的
    • 实验内容
    • 练习
    • 进程状态
    • 再次认识进程切换
    • 调度算法框架
    • 项目组成与执行流
  • LAB7:同步互斥
    • 实验目的
    • 实验内容
    • 练习
    • 同步互斥的基本概念
    • 信号量
    • 条件变量与管程
    • 项目组成与执行流
  • LAB8:文件系统
    • 实验目的
    • 实验内容
    • 练习
    • 文件系统介绍
    • 文件系统抽象层VFS
    • 硬盘文件系统SFS
    • 设备即文件
    • 从中断到终端
    • 项目组成与执行流
由 GitBook 提供支持
在本页

这有帮助吗?

  1. LAB6:进程调度

再次认识进程切换

我们在第四章已经简单了解过了在内核启动过程中进程切换的过程,在这一节我们再来重新回顾一下这些内容,并且深入讨论下其中的几个细节。

首先我们需要考虑的是,什么时候可以进行进程的切换。这里可以主要分为下面几种情况:

  1. 进程主动放弃当前的CPU资源,比如显式调用wait或sleep通知操作系统当前进程需要等待

  2. 进程想要获取的资源当前不可用,比如尝试获得未被释放的锁,或进行磁盘操作的时候

  3. 进程由于外部中断被打断进入内核态,内核发现某些条件满足(比如当前进程时间片用尽),进行进程切换

在我们实现的ucore中,内核进程是不可抢占的。这也就意味着当内核执行的时候,另一个内核进程不可以夺走它的的CPU资源。但这是不是就意味着一个内核进程执行的时候,它就会一直执行到结束呢?虽说内核进程不可以抢占,但是它可以主动放弃自己占有的CPU资源。如果不这样设计的话,内核当中很有可能出现各种死锁导致内核崩溃。

另一方面,内核不能相信用户进程不会无限执行下去,所以需要提供手段在用户进程执行的时候打断他,比如时钟中断。在ucore的实现中,用户进程可以随时被打断进入内核,操作系统会检查当前进程是否需要调度,从而把运行的机会交给别的进程。

由于内核进程是不可抢占的,所以我们在内核中有许多地方使用了显式的函数调用来进行调度,主要有以下几个地方:

函数

原因

proc.c/do_exit

用户进程退出,放弃CPU资源

proc.c/do_wait

用户进程等待,放弃CPU资源

proc.c/init_main

init线程会等待所有的用户线程执行完毕,之后调用kswapd内核线程回收内存资源

proc.c/cpu_idle

idle线程等待处于就绪态的线程,如果有就调用schedule

sync.c/lock

如果获取锁失败就进入等待

trap.c/trap

用户进程在被中断打断后,内核会检查是否需要调度,如果是则调用调度器进行调度

当用户进程A发生中断或系统调用之后,首先其中断帧会被保存,CPU进入内核态,执行中断处理函数。在执行完毕中断处理函数后,操作系统检查当前进程是否需要调度,如果需要,就把当前的进程状态保存,switch到另一个进程B中。注意在执行上面的操作的时候,进程A处于内核态,类似的,调度后我们到达的是进程B的内核态。进程B从系统调用中返回,继续执行。如果进程B在中断或系统调用中被调度,控制权可能转交给进程A的内核态,这样进程A从内核态返回后就可以继续执行之前的代码了。

上一页进程状态下一页调度算法框架

最后更新于4年前

这有帮助吗?