0%

2023开源操作系统训练营一二阶段总结

感谢老师和主教们提供的精彩课程,让我作为一个已经工作的工程师,在业余时间也能够深刻学习操作系统这门课程。课程内容丰富,技术前沿,把RUSTRISCVOS结合在一起,并且提供了完整的实验。经过学习我对操作系统有了很清楚的认识,虽然目前才做完lab3,但是后续会接着把两个实验也给完成。

lab1

实现sys_task_info的系统调用,首先要为TaskControlBlock添加两个对应字段:

1
2
3
4
5
TaskControlBlocl{
/// ...
first_launch_time: Option<usize>,
syscall_times: [usize; MAX_SYSCALL_NUM]
}

之后只要实现对应函数去正确更新这两个字段的值就可以了。

  1. 首先是用Option去记录first_launch_time,如果是None,则用当前的时间去赋值,这样就可以在每次Task调度的时候去记录first_launch_time
  2. 在每次进入sys_call处理函数的时候去更新syscall_times。因为处理的时候可以获取到对应的syscall_id

    lab2

重写sys_get_time 和 sys_task_info两个系统调用是提醒我们返回值是写在虚拟地址的,所以需要做一次内存转换才把返回值写道正确的物理地址当中。主要使用了rCore提供的translated_byte_buffer拿到指向物理地址的内存,再把正确的结果写到内存即可。这里也加深了对rustunsafe的理解。

实现sys_mmapsys_munmap,主要是对TaskControlBlock中的memory_set进行修改。memory_set本身提供了insert_framed_area但是没有提供remove_framed_area,所以照着实现了一下。之后就可以按照是要求去更新memory_set,比较有意思的是要增加MapPermission::U

1
2
3
4
5
6
7
8
9
10
11
impl MemorySet{
/// Remove framed area
pub fn remove_framed_area(&mut self, start_va: VirtAddr, end_va: VirtAddr) {
let mut target_area =
MapArea::new(start_va, end_va, MapType::Framed, MapPermission::empty());

target_area.unmap(&mut self.page_table);
self.areas
.retain(|area| area.vpn_range.get_start() != target_area.vpn_range.get_start())
}
}

lab3

还是首次体验git cherry-pick,再次感谢清华提供的优秀课程,质量真的很高!sys_get_time, sys_task_info, sys_mmap, sys_munmap的实现都类似,实现sys_spawn我仔细读了fork, exec的代码,很自然就做出来了。

问题来到了Stride调度算法的实现上,一开始觉得逻辑不复杂,就是添加TaskControlBlockstride字段,然后从队列中找到stride最小的执行。但是执行起来就发现有死循环,仔细读了文档发现还提到了时间片的概念。所以新增了time_slice字段,并且更改了调度逻辑,每次时间中断触发之后会先更新time_slice再决定进步进行调度。实现过程中也发现了min_stride的逻辑有问题,一开始认为stride最大值等于BIG_STRIDE,实际并不是。

1
2
3
4
5
6
7
let mut min_stride = BIG_STRIDE;// Bug! should use usize::MAX
for tcb in self.ready_queue.iter() {
let cur_stride = tcb.inner_exclusive_access().stride;
if min_stride > cur_stride {
min_stride = cur_stride;
}
}

当实现完slice和修复min_stride的BUG之后,直接通过!