Skip to content

Latest commit

 

History

History
90 lines (79 loc) · 8.54 KB

File metadata and controls

90 lines (79 loc) · 8.54 KB

2023a-rcore-put-down-crate-log

2023年秋冬季开源操作系统训练营第二阶段的日常学习记录

CH2 多道程序与分时多任务

总结:

一:**** 二:**** 三:****

1.手动内容

1.1. 克隆ci-user库到本地,并切换ch3分支

在2023a-rcore-put-down-crate目录下: git clone https://github.com/LearningOS/rCore-Tutorial-Checker-2023A.git ci-user git checkout ch3

2.本章关注点

2.0. 核心目标

2.0.1. 提高系统性能和效率

2.0.1.1. 通过提前加载应用程序到内存,减少应用程序切换开销
2.0.1.2. 通过协作机制支持主动放弃处理器,提高系统执行效率
2.0.1.3. 通过抢占机制支持程序被动放弃处理器,保证不同程序对处理器资源使用的公平性,也进一步提高了应用对I/O事件的响应效率

多道程序(Multiprogramming):只有一个程序执行完毕后或主动放弃扫许,处理器才能执行另外一个程序。这不就是独占串行运行么。

2.0.2. 协作式OS

让应用在执行 I/O 操作或空闲时,可以主动 释放处理器,让其他应用继续执行。当然执行 放弃处理器的操作算是一种对处理器资源的直接管理,所以应用程序可以发出这样的系统调用,让操作系统来具体完成。这样的操作系统就是支持 多道程序或 协作式多任务的协作式操作系统。 win3.x都算协作吧。

2.0.3. 抢占式OS

硬件中断机制可随时打断应用程序的执行,并让OS来完成对外设计I/O响应。 时间片 & 任务片 设计可完成硬件中断机制,也更需要第三方来进行机制的完成与监督。 这个第三方大概就是OS或者GC或者托管程序等等。 在编程语言中体现出来的概念应该就是各种锁了吧。

本章任务:构建支持多道程序及分时多任务,并归纳抽象出任务、任务切换等OS概念。

2.1. 多道程序放置与加载

2.1.0. 按编号一次性加载到内存中

2.1.1. 多道程序放置

所有应用的 ELF 格式执行文件都经过 objcopy 工具丢掉所有 ELF header 和符号变为二进制镜像文件,随后以同样的格式通过在操作系统内核中嵌入 link_user.S 文件(在此文件中进行序号指定及路径指定),在编译时直接把应用链接到内核的数据段中。不同的是,我们对相关模块进行了调整:在第二章中应用的加载和执行进度控制都交给batch 子模块,而在第三章中我们将应用的加载这部分功能分离出来在 loader 子模块中实现,应用的执行和切换功能则交给 task 子模块。目前应用程序的编址方式是基于绝对位置的,并没做到与位置无关,内核也没有提供相应的地址重定位机制。

NOTE:似乎需要补全user/build.py,至少与rCore-Tutorial-Book-v3 3.6.0-alpha.1本节不符

NOTE:需要补全user/build.py有对user/linker.ld的写操作,先备个份

2.1.2. 多道程序加载

所有应用在内核初始化时一并加载到内存需要加载到不同的物理地址,通过os/src/loader.rs/load_apps()实现

NOTE:os/src/loader.rs/load_apps()与至少与rCore-Tutorial-Book-v3 3.6.0-alpha.1本节不符,有代码补全

2.1.3. 执行应用程序

执行跳转到应用加载的内存位置需要设置应用程序返回的不同Trap上下文(Trap上下文中保存了放置程序起始地址的epc寄存器内容):
1.跳转到应用程序(编号i)的入口点entiry[i]
2.将使用的栈切换到用户栈stack[i]

2.2. 任务切换

2.2.0. 提高效率引入新概念

上节一个应用会独占 CPU 直到它出错或主动退出。操作系统还是以程序的一次执行过程(从开始到结束)作为处理器切换程序的时间段。为了提高效率,我们需要引入新的操作系统概念任务 、任务切换 、任务上下文。
当程序访问I/O外设或睡眠时,其实是不需要占用处理器的,于是我们可以把应用程序在不同时间段的执行过程分为两类,占用处理器执行有效任务的计算阶段和不必占用处理器的等待阶段。这些阶段就形成了一个我们熟悉的“暂停-继续…”组合的控制流或执行历史。从应用程序开始执行到结束的整个控制流就是应用程序的整个执行过程。

2.2.1. 任务的概念形成

任务切换,在内核中这种机制是在__switch函数中实现的。任务切换支持的场景是:一个应用在运行途中便会主动或被动交出CPU的使用权,此时它只能暂停执行,等到内核重新给它分配处理器资源之后才能恢复并继续执行。
只要任务切换的开销不大,那么处理器的执行效率就会大大提高。当然,这需要应用程序在运行途中能主动交出 CPU 的使用权,此时它处于等待阶段,等到操作系统让它再次执行后,那它就可以继续执行了。
到这里,我们就把应用程序的一次执行过程(也是一段控制流)称为一个任务 ,把应用执行过程中的一个时间片段上的执行片段或空闲片段称为计算任务片空闲任务片。当应用程序的所有任务片都完成后,应用程序的一次任务也就完成了。从一个程序的任务切换到另外一个程序的任务称为任务切换。为了确保切换后的任务能够正确继续执行,操作系统需要支持让任务的执行暂停继续。 “暂停-继续”组合。一旦一条控制流需要支持“暂停-继续”,就需要提供一种控制流切换的机制,而且需要保证程序执行的控制流被切换出去之前和切换回来之后,能够继续正确执行。这需要让程序执行的状态(也称上下文),即在执行过程中同步变化的资源(如寄存器、栈等)保持不变,或者变化在它的预期之内。不是所有的资源都需要被保存,事实上只有那些对于程序接下来的正确执行仍然有用,且在它被切换出去的时候有被覆盖风险的那些资源才有被保存的价值。这些需要保存与恢复的资源被称为 任务上下文 (Task Context) 。

NOTE:现场保护????

2.2.2. 不同类型的上下文与切换

需要结合硬件机制和软件实现来保存和恢复任务上下文。任务的一次切换涉及到被换出和即将被换入的两条控制流(分属两个应用的不同任务),通常它们都需要共同遵循某些约定来合作完成这一过程。 前面已经知道的两种上下文保存/恢复的实例:
第一章应用程序与基本执行环境中,我们介绍了函数调用与栈 。需要保存和恢复 函数调用上下文
第二章批处理系统中第一次涉及到了某种异常(Trap)控制流,即两条控制流的特权级切换,需要保存和恢复 系统调用(Trap)上下文

2.2.3. 任务切换的设计与实现:核心函数__switch & __restore

任务切换是Trap控制流切换之外的另一种异常控制流,都是描述两条控制流之间的切换,如果将它和Trap切换进行比较,会有如下异同:
1.与Trap切换不同,它不涉及特权级切换。 2.与Trap切换不同,它的一部分是由编译器帮忙完成的。 3.与Trap切换相同,它对应用是透明的。

NOTE:将任务切换视为异常的一种类型

从实现的角度讲, __switch 函数和一个普通的函数之间的核心差别仅仅是它会 换栈 。

包含持有关系:.data>>TaskManager全局实例TASK_MANAGER>>tasks>>TaskControlBlack>>TaskContext>>(ra寄存器==栈内指针 + sp寄存器==栈指针 + s寄存器s0-11 )

大致切换序列:trap>>save before task>>restore taskA>>switch taskA>>trap again

2.3. 多道程序与协作式调度

2.3.0. 关于任务概念相关

1.任务运行状态:任务从开始到结束执行过程中所处的不同运行状态:未初始化、准备执行、正在执行、已退出
2.任务控制块:管理程序的执行过程的任务上下文,控制程序的执行与暂停
3.任务相关系统调用:应用程序和操作系统之间的接口,用于程序主动暂停 sys_yield 和主动退出sys_exit

2.3.1. 多道程序背景与yield系统调用

2.3.2. 任务控制块与任务运行状态

2.3.3. 任务管理器

2.3.4. 实现sys_yield 和 sys_exit 系统调用

2.3.5. 第一次进入用户态

2.4. 分时多任务系统与抢占式调度

2.4.0.

2.4.1. RISC-V架构中的中断

2.4.2. 时钟中断与计时器

2.4.3. 抢占式调度