第三章
-
通过提前加载应用程序到内存,减少应用程序切换开销
-
通过协作机制支持程序主动放弃处理器,提高系统执行效率
-
通抢占机制支持程序被动放弃处理器,提高不同程序对处理器资源使用的公平性,也进一步提高了应用对I/O事件的响应效率
-
在内存中尽量同时驻留多个应用,这样处理器的利用率就会提高。但只有一个程序执行完毕后或主动放弃执行,处理器才能执行另外一个程序。这种运行方式称为 多道程序 。
协作式操作系统
- 应用在执行IO操作时,可以主动 释放处理器 ,让其他应用继续执行。当然执行 放弃处理器 的操作算是一种对处理器资源的直接管理,所以应用程序可以发出这样的系统调用,让操作系统来具体完成。这样的操作系统就是支持 多道程序 协作式操作系统。
抢占式操作系统
- 我们可以把一个程序在一个时间片上占用处理器执行的过程称为一个 任务 (Task),让操作系统对不同程序的 任务 进行管理。通过平衡各个程序在整个时间段上的任务数,就达到一定程度的系统公平和高效的系统效率。在一个包含多个时间片的时间段上,会有属于不同程序的多个任务在轮流占用处理器执行,这样的操作系统就是支持 分时多任务 的抢占式操作系统。
多道程序放置与加载
多道程序放置
在第二章中应用的加载和进度控制都交给 batch 子模块,而在第三章中我们将应用的加载这部分功能分离出来在 loader 子模块中实现,应用的执行和切换则交给 task 子模块。
用脚本 build.py 而不是直接用 cargo build 构建应用的链接脚本:
1 # user/build.py
2
3 import os
4
5 base_address = 0x80400000
6 step = 0x20000
7 linker = 'src/linker.ld'
8
9 app_id = 0
10 apps = os.listdir('src/bin')
11 apps.sort()
12 for app in apps:
13 app = app[:app.find('.')]
14 lines = []
15 lines_before = []
16 with open(linker, 'r') as f:
17 for line in f.readlines():
18 lines_before.append(line)
19 line = line.replace(hex(base_address), hex(base_address+step*app_id))
20 lines.append(line)
21 with open(linker, 'w+') as f:
22 f.writelines(lines)
23 os.system('cargo build --bin %s --release' % app)
24 print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id)))
25 with open(linker, 'w+') as f:
26 f.writelines(lines_before)
27 app_id = app_id + 1
多道程序加载
所有的应用在内核初始化的时候就一并被加载到内存中。为了避免覆盖,它们自然需要被加载到不同的物理地址。这是通过调用 loader 子模块的 load_apps 函数实现的:
#执行应用程序
任务切换
- 那些对于执行流接下来的进行仍然有用,且在它被切换出去的时候有被覆盖的风险的那些资源才有被保存的价值。这些物理资源被称为 任务上下文 (Task Context) 。
- 把应用程序的一个计算阶段的执行过程(也是一段执行流)称为一个 任务 ,所有的任务都完成后,应用程序也就完成了。从一个程序的任务切换到另外一个程序的任务称为 任务切换 。
不同类型的上下文与切换
多道程序与协作式调度
#多道程序背景与 yield 系统调用
一个应用会持续运行下去,直到它主动调用 sys_yield 来交出 CPU 使用权。内核将很大的权力下放到应用,让所有的应用互相协作来最终达成最大化 CPU 利用率,充分利用计算资源这一终极目标。在计算机发展的早期,由于应用基本上都是一些简单的计算任务,且程序员都比较遵守规则,因此内核可以信赖应用,这样协作式的制度是没有问题的。
CPU 会将请求和一些附加的参数写入外设,待外设处理完毕之后, CPU 便可以从外设读到请求的处理结果。
#任务控制块与任务运行状态
#任务管理器
分时多任务系统与抢占式调度
#RISC-V 架构中的中断
中断 (Interrupt) 和我们第二章中介绍的 用于系统调用的 陷入 Trap 一样都是异常 ,但是它们被触发的原因确是不同的。对于某个处理器核而言, 陷入 与发起 陷入 的指令执行是 同步 (Synchronous) 的, 陷入 被触发的原因一定能够追溯到某条指令的执行;而中断则 异步 (Asynchronous) 于当前正在进行的指令,也就是说中断来自于哪个外设以及中断如何触发完全与处理器正在执行的当前指令无关。
- 如果中断的特权级低于 CPU 当前的特权级,则该中断会被屏蔽,不会被处理;
- 如果中断的特权级高于与 CPU 当前的特权级或相同,则需要通过相应的 CSR 判断该中断是否会被屏蔽。
#时钟中断与计时器
#抢占式调度