@@ -21,8 +21,9 @@ chaos 是一个用 Rust 编写的基于 [2024 春夏季开源操作系统训练
21
21
进程是操作系统中资源管理的基本单位,而线程是操作系统调度的基本单位。在 chaos 中,进程由 ` Process ` 结构体表示,线程由所属进程统一管理,二者的底层实现都是一个 ` Task ` 结构体。每个进程拥有独立的内核栈,同一进程下的线程则共享进程内核栈空间。
22
22
23
23
#### 2.1.1 进程控制块
24
+
24
25
``` rust
25
- // os/src/task/process.rs
26
+ // os/src/task/process.rs
26
27
27
28
/// Process Control Block
28
29
pub struct ProcessControlBlock {
@@ -35,7 +36,7 @@ pub struct ProcessControlBlock {
35
36
进程被分为可变和不可变两个部分管理。不可变部分仅包含 ` PCB ` 创建时就被分配的 ` pid ` ,而对于可变那部分我们封装为 ` ProcessControlBlockInner ` 由于进程的父进程和其锁管理的线程都需要持有其所有权,我们使用Rust的智能指针 ` Arc ` 将其包裹以确保异步安全性,而 ` Arc ` 在Rust中默认不可变,因此我们管理 ` ProcessControlBlockInner ` 时利用了Rust的内部可变性。我们封装了 ` RefCell ` :
36
37
37
38
``` rust
38
- // os/src/sync/up.rs
39
+ // os/src/sync/up.rs
39
40
40
41
pub struct UPSafeCell <T > {
41
42
/// inner data
@@ -61,7 +62,10 @@ impl<T> UPSafeCell<T> {
61
62
` RefCell ` 是 Rust 标准库中的一个类型,提供了在运行时进行可变借用检查的能力。它允许在单线程环境中进行内部可变性(interior mutability)。` Sync ` 是一个标记 ` trait ` ,表示类型可以安全地在多个线程间共享引用。` RefCell ` 本身不是 ` Sync ` 的,因为它只在单线程环境中保证安全,因此我们通过 ` unsafe impl ` 声明,承诺 ` UPSafeCell ` 可以安全地在多线程环境中共享。在多核环境下,这种方法并不安全,只是一种在多核尚未实现的情况下的临时措施。
62
63
63
64
可变部分的内容如下:
65
+
64
66
``` rust
67
+ // os/src/task/process.rs
68
+
65
69
/// Inner of Process Control Block
66
70
pub struct ProcessControlBlockInner {
67
71
/// is zombie?
@@ -105,7 +109,10 @@ pub struct ProcessControlBlockInner {
105
109
每个成员的作用如注释所述。我们通过对子进程持强引用,对父进程持弱引用来防止循环引用造成的内存泄漏。
106
110
107
111
#### 2.1.2 线程控制块
112
+
108
113
``` rust
114
+ // os/src/task/task.rs
115
+
109
116
/// Task control block structure
110
117
pub struct TaskControlBlock {
111
118
/// immutable
@@ -119,7 +126,10 @@ pub struct TaskControlBlock {
119
126
和 ` PCB ` 的处理类似,我们也将 ` TCB ` 分为可变部分和不可变部分处理。这里不可变的部分是线程所属的父进程以及创建时就分配的内核栈位置,可变部分同样使用 ` UPSafeCell ` 管理。这里的实现是可以确保安全的,因为我们的OS仍是单核实现,且在我们的OS中, ` Task ` 作为程序执行的最小单位,也就是在多核环境下,一个 ` Task ` 只会在一个核心中执行。
120
127
121
128
可变部分的成员如下:
129
+
122
130
``` rust
131
+ // os/src/task/task.rs
132
+
123
133
pub struct TaskControlBlockInner {
124
134
/// Resources of a task
125
135
pub res : Option <TaskUserRes >,
@@ -162,7 +172,10 @@ chaos 采用了 stride 调度算法,算法描述如下:
162
172
#### 2.1.4 异常与中断
163
173
164
174
chaos 支持响应来自内核态的中断,我们在进入中断时,将中断入口设置为内核中断处理函数的入口,这样就保证可以正确的处理内核态中断。
175
+
165
176
``` rust
177
+ // os/src/trap/mod.rs
178
+
166
179
/// set trap entry for traps happen in kernel(supervisor) mode
167
180
fn set_kernel_trap_entry () {
168
181
extern " C" {
@@ -184,7 +197,10 @@ chaos 暂时沿用了 rCore 的双地址空间机制,即内核与用户拥有
184
197
#### 2.2.1 地址空间
185
198
186
199
chaos 使用 sv39 分页机制,拥有足够大的内存供内核与用户使用,因此我们直接指定了一个 ` MMAP_BASE ` (0x20000000)和 ` STACK_TOP ` (0x100000000)分别作为 mmap 的基地址和用户栈顶,将用户堆基地址固定放在应用程序 elf 文件末尾,并设置了一页的保护页
200
+
187
201
``` rust
202
+ // os/src/mm/memory_set.rs
203
+
188
204
let max_end_va : VirtAddr = max_end_vpn . into ();
189
205
let mut user_heap_base : usize = max_end_va . into ();
190
206
user_heap_base += PAGE_SIZE ;
@@ -195,6 +211,8 @@ user_heap_base += PAGE_SIZE;
195
211
在 chaos 中,内核与用户拥有各自的地址空间。内核的内存被恒等映射到了物理地址高处,而用户地址空间则是基于从elf文件中读取的数据进行物理页帧随机映射。在内核与用户相互切换时,需要用到一个跳板 ` TRAMPOLINE ` 页面,它被固定恒等映射到物理地址最高位处,且对于所有地址空间地址都相同,因此我们可以通过它来实现内核地址空间和用户地址空间之间的平滑切换。
196
212
197
213
``` linkerscript
214
+ // os/src/linker.ld
215
+
198
216
. = BASE_ADDRESS;
199
217
skernel = .;
200
218
stext = .;
@@ -205,12 +223,13 @@ user_heap_base += PAGE_SIZE;
205
223
*(.text.trampoline);
206
224
. = ALIGN(4K);
207
225
*(.text .text.*)
208
- }
209
226
```
210
227
211
228
关于物理页帧随机映射,我们使用了一个物理页帧分配器以管理所有物理页帧。对于单个物理页帧,我们遵循了 RAII 思想,这种思想也被广泛运用在我们内核的实现中。我们将一个物理页帧的生命周期绑定到一个 ` FrameTracker ` 变量上,当一个 ` FrameTracker ` 被创建的时候,我们需要从 ` FRAME_ALLOCATOR ` 中分配一个物理页帧:
212
229
213
230
``` rust
231
+ // os/src/mm/frame_allocator.rs
232
+
214
233
pub struct FrameTracker {
215
234
pub ppn : PhysPageNum ,
216
235
}
@@ -227,7 +246,10 @@ impl FrameTracker {
227
246
}
228
247
```
229
248
当一个 ` FrameTracker ` 生命周期结束被编译器回收的时候,我们需要将它控制的物理页帧回收到 ` FRAME_ALLOCATOR ` 中
249
+
230
250
``` rust
251
+ // os/src/mm/frame_allocator.rs
252
+
231
253
impl Drop for FrameTracker {
232
254
fn drop (& mut self ) {
233
255
frame_dealloc (self . ppn);
@@ -238,6 +260,8 @@ impl Drop for FrameTracker {
238
260
#### 2.2.3 内存管理相关数据结构
239
261
240
262
``` rust
263
+ // os/src/mm/memory_set.rs
264
+
241
265
/// address space
242
266
pub struct MemorySet {
243
267
/// page table
@@ -430,7 +454,7 @@ impl Fat32FS {
430
454
431
455
chaos 项目从初始化仓库到完成初赛的所有赛题,仅仅花费了一周的时间。在这七天里,我们实现了众多的 syscalls、文件系统的重构、 FAT32 的支持……这些成就,离不开队员们良好的沟通、相互的信任和夜以继日的努力。
432
456
433
- 在 chaos 的开发过程中,我们参考了许多优秀的开源项目,例如 [ Linux] ( https://github.com/torvalds/linux ) 、[ Titanix] ( https://github.com/greenhandzpx/Titanixhttps:// gitlab.eduxiji.net/202318123101314/oskernel2023-Titanix ) 、[ Main.os(2)(1)(1)] ( https://gitlab.eduxiji.net/202310008101520/oskernel2023-x ) 等。不过,我们仅参考了这些项目的优秀思想,代码均是自己实现。
457
+ 在 chaos 的开发过程中,我们参考了许多优秀的开源项目,例如 [ Linux] ( https://github.com/torvalds/linux ) 、[ Titanix] ( https://gitlab.eduxiji.net/202318123101314/oskernel2023-Titanix ) 、[ Main.os(2)(1)(1)] ( https://gitlab.eduxiji.net/202310008101520/oskernel2023-x ) 等。不过,我们仅参考了这些项目的优秀思想,代码均是自己实现。
434
458
435
459
如此短的开发时间,注定了 chaos 会存在许多潜在的问题以及一些功能的缺失。在未来的时间里,我们会逐步将 chaos 进行重构,朝着更为完整的操作系统内核前进。
436
460
0 commit comments