0%

1 Stage

初次学习rust ,之前一直以c++作为主语言进行编程,大概了解了rust 的借用机制,而且对操作系统感兴趣,所以开始学习

在学习rust过程中,与c++相对比很多“不适应”

  1. 变量的借用机制以及生命周期的声明让人很水土不服,还在深刻感受
  2. 基础stl库的文档过于繁杂了。
  3. 比 c++ 更原生支持的泛型编程,而且比c++模板可读性更高,debug也相对更容易一些
  4. 总体比 c++ 更约束,c++ 的自由带来的是各种错误和不安全性,rust在这一方面确实做得更加出色(听说性能也与c++相差不多)

2 Stage

lab1

简单的系统调用实现,关键是了解了 os 最初的形状,见识到了如何使用汇编和高级语言一起实现应用,很酷

lab2

rcore 路上的第一道门槛,如果lab1只能算花了我一小会的放松时间,那lab2就相当于一整天。

  1. 先把lab1的实现在lab2中兼容(地址转换有点难受)。
  2. 而后专注于实现 mmap 与 munmap,在实现时,采用直接新建area的方式,删除则删除对应 start area
  3. 但遇到了问题,在校验vpn是否合法时,pte检验一直出现问题,最后在translate to ppn相关函数中做了自己理解的改动

lab3

实现角度看比较简单,但自己尝试了不同的stride位数 以及 bigstride,看到了很多很有意思的现象,包括一直不被调度,包括反转现象

lab4

感觉关键在于硬链接统计方法,实现比较粗暴(实在没时间了。。),有时间可以考虑如何使用抽象的思维跳过 STDOUT STDIN

lab5

考虑银行家算法 和 死锁检测的区别(🤔)

写在前面

我从稍微理解了我的专业之后就一直都很崇拜 Linus,这位堪称传奇的软件工程师在 1991 年 8 月 25 日——他 21 岁时就在网络上发布了 Linux 内核的源代码。现在是 2024 年 4 月 23 日,我也是 21 岁,追逐吗,梦想吗,我也想像他一样写出这样神奇的代码,33 年后的今天,我也要开始了,Linus。

欢迎交流;-)

这次参加训练营,也算是二周目,对很多内容都已经轻车熟路。在上次的训练营之中,我并没有完成三阶段的学习,多少有当时实习没有时间进行分配和对更加复杂的操作系统内核架构没有大概了解的原因。

所以在实习结束之后的暑假,我也没有闲着,主要都在学习 Rust 之前没有接触过的内容还有理解 Linux 操作系统内核上了。成果大概就是把《Rust 程序设计第二版》这本书看完了,加上初探了一下 Rust 的异步框架、对 Linux 0.12 这个老版本的内核代码进行了一些阅读。

希望这次可以成功冲击第四阶段,加油!

背景

在过去的一年时间里,我开始学习 Rust 语言,并完成了 Rust 官方的 rustlings 练习题。这些练习题主要帮助我熟悉了 Rust 的基本语法和特性,如所有权、借用、模式匹配等。通过这些基础知识的积累,我对 Rust 的语法和一些核心概念有了初步理解。

问题与挑战

尽管 rustlings 帮助我打下了基础,但在尝试编写算法和更复杂的数据结构时,还是遇到了不少困难。例如,在实现动态规划、递归和一些复杂数据结构时,感觉自己对于 Rust 的所有权、生命周期、以及内存管理的理解不够深刻。这让我在面对更复杂的算法实现时,仍然感到束手无策。

下一步计划

为了解决上述问题,我计划进一步提升自己的 Rust 算法编程能力。具体来说,我会在 LeetCode 等平台上使用 Rust 进行算法题目的练习,以巩固对语言特性的理解,并适应使用 Rust 实现高效的算法。通过逐步解决不同难度的算法问题,相信自己能更好地掌握 Rust 的特性和应用。

总结

Rust 是一门极具潜力的系统级编程语言,其独特的内存安全机制和高性能特性值得深入学习。尽管当前在编写算法时遇到了一些困难,但相信通过不断的练习,尤其是在 LeetCode 上的算法刷题,我可以进一步提升自己在实际应用中使用 Rust 的能力。

写在前面

我从稍微理解了我的专业之后就一直都很崇拜 Linus,这位堪称传奇的软件工程师在 1991 年 8 月 25 日——他 21 岁时就在网络上发布了 Linux 内核的源代码。现在是 2024 年 4 月 23 日,我也是 21 岁,追逐吗,梦想吗,我也想像他一样写出这样神奇的代码,33 年后的今天,我也要开始了,Linus。

欢迎交流;-)

这次参加训练营,也算是二周目,对很多内容都已经轻车熟路。在上次的训练营之中,我并没有完成三阶段的学习,多少有当时实习没有时间进行分配和对更加复杂的操作系统内核架构没有大概了解的原因。

所以在实习结束之后的暑假,我也没有闲着,主要都在学习 Rust 之前没有接触过的内容还有理解 Linux 操作系统内核上了。成果大概就是把《Rust 程序设计第二版》这本书看完了,加上初探了一下 Rust 的异步框架、对 Linux 0.12 这个老版本的内核代码进行了一些阅读。

希望这次可以成功冲击第四阶段,加油!

内存管理

在二周目的学习之中,我重点学习了 rCore 内存模块关于内存管理的这部分内容,这部分内容在一周目里面可是给我吃了不少苦头,从 ch3 到 ch4 的难度跨度确实有些大,并且 ch4 之中的内容基本上就是后续内容的基石。这部分内容还是看得越懂越好,我越看越觉得当初这些人是怎么想出来这个方案来实现内存地址空间管理的,而且这还是没有实现页置换(顺带一提,这是 Linux 当年的大杀器)和cow。说实话这部分的内容 Linus 当年也是调试到吐。

从物理地址、虚拟地址和物理页号、虚拟页号的初级表示到页目录项、页表对内存的统一管理再到MemoryAreaMemorySet实现对一个进程的内存地址空间的高级表示,确实很精彩。

更加高级的内容

后面的内容,包括文件系统、进程间通信和 I/O 重定向、和并发的复杂性实际上更上一层楼,所以 rcore 可以去繁从简,用几篇文档的篇幅就带我们对这些操作系统的重要抽象有一个大概的概念也实在不容易。就实验要完成的测例来说,感觉也是简化的副作用吧,有点“面向结果编程”的感觉,这个时候就要考验程序员对自己的要求了:只通过测例完全不够,还需要理解这部分的内容。

其实还想要写很多,但是“我有一个对这个命题的十分美妙的证明,这里空白太小,写不下。”,哈哈,期待第三阶段和 ArceOS 擦出的火花。

前言

我是来自华中科技大学计算机科学与技术专业的一名本科生,课堂上做过类似的操作系统实验,但当时忙于其他事情,只是草草应付了事,所以想趁着这个机会,重新详细认识一下操作系统的基本逻辑,也学习一下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

在这个实验被一个小问题卡了很久。

1
2
3
4
5
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是触发如下错误:

1
2
3
4
5
let pte = self.page_table.find_pte(start);
if pte.is_some() {
println!("conflict_vpn: {:?}", start);
return -1;
}

当时百思不得其解,自己造了一些其他测试,发现下面这样的操作居然不会报错:

1
2
3
4
5
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值加完之后溢出了,就把该进程标记一下,之后都不考虑调度它,直到所有进程都溢出了。其实这样徒增了很多计算量,问答作业中的方法其实才是比较好的解法:

思想大致如下,没实际运行过,可能有一些细节上的问题:

1
2
3
4
5
6
7
8
9
10
11
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。

总结

这些实验确实都聚焦在了操作系统中基本且核心的问题,而且架构也是循序渐进,让人能够慢慢了解虚拟化、进程线程、文件系统这些都是怎么一步步得来的,感觉受益匪浅。

第一阶段

工作中已经写了一年多的Rust代码,体验确实不错,特别是完善的包管理工具,大大减少了编译时的心智消耗,所有权和借用系统并没有很复杂,写一阵代码自然就熟悉了

第一阶段算是再巩固下基础,数据结构题比较有意思,不过深入学习还是要抽空看看链表

第二阶段

对操作系统很感兴趣,尤其是第三阶段的虚拟化方向。由于平时工作比较忙,也就晚上和周末抽时间抓紧写写代码,下边主要总结下各个章节产生的疑问和实验遇到的问题吧

lab1(ch2,ch3)

主要熟悉了应用加载,中断,用户栈/内核栈切换,任务切换的机制,再是学习了下risc-v寄存器以及汇编方面的知识,受益匪浅

实验比较简单,主要熟悉下syscall的开发流程

lab2(ch4)

本章新增了地址空间,内核和应用通过页表机制把虚拟内存映射到实际的物理内存,虚拟内存使得不同应用都可以使用连续独立的地址空间,并做到了不同应用之间的隔离

strampoline段用于保存陷入内核和返回用户态的代码,并通过把内核和应用的strampoline设置成相同地址的虚拟页(最高页),使得切换地址空间之后,这段代码地址可以无缝衔接

TrapContext紧贴着strampoline位于应用的次高页(看起来没必要一定要在次高页)。TrapContext用于保存上下文切换时的寄存器以及kernel satpkernel sp等。TrapContext位于用于应用地址空间是因为,切换上下文时只有一个sscratch寄存器可以用于周转,而如果TrapContext位于内核栈(内核栈不是恒等映射),那就只需要先通过sscratch得到kernel satp切换到内核地址空间之后才能访问TrapContext,这时就没有额外寄存器获得kernel sp也就拿不到TrapContext地址。如果位于应用地址空间,就可以通过sscratch寄存器保存TrapContext地址,在陷入内核后,先在应用地址空间保存好上下文之后,再切换到内核地址空间

实验需要注意的点:

  • mmap页面要4k对齐,空间左闭右开

  • syscall复制结构体时,需要通过translated_byte_buffer拿到用户态结构体对应的物理地址(这部分内存在内核是恒等映射的,可以正确写入),再复制

lab3(ch5,ch7)

这两章主要讲了进程和进程通信,是概念相对简单的章节,难点主要在于调度算法

实验是实现spawn,总体来说是new+fork,不复制地址空间,但继承父子关系

lab4(ch6)

本章学习了文件系统,代码中数据结构依赖关系相对复杂,画图梳理下比较方便理解

实验中nlink需要要保存在DiskInode中,同时减少INODE_DIRECT_COUNT保证DiskInode只占用128bytes

这里我把file_count也存下了,方便unlink时候,直接把最后一个DirEntry替换到被删除的Entry位置。其次可以用union保存nlinkfile_count来节省空间,毕竟文件没有file_count,目录不允许有link,这里偷懒了

1
2
3
4
5
6
7
8
9
10
11
12
const INODE_DIRECT_COUNT: usize = 26;

#[repr(C)]
pub struct DiskInode {
pub size: u32,
pub nlink: u32,
pub file_count: u32,
pub direct: [u32; INODE_DIRECT_COUNT],
pub indirect1: u32,
pub indirect2: u32,
type_: DiskInodeType,
}

一定要注意锁不能重入,在开发unlinkat时,因为调用其他也加文件锁的函数导致了死锁,被卡了有一阵

lab5(ch8)

本章主要讲了内核中线程和锁的实现机制

下面有几个注意点

  • 调用schedule切换线程前一定要手动drop资源,否则会造成资源泄露或panic

  • exit_current_and_run_next在调用schedule之前分配了TaskContext::zero_init()作为dummy TaskContext,开始还想着这个线程不会再恢复了,那这个栈空间在后边是如何保证地址合法并最终回收的,而这就是sys_waittid存在价值之一

  • 代码中的PROCESSOR并不是thread_local的,但有很多exclusive_access的调用,可能教学用的rCore并不存在多个cpu,这里暂时不需要考虑这个问题

1
2
3
4
5
6
7
lazy_static! {
pub static ref PROCESSOR: UPSafeCell<Processor> = unsafe { UPSafeCell::new(Processor::new()) };
}

pub fn current_task() -> Option<Arc<TaskControlBlock>> {
PROCESSOR.exclusive_access().current()
}

实验是死算检测,并不复杂,按着文档来就好

2024年秋冬季开源操作系统训练营第一、二阶段总结报告

我个人的话原本这段时间的计划是重新深入学习一下 RUST 语言,通过 RUST 圣经找到的 RUST 官方社区的 QQ 群。刚好在群里看到群友的开源操作系统的邀请,其实时间上对我来说刚刚好,主要原因在于明年暑假可能该找实习了,否则可能不太好找工作。我本人也想通过这个开源来完善自己在开源项目的 PR 上的缺陷,所以,刚刚好,那就坚持到最后吧。

机会总是有的,抓住了还得坚持到底。嗯,就这样。

第一阶段总结

第一阶段怎么说呢,嗯,不太好总结,之前因为一些机缘巧合看过 RUST 官方社区的教材,所以只有简单了解,也写过教材里的demo。所以,总体上来说,对我难度不大。嗯,也是在一阶段前截止前三天吧开始的,后面每天完成一点。大概这样。对我来说的话 RUST 实现链表那边是真的很难,但是只完成 task 倒还好。

第二阶段总结

二阶段的话,分不同的章节吧,收获不同。

第三章实验内容的话是taskinfo系统调用的支持。其实实现这个系统调用不难,这边主要的收获是对程序链接有了更深的了解。在linker链接器脚本中指定的符号可以被OS中以外部符号的形式使用,嗯,链接的作用应该是了解更深了。其次,了解更深的地方在于任务切换,一个任务从elf到一个进程,如何构造,如何执行,如何调度,如何进入User模式执行这样,包括一些寄存器SStatus,SEPC,Stvec等等。

第四章的话,mmap和munmap这两个的实现上也没问题。主要收获其实是在于跳板实现的一些细节,最后跳转trap_handler的时候使用jr指令主要原因在于linker脚本链接出来的地址差值和真正跳板代码的虚拟地址位置还有很大差别。所以,不能这么搞,差值还要加上和跳板的距离。

在进程管理里,先前的任务结构体被重新修改为了进程。并且要实现的系统调用也与进程的产生有关系。此外,对stride算法也有了一定的了解。本质上还是进程里添加了一个字段,然后在每次执行进程时都重新处理一次prio字段并更新记录,以决定下一次执行的进程。

进程管理的主要收获在于,task和进程切换的差别。他们差别很大,进程切换要切所有的通用寄存器等等。任务切换切pc,切栈,切被调用者保存寄存器这样,因为调用者保存寄存器在调用schedule的时候已经保存了。然而切换的时候还有被调用者保存寄存器还没保存好。嗯,就是这样。

这里,有个问题就是使用usize的MAX作为大整数,没想到后面会反复调度任务0,后面debug之后才知道要取余这样。

并发的话,就真的太折磨了,银行家算法真的难搞。最后没过测例的原因居然是没实现sys_get_time。太TM离谱了,以后一定好好看任务手册。

最后

如果这次没坚持到后面的话,可能后面就真的没机会了。学业上有科研要求,还想去实习,嗯,对我的规划来说,可能到毕业之前没有再来一次的机会了。

一定坚持到最后。

Rust学习感悟

学习Rust语言可以是一个既挑战又充满成就感的过程。以下是一些常见的学习Rust的感悟:

  1. 安全性:Rust的设计哲学之一是内存安全,它通过所有权、借用和生命周期的概念来保证。学习这些概念可能会有些复杂,但一旦理解,它们会极大地减少内存错误,比如空指针解引用和数据竞争。
  2. 性能:Rust提供了与C/C++相媲美的性能,因为它允许直接的内存操作和避免运行时垃圾回收。理解这一点可以激励你更深入地学习如何编写高效的代码。
  3. 并发编程:Rust的类型系统和所有权模型使得编写无数据竞争的并发代码变得容易。这种安全性在其他语言中通常是通过运行时检查实现的,这可能会影响性能。
  4. 编译时检查:Rust的编译器非常严格,它会在编译时捕获许多潜在的错误。这可能会让初学者感到挫败,但长远来看,它有助于提高代码质量和减少运行时错误。
  5. 学习曲线:Rust有一个陡峭的学习曲线,特别是对于那些习惯于垃圾回收和动态类型语言的开发者。然而,一旦习惯了Rust的思维方式,你会发现它提供了一种更清晰、更可控的编程方式。
  6. 社区和文档:Rust社区以其友好和乐于助人而闻名,官方文档也非常全面和易于理解。这些都是学习新语言时的重要支持。
  7. 工具链:Rust有一个强大的包管理器Cargo,它简化了依赖管理和构建过程。学习如何使用Cargo可以提高开发效率。
  8. 所有权和借用:这是Rust中最具挑战性的概念之一,但也是其核心特性。理解所有权如何工作,以及如何通过借用和生命周期来管理资源,是掌握Rust的关键。
  9. 错误处理:Rust使用ResultOption类型来处理可能失败的操作,这鼓励开发者在代码中显式地处理错误情况,而不是依赖于异常。
  10. 泛型和trait:Rust的泛型和trait提供了强大的抽象能力,允许编写灵活且可重用的代码。
  11. 宏系统:Rust的宏系统非常强大,允许在编译时执行复杂的代码生成。这为元编程提供了强大的工具,但同时也增加了学习的复杂性。
  12. 生态系统:随着Rust生态系统的成熟,越来越多的库和工具被开发出来,这使得Rust在各种领域,如Web开发、系统编程、嵌入式开发等,都变得更加实用。

学习Rust是一个不断进步的过程,随着经验的积累,你会发现自己对语言的掌握越来越深入,同时也能够欣赏到Rust在系统编程领域所带来的独特优势。

rCore学习感想

学习是一个不断探索和发现的过程,它不仅涉及到知识的积累,还包括技能的提升和思维的拓展。最近,我深入学习了 Rust 语言和 rCore 操作系统,这段经历让我对编程和计算机科学有了更深刻的理解。Rust 语言的安全性和性能给我留下了深刻的印象。通过学习 Rust,我学会了如何利用所有权、借用和生命周期这些核心特性来编写既安全又高效的代码。这些概念在一开始可能会让人感到困惑,但随着实践的深入,我开始欣赏它们在防止内存错误和提高代码质量方面的强大能力。rCore 项目让我有机会将 Rust 的理论应用到实际的操作系统开发中。这个过程不仅加深了我对 Rust 语言的理解,还让我对操作系统的工作原理有了更直观的认识。从内存管理到进程调度,每一个组件的实现都是对 Rust 能力的一次考验,也是对我解决问题能力的一次提升。学习过程中遇到的挑战也促使我不断寻找解决方案,这不仅锻炼了我的问题解决能力,也增强了我的自学能力。每当我解决一个难题,那种成就感都是无与伦比的。我意识到学习是一个永无止境的旅程。随着技术的不断发展,总有新的知识等待我去探索。我对 Rust 和 rCore 的学习只是一个开始,我期待着在未来的学习和工作中,将这些知识应用到更广泛的领域中,继续成长和进步。

Rustlings

我使用过一段时间 Rust,但是已经有大约一年时间没使用了,Rustlings 的练习让我重新找回对 Rust 的熟悉感。Rustlings 前面的一些部分都是通过魔改代码,让编译通过并通过测试,从而理解 Rust 的特性。因为魔改的地方就是教学的地方,所以通过魔改少量代码的方式教学,我认为是非常高效的,而 watch 功能则更快捷方便连续地学习,就跟闯关一行。

相比于 Rust-by-Example,Rustlings 更偏向于实践,更方便开发者在了解 C/C++ 等高级语言的基础上,了解 Rust 的内存安全特性,包括所有权、生命周期等机制,迁移到 Rust。Rust 更强大的枚举、元组等类型以及支持更完善的标准库,更方便开发者专注于程序算法本身,而不是对程序的具体过程操心。Rust 的迭代器抽象还能够方便的提供函数式编程,使用一行语句就完成对数组全部操作,在数学上更美观,同时应该也更方便编译器进行优化。

Rustlings 最难的部分应该是一些算法的实现。正如 Rust 的所有权机制,通常对象之间有树形的嵌套关系,而描述双向链表、图这种数据结构则并不适合使用这种关系;其中有一个练习是二叉排序树,但是不要求实现平衡。如果要实现平衡树则要考虑到树的旋转等操作,在这种所有权机制下则更难实现。而对于图,则只能对于整个图整体分配存储、整体管理,最后很容易写出 C 风格的代码,或者使用了大量的 unsafe( algorithm1 的单链表合并中就有大量 unsafe)。我也尝试过使用 Rust 练习 AtCoder,体验堪称坐牢,写 Rust 就是和编译器作斗争。所以使用 Rust 完成漂亮的算法类代码,是一门深刻的艺术。

本人算是对操作系统比较熟悉,之前做过 xv6-riscv 实验,这次体验了 Rust 的操作系统试验。

ch3

ch3 可以说是 rCore 的入门题,帮助上手 rCore 的代码以及 rust 系统编程,还帮助熟悉 risc-v 的特权级指令。

ch4

ch4 主要是熟悉了操作系统的内存管理,从此,用户的地址空间和内核的地址空间隔离开,同时开启了页表。 ch4 实验重点是在内核和用户空间传输数据,因为内核是恒等映射,而用户空间开启了分页。如果二者没有共用页表,那么就需要手动模拟地址转换,并且还需要按照分页去写内存,因为一次返回的数据可能在不同的页中。此外还实现了简单的空间分配和管理,实现了简单的 mmap 和 munmap。

ch5

ch5 主要实现的进程管理和进程调度。把 fork 和 execve 融合魔改出来一个 spawn 能加深对 fork 和 execve 的印象。

ch6

ch6 是完善 easy-fs 的功能,但是我认为 easy-fs 没有解析路径、构建树形目录结构不能让学生了解到一个功能比较正常的文件系统的样子,而在此过早将 easy-fs 与其它内核模块解耦合也带来了增加功能和 debug 上的困难。

ch8

ch8 要求实现死锁检测算法,但是传统的银行家算法要求预先知道各个线程需要的资源,并且没有考虑线程因等待资源而阻塞的情况,这与现实的操作系统有出入。在现实中,可以认为阻塞的线程所需要资源为它所需的全部资源,将检测的申请资源调用后的状态作为最终状态,只需要检测此次申请是否可能死锁。

总结

对 rCore 的学习与实践更深入了解了操作系统的基本原理,也锻炼了 rust 代码能力。

前言

我是来自于海南大学密码科学与技术专业的本科生,对于计算机体系结构方向很感兴趣,但由于学校条件所限,不能满足个人学习需求,所以来参加这个课程

在之前,我一直对一些东西比较好奇

比如

  1. 盗版激活软件所说的模拟硬件激活
  2. 计算机取证中,DMA技术如何用来解密BitLocker的,DMA外挂是如何实现的(当然,这个漏洞已经被修复),(我觉得,作为一个本科生,不应该只知道表面,而是更深入的了解,正所谓,知其然,知其所以然)
  3. 内核的内存管理
  4. 并发
  5. 动态链接的一些细节

等问题.

所以, 我报名参加了这次的操作系统训练营.

第一阶段

我C写的比较多,而且习惯确实不太好,所以在这阶段,也是磕磕绊绊,尤其是在所有权机制上,给了我“不灵活”的印象,我觉得也不算坏事吧,通过尽可能多的约束,把不安全的代码存在的范围尽可能缩小,方便发现问题和解决。

此外 rust的cargo非常好用。

还有,教程使用的rustlings有点旧?我用着是有点不太方便的,貌似没法很好的调试,我依赖于rustings run name这种方式来debug,但是每次都要写那么多,显然有点麻烦

我通过把如下内容加入 .bashrc,简化了这个操作

alias check=’rustlings run’

alias hint=’rustlings hint’

这样,就可以通过check name的方式检查题目了

第二阶段

Lab 1

一个简单的多任务系统,我曾经参加过海南大学南海鲨战队的电控培训,看过ucosii的代码,所以这点对我来说还好

Lab 2

这个实验启用了分页机制, 在这次实验之前,看过xv6 内存管理部分的代码,所以还好(这在之前,逆向程序时的内存地址,让我有不少困惑)

Lab 3

进程: 在这地方,我觉得问题不大

Lab 4

文件系统: 这里问题挺多的,做的有点糊涂,不过不管怎么样,能用

Lab 5

多线程: 了解了线程与并发的相关知识,还有银行家算法

总结

通过这门课程我学习到了很多操作系统的基础知识, 这个学期补补计算机组成原理,算法。rust也不熟练,不优雅,还得多练,下个学期二战。

我在此感谢此训练营的组织者和助教们,你们为很多人打开了一个新的天地。