Skip to content

Commit 0607295

Browse files
committed
fix lab2 markdown
1 parent a0a9007 commit 0607295

File tree

1 file changed

+29
-28
lines changed

1 file changed

+29
-28
lines changed

docs/lab/lab2.md

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
本实验中,我们将引入进程的概念,并实现如下的进程**状态转换**逻辑。
66

7-
```mermaid fullWidth="false"
7+
```mermaid
88
graph TD
99
A[UNUSED]
1010
B[RUNNABLE]
@@ -17,6 +17,7 @@ B -- yield() --> C
1717
C -- wait() --> D
1818
D -- activate() --> B
1919
C -- exit() --> E
20+
2021
```
2122

2223
我们会先实现负责管理和调度进程的一系列内核库,然后创建一些简易的、运行在内核地址空间的进程。下一个实验,我们将结合页表,引入真正的、拥有独立地址空间的用户态进程。
@@ -98,9 +99,9 @@ typedef struct Proc {
9899
* `ucontext`:用户态上下文,用于保存用户态的寄存器信息,也称作 `trap frame`
99100
* `kcontext`:内核态上下文,用于保存内核态的寄存器信息。
100101

101-
{% hint style="success" %}
102-
**思考**:内核态上下文切换时,有哪些寄存器是一定要保存的?
103-
{% endhint %}
102+
> [!tip]
103+
>
104+
> **思考**:内核态上下文切换时,有哪些寄存器是一定要保存的?
104105
105106
进程退出时,将其子进程的父进程改为 `root_proc`。确保除了 root 的进程都有父进程,也就是所有的进程能够构成一棵树。
106107

@@ -115,9 +116,9 @@ typedef struct Proc {
115116

116117
因此操作系统引入了**调度器**的概念。
117118

118-
{% hint style="info" %}
119-
**注意:** 在我们的实验中,并不存在一个具体的调度器对象,调度器是由 `sched.c` 中的所有全局变量和函数一起组成的。
120-
{% endhint %}
119+
> [!info]
120+
>
121+
> **注意:** 在我们的实验中,并不存在一个具体的调度器对象,调度器是由 `sched.c` 中的所有全局变量和函数一起组成的。
121122
122123
调度器维护 CPU 和进程的调度信息,在进程请求调度时决定下一个运行什么进程,并执行进程切换。进程切换需要更新相关的调度信息,并进行上下文切换。
123124

@@ -133,41 +134,41 @@ typedef struct Proc {
133134

134135
本段将带大家过一遍进程的从创建到退出的整个流程。
135136

136-
{% hint style="info" %}
137-
涉及的具体理论知识请参考elearning上进程相关理论课内容。
138-
{% endhint %}
137+
> [!info]
138+
>
139+
> 涉及的具体理论知识请参考elearning上进程相关理论课内容。
139140
140141
当一段内核代码需要创建一个进程时,首先它应该处于init阶段之后,因为init阶段才完成进程树和调度器的初始化。
141142

142143
要创建进程的内核代码首先调用`create_proc`,分配空间并初始化进程结构体。此时进程处于`UNUSED`状态。
143144

144145
在进程启动之前,还可以对进程结构体的一些内容进行修改,如修改其父进程,修改其调度信息,修改初始寄存器值等。
145146

146-
{% hint style="success" %}
147-
**思考**:一般情况下,只能选择`root_proc`和当前进程为新进程的父进程,为什么?
148-
{% endhint %}
147+
> [!tip]
148+
>
149+
> **思考**:一般情况下,只能选择`root_proc`和当前进程为新进程的父进程,为什么?
149150
150151
随后调用`start_proc`启动进程。启动进程时,将为进程设置入口函数,并将其加入调度队列,状态更新为`RUNNABLE`。此时进程已经可以被调度。
151152

152153
进程被调度后,进入指定的进程入口函数,执行进程代码。
153154

154-
{% hint style="success" %}
155-
**思考**:真正的入口函数是`proc_entry`,然后才进入指定的入口函数,为什么要这样设计?
156-
{% endhint %}
155+
> [!tip]
156+
>
157+
> **思考**:真正的入口函数是`proc_entry`,然后才进入指定的入口函数,为什么要这样设计?
157158
158159
进程可以调用`wait``wait_sem`等函数,这些函数会在条件不满足时令进程陷入`SLEEPING`状态等待。它们都是通过配置好相关信息后调用`sched(SLEEPING)`实现的。
159160

160-
{% hint style="success" %}
161-
**思考**:直接调用`sched(SLEEPING)`会怎么样?
162-
{% endhint %}
161+
> [!tip]
162+
>
163+
> **思考**:直接调用`sched(SLEEPING)`会怎么样?
163164
164165
其他进程可以通过调用`activate_proc`唤醒处于`SLEEPING`状态的进程,这会将进程的状态更改为`RUNNABLE`并加入调度队列。
165166

166167
进程执行完毕后,应调用`exit`退出。`exit`将释放一些资源,将子进程全部转移给`root_proc`,然后调用`sched(ZOMBIE)`。此时进程处于`ZOMBIE`状态,不再执行,只保留一些基础的数据等待父进程在`wait`中回收。
167168

168-
{% hint style="success" %}
169-
**思考**:进程执行完毕后,直接`return`而不`exit`会怎样?
170-
{% endhint %}
169+
> [!tip]
170+
>
171+
> **思考**:进程执行完毕后,直接`return`而不`exit`会怎样?
171172
172173
进程的父进程可以调用`wait`释放`ZOMBIE`状态子进程的剩余资源,并释放进程结构体。`wait`将向父进程反馈子进程的退出代码和 PID 。
173174

@@ -179,9 +180,9 @@ typedef struct Proc {
179180
* **异常**(Exception):是指程序运行时发生错误,例如除 0 或者读取非法内存地址时发生的中断。
180181
* **陷入**(Trap):一般指由于软件指令,例如系统调用,使得用户态程序中断,进入内核态执行一些任务。也指在中断发生时,保存用户寄存器、执行特殊处理程序、恢复用户寄存器的过程。
181182

182-
{% hint style="info" %}
183-
事实上,不同平台(如x86-64,AArch64,RISC-V)对于以上三个概念的定义不甚相同,很多情况下甚至交替使用。
184-
{% endhint %}
183+
> [!info]
184+
>
185+
> 事实上,不同平台(如x86-64,AArch64,RISC-V)对于以上三个概念的定义不甚相同,很多情况下甚至交替使用。
185186
186187
通过配置相关寄存器,我们将所有 trap 的入口设定为 `trap_entry``trap_entry` 中需要保存 trap 的上下文,并调用 `trap_global_handler`
187188

@@ -195,9 +196,9 @@ typedef struct Proc {
195196

196197
**信号量**是操作系统解决并发中的互斥、同步问题的一种重要方法,基于信号量我们可以实现进程的 SLEEPING ,等待子进程唤醒等功能。
197198

198-
{% hint style="info" %}
199-
具体的实现可以参考 `src/common/sem.h``src/common/sem.c`
200-
{% endhint %}
199+
> [!info]
200+
>
201+
> 具体的实现可以参考 `src/common/sem.h``src/common/sem.c`
201202
202203
信号量维护了一个值 val 以及一个等待队列 sleeplist。val 提示此信号量的资源量,对于信号量的操作上分为P、V操作(对应wait、post)。通俗的理解post是生产、wait是消费
203204

0 commit comments

Comments
 (0)