感谢老师和主教们提供的精彩课程,让我作为一个已经工作的工程师,在业余时间也能够深刻学习操作系统这门课程。课程内容丰富,技术前沿,把RUST
, RISCV
和OS
结合在一起,并且提供了完整的实验。经过学习我对操作系统有了很清楚的认识,虽然目前才做完lab3,但是后续会接着把两个实验也给完成。
lab1
实现sys_task_info
的系统调用,首先要为TaskControlBlock
添加两个对应字段:
1 | TaskControlBlocl{ |
之后只要实现对应函数去正确更新这两个字段的值就可以了。
- 首先是用
Option
去记录first_launch_time
,如果是None
,则用当前的时间去赋值,这样就可以在每次Task
调度的时候去记录first_launch_time
。 - 在每次进入
sys_call
处理函数的时候去更新syscall_times
。因为处理的时候可以获取到对应的syscall_id
。lab2
重写sys_get_time 和 sys_task_info两个系统调用是提醒我们返回值是写在虚拟地址的,所以需要做一次内存转换才把返回值写道正确的物理地址当中。主要使用了rCore
提供的translated_byte_buffer
拿到指向物理地址的内存,再把正确的结果写到内存即可。这里也加深了对rust
中unsafe
的理解。
实现sys_mmap
和sys_munmap
,主要是对TaskControlBlock
中的memory_set
进行修改。memory_set
本身提供了insert_framed_area
但是没有提供remove_framed_area
,所以照着实现了一下。之后就可以按照是要求去更新memory_set
,比较有意思的是要增加MapPermission::U
。
1 | impl MemorySet{ |
lab3
还是首次体验git cherry-pick
,再次感谢清华提供的优秀课程,质量真的很高!sys_get_time, sys_task_info, sys_mmap, sys_munmap
的实现都类似,实现sys_spawn
我仔细读了fork, exec
的代码,很自然就做出来了。
问题来到了Stride
调度算法的实现上,一开始觉得逻辑不复杂,就是添加TaskControlBlock
的stride
字段,然后从队列中找到stride
最小的执行。但是执行起来就发现有死循环,仔细读了文档发现还提到了时间片的概念。所以新增了time_slice
字段,并且更改了调度逻辑,每次时间中断触发之后会先更新time_slice
再决定进步进行调度。实现过程中也发现了min_stride
的逻辑有问题,一开始认为stride
最大值等于BIG_STRIDE
,实际并不是。
1 | let mut min_stride = BIG_STRIDE;// Bug! should use usize::MAX |
当实现完slice
和修复min_stride
的BUG之后,直接通过!