-
Notifications
You must be signed in to change notification settings - Fork 452
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'rcore-os:master' into master
- Loading branch information
Showing
120 changed files
with
5,648 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--- | ||
title: 2024 秋冬季开源操作系统训练营第一 & 二阶段总结 - 冰轩 | ||
date: 2024-11-10 16:19:54 | ||
tags: | ||
- author: BingXuanOwO | ||
- repo: https://github.com/LearningOS/2024a-rcore-BingXuanOwO | ||
--- | ||
|
||
## 前言 | ||
|
||
这次加入训练营的前因来自于两位朋友曾断断续续提到了 rCore,以及这个与 rCore 有关的 OS 训练营。 | ||
|
||
关于 Rust,我曾抱着将信将疑的态度。在社交媒体上关于此的风评给我的感受来讲,就好像万物皆可被该语言重写,这个语言能解决一切编程问题。而包括这种偏见在内等原因,我却没有对 Rust 有太多了解。 | ||
|
||
而至于 OS,我曾因观看过蒋炎岩的 OS 课程而对 OS 略知一二,但却一拖再拖,因各种原因没有完整的学完全部课程以及做完 labs。 | ||
|
||
我想,是时候改变这一切了。我最终报名加入了进来。 | ||
|
||
<--! more --> | ||
|
||
## PT1. 初次上手 Rust 与 Rustlings | ||
|
||
在报名之后,接下来的第一个任务便是完成 Rustlings 全部 110 道题目,以此形成对 Rust 初步的认识。Rust 的基础语法适应起来很快,但是最重要的还是适应 Rust 最核心的 borrow,所有权等一系列与 RAII 相关的设计。虽然碍于 Rustlings 篇幅受限,我没能完整掌握这方面,不过这部分知识还是在 rCore 的实验中补回来了的。 | ||
|
||
最终,我成功完成了全部的 rustlings 题目,并晋级至重要的下一阶段——rCore。 | ||
|
||
## PT2. rCore 之旅 | ||
|
||
接下来要完成的,便是相对而言更为重要的 rCore。一路上磕磕绊绊不少,但还是完成了挑战。 | ||
|
||
首先是 Lab1,Lab1 的任务主要是理清 rCore 原有的代码结构。我在刚看到 rCore 的框架代码的时候,老实讲的确会感觉无从下手。不过,在我花上一段时间了解原本的代码结构,理解调度部分的实现后,就没感觉问题很大了。这中间有个小插曲--由于我一开始看错了题目,我一开始以为 syscall_times 部分记录的是每次 syscall 调用时对应进程运行的时间,但是后来发现其实是每种 syscall 调用的次数。 | ||
|
||
接下来是 Lab2。因为 Lab2 的框架代码已经提前实现了多种用于内存管理的 struct,我最开始的想法是直接在内存的 PTE 上做文章。但我后续发现,在不对框架原有分配部分不做出大变动的情况下,这种想法似乎并不可行。我好像又有点手足无措,不过思考过后,我最终想到遍历 `MemorySet` 中全部 `MapArea` 区间计算并调整区间的方案,总算实现了 map 和 unmap 的 syscall。 | ||
|
||
Lab2 中重写 `sys_get_time` 和 `sys_task_info` 的部分就相对容易些,我实现的方案是按照对应函数所需返回值的大小,对于每个可能包含该变量的虚拟页,反查用户空间对应的物理页,并从内核 0x10000 虚拟页处开始分配虚拟页表然后 map 到对应的物理页。Lab2 原本这部分的实现实际上每次 map 后都不会 unmap 掉, 而是在接下来继续 map 的时候从上一次分配的末尾处 map。但在后面的 Lab 中,由于分配量超出预期,从而会导致其尝试 map 已经在别处分配了的 PTE。到问题发现之后,我添加了 unmap 部分,并使分配都从 0x10000 开始,以此解决了问题。 | ||
|
||
随后便是 Lab3,相对而言其实还算简单,stride 部分只需要参照题目描述实现。而至于 spawn 部分,可以参照已实现的 fork 与 exec 部分,这样照葫芦画瓢也同样能较为轻松的实现出来。 | ||
|
||
而接下来的 Lab4,由于项目结构又一次进行了变化,引入了一个新的 easy-fs 库,从而又感到了和刚进行 Lab1 时,没法理解代码结构时的头疼。而在进行 Lab4 的过程中,因为不知为何导致的死锁,我又一次头疼不已,甚至一度想放弃。好在最后因为 Rust RAII 的特性,通过封装一层函数的方式,将某个我并不知情的引用自动 drop 掉,才最终解决了问题。 | ||
|
||
最后,到了 Lab5,rCore 阶段要结束了。虽然这次我并没有选择将检测死锁的部分独立拆分为单独的 crate,但这部分仍然先在裸机上开发,完成后再移植进内核。由于是直接在裸机上开发,整体调试起来也会方便很多。不过话虽如此,在刚开始的时候,由于我开始进行 Lab5 的时间早于这次线程相关课程的上课时间,且题目没有详尽地描写检测死锁的算法,以及对算法的不熟悉,导致我在这里卡住了很久没有进展。不过最后,我确定了题目给出的算法为 Dijkstra 的银行家算法,在不断的了解这个算法后,最终完成了 Lab5。 | ||
|
||
_至此,一锤定音。_ | ||
|
||
_尘埃,已然落定。_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
title: 2024-秋冬季开源操作系统训练营第一二阶段总结-wang.md | ||
date: 2024-11-10 11:14:20 | ||
tags: | ||
--- | ||
|
||
|
||
## 第一阶段总结 | ||
|
||
因为之前已经在学校里学习过Rust的内容,第一阶段更像是起到一个查缺补漏和复习的作用。通过完成Rustlings的100道练习题,对Rust生命周期、所有权机制、智能指针、移动语义等内容有了更深入的理解。 | ||
|
||
|
||
## 第二阶段总结 | ||
- lab3: 实现syscall: sys_get_time(), sys_task_info() | ||
- lab4: 引入虚拟内存/分页机制,重新实现sys_get_time()和sys_task_info(), 实现mmap和munmap | ||
- lab5: 将task抽象为process进程,实现sys_spawn()和stride调度算法 | ||
- lab6: 新增文件系统,可以将原来在内存中的数据持久化到硬盘上。 实现sys_linkat(), sys_unlinkat(), sys_stat() | ||
- lab8: 引入thread。实现死锁检测,实现sys_enable_deadlock_detect() | ||
通过完成5个操作系统的实验,对操作系统的基本原理有了更深入的理解。在实验过程中,我遇到了很多问题,比如在实验四中,我在实现文件系统时,由于对文件系统Inode/OSInode/DiskInode/File之间的关系和概念理解不够透彻,一开始写lab的时候确实是完全不知道该怎么做,也导致了一些错误。于是我认真阅读了实验手册,通过画图和总结,最终完成了lab。 | ||
lab1-3个人认为是相对简单的,几乎每一个的pattern都是先去某个struct添加一个新的field,然后在impl中对这个新的field进行一些需要的操作。这其中还可能涉及用户态与内核态之间的数据传递,比如在lab1中的sys_task_info()函数就涉及到内核态数据到用户态数据之间的传递。 | ||
总之,通过这次训练营,我对操作系统的原理有了更深入的理解,也对Rust的应用有了更多的实践经验。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
title: 2024-秋冬季开源操作系统训练营第一二阶段总结-陈栩民 | ||
date: 2024-11-09 18:53:04 | ||
categories: | ||
- 2024秋冬季开源操作系统训练营 | ||
tags: | ||
- author:yumu20030130 | ||
- repo:https://github.com/LearningOS/2024a-rcore-yumu20030130 | ||
--- | ||
|
||
# 前言 | ||
我是来自华中科技大学计算机科学与技术专业的一名本科生,课堂上做过类似的操作系统实验,但当时忙于其他事情,只是草草应付了事,所以想趁着这个机会,重新详细认识一下操作系统的基本逻辑,也学习一下rust这门语言。 | ||
|
||
# 第一阶段 | ||
主要参考资料:https://course.rs/basic/intro.html | ||
|
||
之前日常学习都是c和c++写得多,习惯了各种指针等非常自由的操作,遇到rust确实非常不适应,感觉编译器时时刻刻都要和我作对,我明明知道这么写没问题,但编译器就是不让。 | ||
但是随着我对于所有权、借用引用、生命周期这些核心概念的了解,慢慢我也体会到了rust这种“安全编程”带来的好处(后面写操作系统实验时,也比之前课堂上用c写bug少了很多)。 | ||
此外,“万物皆是模式匹配”的思想,也让整个编程风格看起来优雅了许多。 | ||
|
||
# 第二阶段 | ||
## Lab 1 | ||
一开始接触这个系统,主要还是不太了解rust的rs文件之间是如何包含的,在引用一个外部模块时,实际上这个查询路径是怎样的。 | ||
|
||
如果是在c语言中,就是很自然地,只要有对应的PATH环境变量,根据对应的相对路径去include就可以了,但在rust里面,是通过各个目录下一个名为mod.rs的文件去形成一个文件树的,各种文件以什么程度可见,都由mod.rs控制。 | ||
|
||
具体见:https://skyao.io/learning-rust/docs/build/module/rust-module-system-explanation/ | ||
|
||
核心在于这句话: | ||
|
||
当执行mod my_module;则编译器可以在同一目录下寻找到 my_module.rs 或 my_module/mod.rs 。 | ||
|
||
## Lab2 | ||
|
||
在这个实验被一个小问题卡了很久。 | ||
```rust | ||
let start: usize = 0x10000000; | ||
let len: usize = 4096; | ||
let prot: usize = 3; | ||
assert_eq!(0, mmap(start, len, prot)); | ||
assert_eq!(mmap(start + len, len * 2, prot), 0); | ||
``` | ||
上面的代码会在第二个mmap是触发如下错误: | ||
```rust | ||
let pte = self.page_table.find_pte(start); | ||
if pte.is_some() { | ||
println!("conflict_vpn: {:?}", start); | ||
return -1; | ||
} | ||
``` | ||
当时百思不得其解,自己造了一些其他测试,发现下面这样的操作居然不会报错: | ||
```rust | ||
let start: usize = 0x10000000; | ||
let len: usize = 4096; | ||
let prot: usize = 3; | ||
assert_eq!(0, mmap(start - len, len, prot)); | ||
assert_eq!(mmap(start, len * 2, prot), 0); | ||
``` | ||
这两个测试有什么区别,我仔细思考了一下虚拟地址转换为物理地址的过程,怎么使用多级页表一步步得到最终的物理页,结合这个如此“整数”的start,我发现了它们的区别很有可能在于,第二个测试,两个请求会处在不同的子页表中,而第一个测试则都在同一个子页表。因此,我终于开始详细看find_pte的流程,发现它是只要找到对应页表项就会返回,不会判断该页表项是否Valid。 | ||
|
||
那么此时,如果某个子页表已经分配,只是对应页表项不Valid,那么conflict的判断就会失误。 | ||
|
||
这个故事告诉我们:不要主观臆测一个函数的用途,在使用一个函数之前,一定要确切知道它的输入输出表示什么意思。 | ||
|
||
此外,也不应该使用find_pte函数,本来这个函数就不是pub的,有一个判断了是否Valid的封装好了的函数供使用。 | ||
|
||
## Lab3 | ||
|
||
这个lab挺简单的,就看懂fork和exec的执行逻辑之后,找到那些二者都改了的数据,只执行exec的对应改动,减少无意义的赋值。 | ||
|
||
stride算法,我使用了一个溢出标记的方法来防止溢出,即计算某个进程的stride值加完之后溢出了,就把该进程标记一下,之后都不考虑调度它,直到所有进程都溢出了。其实这样徒增了很多计算量,问答作业中的方法其实才是比较好的解法: | ||
|
||
思想大致如下,没实际运行过,可能有一些细节上的问题: | ||
```rust | ||
impl PartialOrd for Stride { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
let a = (self.0 & 0xff) as u16; | ||
let b = (other.0 & 0xff) as u16; | ||
if (a > b && a < b + 255 / 2) || (a < b && a + 255 / 2) < b { | ||
Some(Ordering::Greater) | ||
} else { | ||
Some(Ordering::Less) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Lab4 | ||
|
||
这个实验做的时候遇到很多多重借用的错误,一个比较好的编程习惯是,在函数A调用一个函数B之前,先看看B里面有没有对什么进行了借用,如果有,注意先在调用之前把对应的借用drop掉。 | ||
|
||
## Lab5 | ||
|
||
银行家算法,增减数据的时候记住,allocated + remian = all,有bug的时候就多看看这个规则有没有违背。以及记得在获得对应数据之后减need。 | ||
|
||
## 总结 | ||
这些实验确实都聚焦在了操作系统中基本且核心的问题,而且架构也是循序渐进,让人能够慢慢了解虚拟化、进程线程、文件系统这些都是怎么一步步得来的,感觉受益匪浅。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
title: 2024 秋冬季开源操作系统训练营第一阶段总结-DFP-HN | ||
date: 2024-11-10 14:01:09 | ||
tags: | ||
- author: DFP-HN | ||
- repo: https://github.com/LearningOS/rust-rustlings-2024-autumn-DFP-HN | ||
--- | ||
# 第一阶段总结 | ||
第一阶段训练营通过写一些rust的基本语句,快速入门rust,掌握了rust的基本语法。第一阶段的题目设置非常合理,对于rust零基础的也能快速入门,只需要一步一步按照文档上的学习就能轻松完成题目。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
title: 2024 秋冬季开源操作系统训练营第二阶段总结-DFP-HN | ||
date: 2024-11-10 13:57:28 | ||
tags: | ||
- author: DFP-HN | ||
- repo: https://github.com/LearningOS/2024a-rcore-DFP-HN | ||
--- | ||
# 第二阶段总结 | ||
第二阶段的题目略有难度,我在这个阶段有了很大的收获。第三章的练习是获取当前任务的信息,通过这个练习,大致清楚了进程在操作系统中的运行流程以及组成结构,系统调用的实现和中断的实现。第四章的练习考察对页表的理解,在完成的过程中加深了我对虚拟地址和物理地址的理解。第五章的练习是实现一个子进程的创建,fork+exec也能生成一个子进程,但这个子进程的资源和空间与父进程完全一致,然而练习的要求需要子进程有独立的数据,如果采用fork+exec将浪费很多时间去重新加载数据。第六章的练习是关于文件系统,创建硬链接和取消硬链接,这一章节对我来说有点挑战,因为之前学操作系统对于文件系统这一块就没太搞懂,认真看了几个晚上的代码后才搞懂文件系统的结构,收获非常大。第八章练习比前面的轻松一些,只要搞清楚了代码中各个结构之间的关系,就能轻松解决。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
title: 2024_第二阶段总结_ghost | ||
date: 2024-11-10 20:14:22 | ||
tags: | ||
- author:<ghostdragonzero> | ||
- repo:<https://github.com/LearningOS/2024a-rcore-ghostdragonzero> | ||
--- | ||
|
||
# 一、前言 | ||
|
||
毕业之后一直工作都是在做c嵌入式驱动开发,是和同事闲聊的时候了解这个项目的就开始学下去了 从2024春季就已经开始学了但是因为一些事情耽误了就没有完成 | ||
对我个人来说主要是好奇想看看经常看到的所谓写操作系统是做什么,以及我在工作中也会看到rust的一些内容对这个语言也很好奇 | ||
# 二、基础阶段 | ||
|
||
![错误记录](1-1.png) | ||
|
||
在基础学习的时候我认为这样的错误记录是很有必要的 | ||
因为我基础并不好经常对于书上看到的方法看到就忘了 实际写起来我最大的感受就是 | ||
1、如果有多个数据结构嵌套我很容易就搞不清哪里要复制哪里不复制 | ||
2、闭包按照我理解就是一个函数指针 在传递闭包的时候一开始没理解总是搞不清楚到底是怎么回事 | ||
|
||
**以及在完成一阶段之后我才安装了rust-analyer也算是踩坑了把 有这个插件才发现可以很快就发现错误不用在一次次编译** | ||
|
||
# 三、OS专业阶段 | ||
|
||
专业阶段在整个学习的过程中对我而言最困难的是第四章和第八章 | ||
在第四章 我觉得内存的边界条件卡住了很久 主要还是理解不够 明白了 地址空间 应用空间 需要转换 | ||
也看明白了虚拟地址的寻址方法 但是真的感觉新的文档没有图我一开始没理解的就是 他三级页表怎么寻址的过程 | ||
后面才真的理解上一级页表的值代表的是下一级要去找的page 再再下一级page上找到对应页表项 才实现了多级页表的寻址 | ||
![三级页表](3-1.png) | ||
|
||
整体来说我觉得这个专业阶段 首先文档需要图 | ||
并且我发现只看一遍效果很差 需要边看边记 并且对于代码讲解最好是能够记录并且依次添加注释 明白每一步再做什么不是只看文档中的讲解就过一遍就结束 | ||
![结构体关系](3-2.jpg) | ||
以及我觉得再实验过程中最重要的是搞清楚各个结构体所代表的实际意义 | ||
并且可以集中在图上展示 不然我在做ch6一开始总是错就是 没梳理清楚 disk_inode inode OS_inode还有目录项分别都是些什么 导致ch6经常找错 | ||
于是我就在草稿纸上根据理解写了我对于这些数据结构的理解和关联很快就解决了 | ||
|
||
实验的时候还有一点 有时候我总喜欢通过结构体之间的关系来找对应的数据 但是在rust里这样做我觉的很复杂 | ||
最好的方式就是在容易得到的结构体中保存需要的数据 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.