NJUOS-22-极限速通操作系统实验

本文最后更新于:2 年前

康康视频,纸面的知识,落在系统上,很多细节困难的昂!!!

复习

  • 你们是否感受到实验无从下手?
  • 写个操作系统也太难了吧?

本次课回答的问题

  • Q: 到底应该如何实现操作系统?

本次课主要内容

  • AbstractMachine 实验框架
  • 极简操作系统实验功能展示

速通任务简介

速通任务简介

实现一个真正的操作系统

  • 内核线程
    • 物理内存分配
    • 多处理器 (进程/线程绑定到处理器)
    • 支持内核信号量 P/V 操作
  • 用户态进程和系统调用
    • kputc - 打印字符
    • fork - 进程复制
    • sleep - 进程睡眠
    • 支持并不算太简单的uproc.c
  • 当然为了防止翻车,我作弊了 (事先实现过一遍了)

L0: AbstractMachine Game

复习:程序 = 状态机

数字电路是状态机


C 程序 (on AbstractMachine) 也是状态机

  • 状态 = stack frame 的列表 (每个 frame 有 PC) + 全局变量
  • 初始状态 = main(argc, argv), 全局变量初始化
  • 迁移 = 执行 top stack frame PC 的语句; PC++
    • 函数调用 = push frame (frame.PC = 入口)
    • 函数返回 = pop frame
  • 例子:非递归汉诺塔 hanoi-nr.c

AbstractMachine: TRM & IOE

基础状态机

  • 允许 “调试输出” 和 “终止”
1
2
3
extern Area  heap;
void putch (char ch);
void halt (int code);

输入/输出设备

  • 允许向设备寄存器的写入
1
2
3
4
bool ioe_init  (void);
void ioe_read (int reg, void *buf);
void ioe_write (int reg, void *buf);
#include "amdev.h"

L0: 实验要求与实现要点

在框架代码的基础上实现一个能动的游戏

1
2
3
4
5
6
while (1) {
while (!next_frame()) ;
update_input();
update_state();
update_gfx();
}

与 Hello World 本质相同

  • 速通:直接偷家
    • 甚至都不需要实现 printf

温馨提示

  • 是 RTFM/RTFSC 的好机会

L1: Physical Memory Management

AbstractMachine: MPE

共享内存多处理器状态机

  • 多个 C 语言状态机,拥有独立堆栈且共享内存
  • Data race = undefined behavior
    • atomic_xchg 是唯一的处理器间同步方法
1
2
3
4
bool mpe_init   (void (*entry)());
int cpu_count (void);
int cpu_current(void);
int atomic_xchg(int *addr, int newval);

L1: 实验要求与实现要点

实现 malloc/free 的内核版本

  • 速通:直接偷家
    • 一把大锁保平安 -> 多处理器相关的可能出现问题的地方,直接atomic!!!别给俺并发搞花的哈哈哈哈,真有你的jyy哈哈哈哈哈!!!
    • 只分配不回收
  • 注意要求
    • 按照 2k 边界对齐

温馨提示

  • 对自己的代码持最大程度的 “不信任”
    • 例如,在拆锁的时候保持所有的 assertions
  • 注意代码的可维护性

所有的技巧,可能确实很聪明,减少了时间。但是同时,每一次的“聪明”,都引入了复杂性昂!!!可维护性就差了,可能需要更多的assert来保证系统的安全性。

自己balance一下,技巧不是不能用,但是同时也要保证简单性昂!!!

可读性非常非常重要,多把锁请定义在一起,并且保证他们的Lock Order。

L2: Kernel Multithreading

AbstractMachine: CTE

管理 C 语言状态机执行的 “快照” (context)

  • 允许创建的状态机需要占用空间 (栈)
  • 允许主动让出处理器 (yield) 或外部中断

中断行为

  • 将当前状态机的 context 就地保存在栈上
  • 调用 cte_init 注册的 handler
  • 返回时可以恢复到任意一个 context
1
2
3
4
5
bool     cte_init(Context *(*handler)(Event ev, Context *ctx));
void yield (void);
bool ienabled(void);
void iset (bool enable);
Context *kcontext(Area kstk, void (*entry)(void *), void *arg);

CTE 和多处理器

处理器分别响应中断/异常

  • 关中断只能关闭当前处理器的中断

handler 执行时会使用当前执行流的堆栈

  • 因此被中断的线程在返回之前不能被调度到其他处理器
  • 可能导致非常 subtle 的 data race
    • Data race = undefined behavior

L2: 实验要求与实现要点

实现内核线程的创建和同步

  • 速通
    • 抄 thread-os
    • 一把大锁保平安
    • Just yield
      • P() 的语义:如果没有资源,则让出 CPU 等待

温馨提示

  • 并发有很多琐碎的细节
    • lock(a); lock(b) 的开关中断
    • lock(a); lock(a):AA型死锁(可重入)
    • 关中断,开中断时机
    • ……

参考一下Xv6的代码,是很好的昂!!!看看别人对的,是怎么写的昂!!!

L3: User Processes

AbstractMachine: VME

允许为 context 增加 “VR 眼镜”

  • protect/unprotect 管理地址空间
  • map 可以修改 VR 眼镜中的世界 (va 映射到 pa)
1
2
3
4
5
bool     vme_init (void *(*alloc)(int), void (*free)(void *));
void protect (AddrSpace *as);
void unprotect(AddrSpace *as);
void map (AddrSpace *as, void *va, void *pa, int prot);
Context *ucontext (AddrSpace *as, Area kstk, void *entry);

L3: 实验要求与实现要点

实现若干系统调用

  • kputc, sleep, fork, …
    • 你得到了一个真正的 “操作系统”!
  • 先创建一个没有任何地址空间映射的空进程
    • Demand Paging: 在缺页时现场分配

温馨提示

  • 资源管理
    • 引用计数/gc 是个好方法
  • 中断/异常的嵌套
    • 从关中断执行系统调用开始
    • 如果要处理,先从 “明显正确” 的方式开始

总结

本次课回答的问题

  • Q: 到底应该如何实现操作系统?

Take-away messages

  • 写操作系统没那么难嘛
    • 建立抽象 (例如 AbstractMachine)
  • 极限速通 != 正确的实现方法
    • 但可以帮助你理解概念 (例如什么是 P/V)
  • 防御性编程
    • 总是实现最简单的版本,并且把 assertions 带到后面

References

  1. vedio link: https://www.bilibili.com/video/BV1iY411A7w1/?spm_id_from=333.999.0.0&vd_source=ff957cd8fbaeb55d52afc75fbcc87dfd
  2. verbose的时候,可能需要一些有意义的临时变量,去进行操作昂!!!可以减少代码的复杂度呢!!!

NJUOS-22-极限速通操作系统实验
https://alexanderliu-creator.github.io/2023/01/11/njuos-22-ji-xian-su-tong-cao-zuo-xi-tong-shi-yan/
作者
Alexander Liu
发布于
2023年1月11日
许可协议