2025 年春夏开源操作系统训练营三阶段总结
第一阶段总结
学习 rust 的语法,发现很多都是现代 c++的写法,遂上手很快,但与 c++不同的是,其拥有所有权机制,人为限制了 c++中不安全的写法,对内存更加安全,改正了自己之前写 c++时候的乱用指针,引用的不安全的写法,同时也学会了一门新的语言。
第二阶段总结
lab1
为了实现 sys_trace
系统调用(ID 为 410),我们查看了任务系统的机构,在其中人为的加上了我们所需要的参数,使得我们对 TCB 的结构熟悉和了解
lab2
我们实现了 mmap syscall ID:222 和 munmap syscall ID:215 的系统调用,其中,我们了解到每个任务的 mm,也就是 TCB 中 memory_set,中的结构有了更加深刻的了解。我们只需要在其中的 area 完成插入和删除。
lab3
这里要求我们实在 spawn 进程,因此,我们可以根据将其类似为 fork + exec ,其中,不必像 fork 一样复制父进程的地址空间。我们只需要新建一个地址空间,其中,我们需要新建一些虚拟区域,然后就可以完成,整体类似于与 fork + exec 的逻辑,其中,只是没有复制其地址空间。
然后,要我们完成 stride 调度算法,我们可以直接参考 manager 中的 fifo 的实现来进行更改,其中,manager 增加 BIG_STRIDE 这个成员,然后 tcb 中的 inner 加入 priority 和 Stride 这两个成员(因为是可变的)。这个时候,我们需要每次调度的时候寻找最小的 Stride,linux 中是采用红黑树查询的,但是这里比较简单,我们就直接使用轮询的方式。
lab4
要求我们去完成pub fn sys_linkat(_old_name: *const u8, _new_name: *const u8) -> isize
这样的调用接口,仿照上面的 sys_open()我们可以也写一个类似于 open_file 的函数,其形式为:pub fn __sys_linkat(_old_name: &str, _new_name: &str) -> isize
我们在__sys_linkat 中就可以调用 ROOTINODE 中的 linkat 方法。对于 linkat 方法,我们可以参照上面 create 方法,我们只需要注意以下:pub fn linkat(&self, _old_name: &str, _new_name: &str) -> isize
- 判断 oldname 的文件不为空,为空直接返回负一
- 由 oldname 中寻找 inode_id,而不是像 create 中直接 alloc_inode 得到
unlinkat:
前面于 linkat 相同,当到了 ROOTINODE 中的 unlink 方法pub fn unlink(&self, name: &str) -> isize
接下来,其思路和 linkat 完全相反,由于这里不要求我们删除,我们便不管
fstat:
参考文档,我们只需要获取 ino 和 nlink。其中 ino 我们写一个 osnode 中的get_inode_id
,其中,类型转化我们写一个 any 的 trait,将其转换,nlink 我们写一个 get_link_num 的方法,数有几个 DirEntry。再将其数据写入_st 中,我们便完成的 fstat 的写入
lab5
根据要求,我们,需要 Available ,为含有 m(资源数量) 个元素的一维数组,我们可以把他放到 process 中,其中他检测每个资源,根据题意要求,我们可以分别给 mutex 和 semaphore 设计一个。同时在线程中(task),我们需要添加相应的 Allocation 和 Need,其中长度为 mutex 和 semaphore 的数量,我们在修改相应的,创建,lock,unlock 函数的逻辑,按照作业中要求我们使用的逻辑和流程去完成编写。于此同时,我们需要修改 task 的创建,进程的初始化,fork 函数的逻辑,这样,我们就可以通过了。
第三阶段总结
Unikernel
这个阶段,我们需要完成以下内容:
- 带颜色的输出
- 手写一个 HashMap
- 实现 bump 内存分配算法
- 在 axfs_ramfs 下实现 rename 功能
print_with_color 很简单,我们只需要理解一下 axstd 模块,然后对照着对 println 这个宏进行修改
support_hash_map 比较困难,这里我偷了个懒,使用了 hashbrown::HashMap,这个过程中我们需要注意编译时候的条件限制,我们需要这样去进行条件编译
1 | #[cfg(feature = "alloc")] |
alt_alloc 很简单,我们按照 ppt 的提示,我们完成其 byte 和 page 的 api 的编写,只需要实earlyAllocator
trait 就可以接入内核中了
ramfs_rename 也不是很难,要把 cargo 里的包换成 arceos 下面的,找到对 trait 去实现 rename 函数,我们可以参照上面的创建和删除的 api,我们只需要修改就是修改两个 DirNode 下的BTreeMap<String, VfsNodeRef>
Monolithic Kernel
接下来我们从 Unikernel 到了宏内核,我们需要完成以下内容:
- 实现 sys_mmap
sys_map 我们可以按照提示,参考 m1_0,我们需要在 current 的task_ext
提供的接口去使用,我们可以使用 man 工具具体的查看每个参数的作用,根据其为 NULL 的时候,我们需要找片空地,在翻 aspeace 提供的 api 中,我们可以使用find_free_area
,在按照其逻辑,如果有文件,读文件,写入,就是文件映射,没有,就直接返回所寻找的虚拟地址。等实际使用爆出页错误再进行处理。
Hypervisor
在 Unikernel 的基础上引入 RISC-V 的 H 扩展,获得了虚拟化的能力。我们需要虚拟化 cpu,内存和进程。我们需要完成以下内容:
- 支持 simple_hv
simple_hv,我们只要在 vmexit_handler
中处理异常,然后给 a0,a1 赋值,我们就可以完成我们的任务。
总结
相比 rcore,arceos 复杂了许多,但是 arceos 中的很多思想思路都出现在 rcore 中,所以我们学习,上手的就很同时我们了解了组件化内核,其可以到 Monolithic Kernel 和 Hypervisor 中,我收获到了很多。同时遇上了很多的困难,在与伙伴聊天中收获到了很多的思路,看到了很多优秀的人。