Thread-OS/Lab2

实现了在多个线程之间切换

Context *on_interrupt(Event ev, Context *ctx) {
  if (!current) {
    current = &tasks[0];  // First trap
  } else {
    current->context = ctx;
    current = current->next;
  }
  return current->context;
}

内核线程 v.s. 进程,还差了什么?

一个 VR 眼镜!


我们看到的世界未必真实

  • (进程也是)

进程的地址空间

pmap: 进程拥有 $[0,2^{64})$ 的地址空间

  • 但这个地址空间是 “虚拟” 的
  • 我们的物理内存也就是从 0 开始的几个 GB

地址翻译

  • 计算机系统中的一个数据结构 $f(x)$
    • 把虚拟内存地址翻译成物理内存地址
    • 由寄存器 (例如 x86 的 CR3) 和内存共同描述
  • 地址翻译 (VR 眼镜) 是强制的
    • 用户程序 mov CR3 将导致 #GP 异常
    • 越权访问/非法访问将导致 #PF 异常 (Page Fault)
    • 你看到的世界完全是操作系统的安排 (你害怕了吗)

AbstractMachine 对地址空间的抽象

是的,你没看错,AddrSpace 就是一个数据结构 $f$

  • 支持对数据结构的动态调整 (map)
  • 可以创建一个 “戴 VR 眼镜” 的 kcontext (线程)
    • 就是进程啦!

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);

虚假的地址空间 (1)

“映射了,但没有真的映射”

  • VR 眼镜:眼睛还没看到的地方可以先不显示

还记得 mmap 分配空间/映射磁盘的例子吗?

  • 操作系统只要用一个数据结构记录哪段内存是什么
    • 因此进程可以使用超过物理内存的虚拟内存 (swap)
  • Page Fault 的时候再分配
    • 文件 → 映射文件内容后返回
    • 匿名数据 → 分配物理页面后返回
    • 非法访问 → SIGSEGV
  • 用什么样的数据结构实现?
mmap.mmap(fd, prot=mmap.PROT_READ, length=128 << 30)

虚假的地址空间 (2)

“映射了很多次,但又只有一个”

  • 比 VR 眼镜高级的功能:多个位置共享同一块屏幕

我们相信:厉害的操作系统,同一份代码仅有一个副本

  • 如何间接证实这一点?
  • 如何直接确认这一点?
    • AskGPT: How to print the corresponding physical address of a given virtual address in Linux user space in C?

虚假的地址空间 (3)

“复制了,但没有完全复制”

  • 即便使用了很多内存,fork() 依然可以在瞬间完成
    • 复制 GB 级内存也需要数百 ms
    • 怎么做到的?

复制,很有可能白复制

  • fork-execve 非常常见
  • 刚复制完 1GB 内存,就销毁了
    • 操作系统:我不干这种事
    • 除了万不得已,能不复制就不复制
    • “写时复制” (copy-on-write)