实验四(上):线程

优质
小牛编辑
146浏览
2023-12-01

实验四(上):线程

实验之前

  • 阅读实验指导四。
  • 从本次实验起,我们将不再提供“截至当前章节的代码框架”。你可以直接在 master 分支上查看代码,因为后面章节基本只会添加代码而鲜有修改。
  • 实验用到的代码在 lab-4 分支上,与 master 稍有修改。

实验题目

  1. 原理:线程切换之中,页表是何时切换的?页表的切换会不会影响程序 / 操作系统的运行?为什么?

    Click to show

    页表是在 Process::prepare_next_thread() 中调用 Thread::prepare(),其中换入了新线程的页表。

    它不会影响执行,因为在中断期间是操作系统正在执行,而操作系统所用到的内核线性映射是存在于每个页表中的。

  2. 设计:如果不使用 sscratch 提供内核栈,而是像原来一样,遇到中断就直接将上下文压栈,请举出(思路即可,无需代码):

    • 一种情况不会出现问题
    • 一种情况导致异常无法处理(指无法进入 handle_interrupt
    • 一种情况导致产生嵌套异常(指第二个异常能够进行到调用 handle_interrupt,不考虑后续执行情况)
    • 一种情况导致一个用户进程(先不考虑是怎么来的)可以将自己变为内核进程,或以内核态执行自己的代码
    Click to show
    • 只运行一个非常善意的线程,比如 loop {}
    • 线程把自己的 sp 搞丢了,比如 mv sp, x0。此时无法保存寄存器,也没有能够支持操作系统正常运行的栈
    • 运行两个线程。在两个线程切换的时候,会需要切换页表。但是此时操作系统运行在前一个线程的栈上,一旦切换,再访问栈就会导致缺页,因为每个线程的栈只在自己的页表中
    • 用户进程巧妙地设计 sp,使得它恰好落在内核的某些变量附近,于是在保存寄存器时就修改了变量的值。这相当于任意修改操作系统的控制信息
  3. 实验:当键盘按下 Ctrl + C 时,操作系统应该能够捕捉到中断。实现操作系统捕获该信号并结束当前运行的线程(你可能需要阅读一点在实验指导中没有提到的代码)

  4. 实验:实现进程的 fork()。目前的内核线程不能进行系统调用,所以我们先简化地实现为“按 F 进行 fork”。fork 后应当为目前的进程复制一份几乎一样的拷贝。

    旧题目:这个题目有一些问题,会导致线程中对栈上的指针失效。如果已经完成了 clone() 实验,推荐但不必须重新做 fork()

    实现线程的 clone()。目前的内核线程不能进行系统调用,所以我们先简化地实现为“按 C 进行 clone”。clone 后应当为目前的线程复制一份几乎一样的拷贝,新线程与旧线程同属一个进程,公用页表和大部分内存空间,而新线程的栈是一份拷贝。