Skip to content

Commit 2e993ce

Browse files
authored
Merge pull request #191 from h888866j/main
2 parents 942680f + 1b93f38 commit 2e993ce

File tree

12 files changed

+608
-608
lines changed

12 files changed

+608
-608
lines changed

source/chapter1/5support-func-call.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@
210210

211211
它的开头和结尾分别在 sp(x2) 和 fp(s0) 所指向的地址。按照地址从高到低分别有以下内容,它们都是通过 ``sp`` 加上一个偏移量来访问的:
212212

213-
- ``ra`` 寄存器保存其返回之后的跳转地址,是一个调用者保存寄存器
213+
- ``ra`` 寄存器保存其返回之后的跳转地址,是一个被调用者保存寄存器
214214
- 父亲栈帧的结束地址 ``fp`` ,是一个被调用者保存寄存器;
215215
- 其他被调用者保存寄存器 ``s1`` ~ ``s11`` ;
216216
- 函数所使用到的局部变量。
@@ -361,4 +361,4 @@
361361

362362
C 语言中的指针相当于 Rust 中的裸指针,它无所不能但又太过于灵活,程序员对其不谨慎的使用常常会引起很多内存不安全问题,最常见的如悬垂指针和多次回收的问题,Rust 编译器没法确认程序员对它的使用是否安全,因此将其划到 unsafe Rust 的领域。在 safe Rust 中,我们有引用 ``&/&mut`` 以及各种功能各异的智能指针 ``Box<T>/RefCell<T>/Rc<T>`` 可以使用,只要按照 Rust 的规则来使用它们便可借助编译器在编译期就解决很多潜在的内存不安全问题。
363363

364-
本节我们介绍了函数调用和栈的背景知识,通过分配栈空间并正确设置栈指针在内核中使能了函数调用并成功将控制权转交给 Rust 代码,从此我们终于可以利用强大的 Rust 语言来编写内核的各项功能了。下一节中我们将进行构建“三叶虫”操作系统的最后一个步骤:即基于 RustSBI 提供的服务成功在屏幕上打印 ``Hello, world!`` 。
364+
本节我们介绍了函数调用和栈的背景知识,通过分配栈空间并正确设置栈指针在内核中使能了函数调用并成功将控制权转交给 Rust 代码,从此我们终于可以利用强大的 Rust 语言来编写内核的各项功能了。下一节中我们将进行构建“三叶虫”操作系统的最后一个步骤:即基于 RustSBI 提供的服务成功在屏幕上打印 ``Hello, world!`` 。

source/chapter3/3multiprogramming.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

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

1717
这些都是三叠纪“始初龙”协作式操作系统 [#eoraptor]_ 需要具有的功能。本节的代码可以在 ``ch3-coop`` 分支上找到。
1818

source/chapter4/6multitasking-based-on-as.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@
560560
TASK_MANAGER.get_current_trap_cx()
561561
}
562562
563-
通过 ``current_user_token`` ``current_trap_cx`` 分别可以获得当前正在执行的应用的地址空间的 token 和可以在内核地址空间中修改位于该应用地址空间中的 Trap 上下文的可变引用
563+
通过 ``current_user_token`` 可以获得当前正在执行的应用的地址空间的 token 。同时,该应用地址空间中的 Trap 上下文很关键,内核需要访问它来拿到应用进行系统调用的参数并将系统调用返回值写回,通过 ``current_trap_cx`` 内核可以拿到它访问这个 Trap 上下文的可变引用并进行读写
564564

565565
改进 Trap 处理的实现
566566
------------------------------------
@@ -737,4 +737,4 @@
737737

738738
如果同学能想明白如何插入/删除页表;如何在 ``trap_handler`` 下处理 ``LoadPageFault`` ;以及 ``sys_get_time`` 在使能页机制下如何实现,那就会发现下一节的实验练习也许 **就和lab1一样** 。
739739

740-
.. [#tutus] 头甲龙最早出现在1.8亿年以前的侏罗纪中期,是身披重甲的食素恐龙,尾巴末端的尾锤,是防身武器。
740+
.. [#tutus] 头甲龙最早出现在1.8亿年以前的侏罗纪中期,是身披重甲的食素恐龙,尾巴末端的尾锤,是防身武器。

source/chapter5/4scheduling.rst

Lines changed: 590 additions & 590 deletions
Large diffs are not rendered by default.

source/chapter5/5exercise.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ challenge: 支持多核。
109109

110110
(1) fork + exec 的一个比较大的问题是 fork 之后的内存页/文件等资源完全没有使用就废弃了,针对这一点,有什么改进策略?
111111

112-
(2) [选做,不占分]其实使用了题(1)的策略之后,fork + exec 所带来的无效资源的问题已经基本被解决了,但是今年来 fork 还是在被不断的批判,那么到底是什么正在"杀死"fork?可以参考 `论文 <https://www.microsoft.com/en-us/research/uploads/prod/2019/04/fork-hotos19.pdf>`_ 。
112+
(2) [选做,不占分]其实使用了题(1)的策略之后,fork + exec 所带来的无效资源的问题已经基本被解决了,但是近年来 fork 还是在被不断的批判,那么到底是什么正在"杀死"fork?可以参考 `论文 <https://www.microsoft.com/en-us/research/uploads/prod/2019/04/fork-hotos19.pdf>`_ 。
113113

114114
(3) 请阅读下列代码,并分析程序的输出,假定不发生运行错误,不考虑行缓冲:
115115

source/chapter6/1fs-interface.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ Blocks 给出 ``os`` 目录也占用 8 个块进行存储。实际上目录也
195195
文件关闭
196196
++++++++++++++++++++++++++++++++++++++++++++++++++
197197

198-
在打开文件,对文件完成了读写操作后,还需要关闭文件,这样才让进程释放被这个文件所占用的内核资源。 ``close`` 的调用参数是文件描述符,但文件被关闭后,文件在内核中的资源会被释放,文件描述符会被回收。这样,进程就不能继续使用该文件描述符进行文件读写了。
198+
在打开文件,对文件完成了读写操作后,还需要关闭文件,这样才让进程释放被这个文件占用的内核资源。 ``close`` 的调用参数是文件描述符,当文件被关闭后,该文件在内核中的资源会被释放,文件描述符会被回收。这样,进程就不能继续使用该文件描述符进行文件读写了。
199199

200200
.. code-block:: rust
201201

source/chapter7/2pipe.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@
312312
313313
``PipeRingBuffer::read_byte`` 方法可以从管道中读取一个字节,注意在调用它之前需要确保管道缓冲区中不是空的。它会更新循环队列队头的位置,并比较队头和队尾是否相同,如果相同的话则说明管道的状态变为空 ``EMPTY`` 。仅仅通过比较队头和队尾是否相同不能确定循环队列是否为空,因为它既有可能表示队列为空,也有可能表示队列已满。因此我们需要在 ``read_byte`` 的同时进行状态更新。
314314

315-
``PipeRingBuffer::available_read`` 可以计算管道中还有多少个字符可以读取。我们首先需要需要判断队列是否为空,因为队头和队尾相等可能表示队列为空或队列已满,两种情况 ``available_read`` 的返回值截然不同。如果队列为空的话直接返回 0,否则根据队头和队尾的相对位置进行计算。
315+
``PipeRingBuffer::available_read`` 可以计算管道中还有多少个字符可以读取。我们首先需要判断队列是否为空,因为队头和队尾相等可能表示队列为空或队列已满,两种情况 ``available_read`` 的返回值截然不同。如果队列为空的话直接返回 0,否则根据队头和队尾的相对位置进行计算。
316316

317317
``PipeRingBuffer::all_write_ends_closed`` 可以判断管道的所有写端是否都被关闭了,这是通过尝试将管道中保存的写端的弱引用计数升级为强引用计数来实现的。如果升级失败的话,说明管道写端的强引用计数为 0 ,也就意味着管道所有写端都被关闭了,从而管道中的数据不会再得到补充,待管道中仅剩的数据被读取完毕之后,管道就可以被销毁了。
318318

source/chapter8/1thread-kernel.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
- 第 4~7 行我们声明线程函数接受的参数类型为一个名为 ``FuncArguments`` 的结构体,内含 ``x`` 和 ``y`` 两个字段。
8686
- 第 15 行我们创建并默认初始化三个 ``pthread_t`` 实例 ``t0`` 、 ``t1`` 和 ``t2`` ,分别代表我们接下来要创建的三个线程。
8787
- 第 16 行在主线程的栈上给出三个线程接受的参数。
88-
- 第 9~12 行实现线程运行的函数 ``func`` ,可以看到它的函数签名符合要求。它实际接受的参数类型应该为我们之前定义的 ``FuncArguments`` 类型的指针,但是在函数签名中是一个 ``void *`` ,所以在第 10 行我们我们首先进行类型转换得到 ``FuncArguments*`` ,而后才能访问 ``x`` 和 ``y`` 两个字段并打印出来。
88+
- 第 9~12 行实现线程运行的函数 ``func`` ,可以看到它的函数签名符合要求。它实际接受的参数类型应该为我们之前定义的 ``FuncArguments`` 类型的指针,但是在函数签名中是一个 ``void *`` ,所以在第 10 行我们首先进行类型转换得到 ``FuncArguments*`` ,而后才能访问 ``x`` 和 ``y`` 两个字段并打印出来。
8989
- 第 17~19 行使用 ``pthread_create`` 创建三个线程,分别绑定到 ``t0~t2`` 三个 ``pthread_t`` 实例上。它们均执行 ``func`` 函数,但接受的参数有所不同。
9090

9191
编译运行,一种可能的输出为:

source/chapter8/5concurrency-problem.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ A是共享变量。粗略地看,可以估计执行流程为:线程thr1先被
193193

194194
状态是安全的,是指存在一个资源分配/线程执行序列使得所有的线程都能获取其所需资源并完成线程的工作。如果找不到这样的资源分配/线程执行序列,那么状态是不安全的。这里把线程的执行过程简化为:申请资源、释放资源的一系列资源操作。这意味这线程执行完毕后,会释放其占用的所有资源。
195195

196-
我们需要知道,不安全状态并不等于死锁,而是指有死锁的可能性。安全全状态和不安全状态的区别是:从安全状态出发,操作系统通过调度线程执行序列,能够保证所有线程都能完成,一定不会出现死锁;而从不安全状态出发,就没有这样的保证,可能出现死锁。
196+
我们需要知道,不安全状态并不等于死锁,而是指有死锁的可能性。安全状态和不安全状态的区别是:从安全状态出发,操作系统通过调度线程执行序列,能够保证所有线程都能完成,一定不会出现死锁;而从不安全状态出发,就没有这样的保证,可能出现死锁。
197197

198198
.. chyyuu 有一个安全,不安全,死锁的图???
199199

source/chapter9/2device-driver-1.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@
156156
157157
.. chyyuu 在我们的具体实现中,与上述的一般中断处理过程不太一样。首先操作系统通过自定义的 ``SBI_DEVICE_HANDLER`` SBI调用,告知RustSBI在收到外部中断后,要跳转到的操作系统中处理外部中断的函数 ``device_trap_handler`` 。这样,在外部中断产生后,先由RustSBI在M Mode下接收的,并转到S Mode,交由 ``device_trap_handler`` 内核函数进一步处理。
158158
159-
在以往的操作系统实现中,当一个进程通过 ``sys_read`` 系统调用来获取串口字符时,并没有用上中断机制。但一个进程读不到字符的时候,将会被操作系统调度到就绪队列的尾部,等待下一次执行的时刻。这其实就是一种变相的轮询方式来获取串口的输入字符。这里其实是可以对进程管理做的一个改进,来避免进程通过轮询的方式检查串口字符输入。既然我们已经在上一章设计实现了让用户态线程挂起的同步互斥机制,我们就可以把自然地把这种机制也用来内核中,在外设不能及时提供资源的情况下,让想获取资源的线程或进程挂起,知道外设提供了资源,再唤醒进程继续执行
159+
在以往的操作系统实现中,当一个进程通过 ``sys_read`` 系统调用来获取串口字符时,并没有用上中断机制。但一个进程读不到字符的时候,将会被操作系统调度到就绪队列的尾部,等待下一次执行的时刻。这其实就是一种变相的轮询方式来获取串口的输入字符。这里其实是可以对进程管理做的一个改进,来避免进程通过轮询的方式检查串口字符输入。既然我们已经在上一章设计实现了让用户态线程挂起的同步互斥机制,我们就可以把这种机制也用在内核中,在外设不能及时提供资源的情况下,让想获取资源的线程或进程挂起,直到外设提供了资源,再唤醒线程或进程继续执行
160160

161161
目前,支持中断的驱动可有效地支持等待的进程唤醒的操作。以串口为例,如果一个进程通过系统调用想获取串口输入,但此时串口还没有输入的字符,那么操作系统就设置一个进程等待串口输入的条件变量(条件变量包含一个等待队列),然后把当前进程设置等待状态,并挂在这个等待队列上,再把CPU让给其它就绪进程执行。对于串口输入的处理,由于要考虑中断,相对就要复杂一些。读字符串的代码如下所示:
162162

0 commit comments

Comments
 (0)