所以本书的目标是以简洁的 RISC-V 架构为底层硬件基础,根据上层应用从小到大的需求,按 OS 发展的历史脉络,逐步讲解如何设计并实现满足这些需求的“从小到大”的多个“小”操作系统,并在设计实现操作系统的过程中,逐步解析操作系统各种概念与原理的知识点,对应的做到有“理”可循和有“码”可查,最终让读者通过主动的操作系统设计与实现来深入地掌握操作系统的概念与原理。
...
...
@@ -32,15 +32,15 @@ Remzi H. Arpaci-Dusseau 和 Andrea C. Arpaci-Dusseau 的《Operating Systems: Th
**目前常见的操作系统内核都是基于 C 语言的,为何要推荐 Rust 语言?**
- 没错, C 语言就是为写 UNIX 而诞生的。Dennis Ritchie 和 KenThompson 没有期望设计一种新语言能帮助高效简洁地开发复杂的应用业务逻辑,只是希望用一种简洁的方式抽象出计算机的行为,便于编写控制计算机硬件的操作系统,最终的结果就是 C 语言。
- C 语言的指针既是天使又是魔鬼,且 C 语言缺少有效的并发支持,导致内存和并发漏洞成为当前操作系统的噩梦。
- 事实上, C 语言就是为写 UNIX 而诞生的。Dennis Ritchie 和 KenThompson 没有期望设计一种新语言能帮助高效简洁地开发复杂的应用业务逻辑,只是希望用一种简洁的方式来代替难以使用的汇编语言抽象出计算机的行为,便于编写控制计算机硬件的操作系统。
- C 语言的指针既是天使又是魔鬼。它灵活且易于使用,但语言本身几乎不保证安全性,且缺少有效的并发支持。这导致内存和并发漏洞成为当前基于 C 开发的主流操作系统的噩梦。
- Rust 语言具有与 C 一样的硬件控制能力,且大大强化了安全编程。从某种角度上看,新出现的 Rust 语言的核心目标是解决 C 的短板,取代 C 。所以用 Rust 写 OS 具有很好的开发和运行的体验。
- 用 Rust 写 OS 的代价仅仅是学会用 Rust 编程。
**目前常见的指令集架构是 x86 和 ARM ,为何要推荐 RISC-V ?**
- 没错,最常见的的架构是 x86 和 ARM ,他们已广泛应用在服务器,台式机,移动终端和很多嵌入式系统中。它们需要支持非常多的软件系统和应用需求,导致它们越来越复杂。
- x86 的向过去兼容的策略确保了它的江湖地位,但导致其丢不掉很多已经比较过时的硬件设计,让操作系统疲于适配这些硬件特征。
- x86 和 ARM都很成功,这主要是在商业上,其广泛使用使得其 CPU 硬件逻辑越来越复杂,且不够开放,不能改变,不是开源的,提高了操作系统开发者的学习难度。
- 目前为止最常见的架构是 x86 和 ARM ,他们已广泛应用在服务器,台式机,移动终端和很多嵌入式系统中。它们需要支持非常多的软件系统和应用需求,导致它们越来越复杂。
- x86 后向兼容的策略确保了它的江湖地位,但导致其丢不掉很多已经比较过时的硬件设计,让操作系统疲于适配这些硬件特征。
- x86 和 ARM 在商业上都很成功,其广泛使用使得其 CPU 硬件逻辑越来越复杂,且不够开放,不能改变,不是开源的,提高了操作系统开发者的学习难度。
应用程序二进制接口 ABI 是不同二进制代码片段的连接纽带。ABI 定义了二进制机器代码级别的规则,主要包括基本数据类型,通用寄存器的使用,参数的传递规则,以及堆栈的使用等等。ABI 是用来约束链接器 (Linker) 和汇编器 (Assembler) 的。基于不同高级语言编写的应程序、库和操作系统,如果遵循同样的ABI定义,那么它们就能正确链接和执行。
应用程序二进制接口 ABI 是不同二进制代码片段的连接纽带。ABI 定义了二进制机器代码级别的规则,主要包括基本数据类型,通用寄存器的使用,参数的传递规则,以及堆栈的使用等等。ABI 是用来约束链接器 (Linker) 和汇编器 (Assembler) 的。基于不同高级语言编写的应用程序、库和操作系统,如果遵循同样的 ABI 定义,那么它们就能正确链接和执行。
应用程序编程接口 API 是不同源代码片段的连接纽带。API 定义了一个源码(如 C 语言)级函数的参数,参数的类型,函数的返回值等。因此 API 是用来约束编译器 (Compiler) 的:一个 API 是给编译器的一些指令,它规定了源代码可以做以及不可以做哪些事。API 与编程语言相关,如 LibC 是基于 C 语言编写的标准库,那么基于 C 的应用程序就可以通过编译器建立与 LibC 的联系,并能在运行中正确访问 LibC 中的函数。
应用程序编程接口 API 是不同源代码片段的连接纽带。API 定义了一个源码级(如 C 语言)函数的参数,参数的类型,函数的返回值等。因此 API 是用来约束编译器 (Compiler) 的:一个 API 是给编译器的一些指令,它规定了源代码可以做以及不可以做哪些事。API 与编程语言相关,如 LibC 是基于 C 语言编写的标准库,那么基于 C 的应用程序就可以通过编译器建立与 LibC 的联系,并能在运行中正确访问 LibC 中的函数。
对于实际操作系统而言,具有大量的服务接口,比如目前 Linux 有三百个系统调用接口。下面列出了一些相对比较重要的操作系统接口:
对于实际操作系统而言,具有大量的服务接口,比如目前 Linux 有三百个系统调用接口。下面列出了一些相对比较重要的操作系统接口或抽象:
再来看 CPU 虚拟化。不同的应用程序可以在内存中并发运行,相同的应用程序也可有多个拷贝在内存中并发运行。而每个程序都“认为”自己完全独占了 CPU 在运行,这是”时间虚拟化“。这其实也是操作系统给了运行的应用程序一个幻象。其实是操作系统把时间分成小段,每个应用程序占用其中一小段时间片运行,用完这一时间片后,操作系统会切换到另外一个应用程序,让它运行。由于时间片很短,操作系统的切换开销也很小,人眼基本上是看不出的,反而感觉到多个程序各自在独立”并行“执行,从而实现了 **时间虚拟化** 。
操作系统为了能够让 CPU 充分地忙起来并充分利用各种资源,就需要给很多任务给它去完成。这些任务是分时完成的,由操作系统来完成各个应用在运行时的任务切换。并发性虽然能有效改善系统资源的利用率,但并发性也带来了对共享资源的争夺问题,即同步互斥问题;执行时间的不确定性问题,即并发程序在执行中是走走停停,断续推进的。并发性对操作系统的设计也带来了很多挑战,一不小心就会出现程序执行结果不确定,程序死锁等很难调试和重现的问题。
操作系统为了能够让 CPU 充分地忙起来并充分利用各种资源,就需要给很多任务给它去完成。这些任务是分时完成的,由操作系统来完成各个应用在运行时的任务切换。并发性虽然能有效改善系统资源的利用率,但也带来了对共享资源的争夺问题,即同步互斥问题;执行时间的不确定性问题,即并发程序在执行中是走走停停,断续推进的。并发性对操作系统的设计也带来了很多挑战,一不小心就会出现程序执行结果不确定,程序死锁等很难调试和重现的问题。
- 第三章《多道程序与分时多任务》中,出于一些对于总体性能或者交互性的要求,从 CPU 的角度看,它在执行一个应用一段时间之后,会暂停这个应用并切换出去,等到之后切换回来的时候再继续执行。其核心机制就是 **任务切换** 。对于每个应用来说,它会认为自己始终独占一个 CPU ,不过这只是内核对 CPU 资源的恰当抽象给它带来的一种幻象。
你的电脑桌面是咋样的?是放满了图标吗?反正我的 windows 是这样的。显然很少人会真的吧可执行文件放到桌面上,桌面图标其实都是一些快捷方式。或者用 unix 的术语来说:软链接。为了减少工作量,我们今天来实现软链接的兄弟:[硬链接](https://en.wikipedia.org/wiki/Hard_link)。
你的电脑桌面是咋样的?是放满了图标吗?反正我的 windows 是这样的。显然很少人会真的把可执行文件放到桌面上,桌面图标其实都是一些快捷方式。或者用 unix 的术语来说:软链接。为了减少工作量,我们今天来实现软链接的兄弟:[硬链接](https://en.wikipedia.org/wiki/Hard_link)。