- OS 设计:怎么运行的
- xv6小型操作系统:实践经验
目标:
- 对硬件抽象
- 在许多应用程序中复用硬件(multiplexing)
- 进程隔离(并发
- 共享文件
- 安全系统/权限系统
- 不会阻碍应用程序的性能
结构

FS:文件系统
- 访问控制
内核-API:
内核态:操作系统启动后会一直执行的部分,比如文件访问
用户态:操作系统启动后,操作系统之上的程序执行的部分。比如qq,微信,浏览器
系统调用
- 打开文件:
open("filename", 1),系统会获取到open的参数,执行一些实现了open的内核代码 - 创建一个新线程:
pid = fork() - …
why hard and interesting
QEMU: 硬件模拟器
操作系统的困难:
- 解决一系列矛盾
- 高性能、高度抽象
- 责任重大(powerful)、易于使用(simple api)
- 灵活接口、安全的接口
有趣的点:
- 靠近计算机运行原理
- 靠近基础架构
- 便于你解决上层应用程序的bug,因为可能与操作系统特性有关
unix系统调用简介
系统调用时操作系统提供服务的接口
课程使用xv6并运行在RISC-V处理器上,不过这里使用QEMU模拟
read, write, exit

这个简单的程序使用了三个系统调用:
read:- 接受三个参数:文件描述符、指向内存的指针、读取最大长度
- 文件描述符:
0代表console的输入,1代表console的输出 - 返回值:读取到的字节数
write:- 接受参数和
read相同,只不过是向console输出
- 接受参数和
exit:程序返回,告诉操作系统自己的状态,并让操作系统杀死自己。
open调用
open调用会创建新的文件描述符。如果建立成功,会建立唯一的文件到设备的访问路径。调用失败会返回-1并设置全局变量errno指明失败原因。

open 调用必须指定以下文件访问模式之一:
- O_RDONLY:以只读方式打开;
- O_WRONLY:以只写方式打开;
- O_RDWR :以读写方式打开。
另外,还有以下几种可选模式的组合( 用按位或 || 来操作 ):
- O_APPEND:把写入数据追加在文件的末尾;
- O_TRUNC:把文件长度设置为零,丢弃已有的内容;
- O_CREAT:如果需要,就按照参数 mode 中给出的访问模式创建文件;
- O_EXCL:与 O_CREAT 一起使用,确保调用者创建出文件。使用这个模式可以防止两个程序同时创建同一个文件,如果文件已经存在,open 调用将失败。
Shell
fork调用

就是复制一份程序,执行后会有两个完全一样的进程,包括寄存器、内存,唯一的区别的进程编号pid。
fork后OS会选择一个执行,但创建新线程会产生额外的开销,所以概率上会先执行父线程。
fork后因为需要复制内存,所以会产生开销,但是可能不会使用这些内存,这产生了很多浪费,所以操作系统可能会在程序访问时创建内存。
在Shell中,shell会创建一个子线程处理,比如ls,mkdir,然后在子线程中调用exec系统调用执行。
exec

系统调用exec是以新的进程去代替原来的进程,原来的线程不复存在了,但程序的pid不变。可以理解成程序跑去执行另一个程序了,除非exec失败,后面的代码都不会执行。
在shell中不会使用exec执行,因为这会关闭shell,shell会fork一个子线程然后在子线程中执行exec。
wait
wait会让父线程等待子线程执行,会查看自己的子线程,只要有一个子线程运行结束了,父线程才会执行后面的代码。

如果存在多个子线程,即fork过多次,那么父线程需要wait多次。
IO 重定向
echo hello > out上面代码的功能是将echo程序执行的结果输出到out文件中
cat < out这个代码的功能是从out中读取然后让cat输出

图片中close(1)只会在子线程中执行,会将输出重定向,此时程序执行后会将内容写到output.txt中