本实验主要完成了实验要求的:
- 修改ch2的代码, 在遇到不支持的trap的时候不要panic , 而是返回-1
- sys_write时增加对于物理内存的检查, 只能打印属于自己物理内存的信息, 超出则返回 -1
- 通过ch2的所有test
主要思路:
- 实现sys_yield
主要难点在于转发到内核的处理函数(可以借鉴其他sys_call的实现),只要简单的调用suspend_current_and_run_next()就好了 - 实现 sys_gettime, sys_set_priority 两个系统调用
系统调用的转发部分和其他类似,不展开解释,主要记录下sys_gettime 和 sys_set_priority的实现,以及基于优先级调度的策略的实现
//sys_set_priority
pub fn set_priority(priority: isize) -> isize {
if priority <= 1 {
-1
}else{
let mut inner = TASK_MANAGER.inner.borrow_mut();
let current_task = inner.current_task;
let before = inner.tasks[current_task].pass;
inner.tasks[current_task].pass = (BIG_STRIDE as isize) / priority;
println!("SET priority : before[{}] , after[{}]" , before, inner.tasks[current_task].pass);
priority
}
}
//sys_gettime
pub fn get_time() -> usize {
time::read()
}
- 实现 stride 调度算法
主要原理:选择当前stride值最小的进程,__switch到running状态,并加上task的pass值. 在这样的过程中,优先级较高的增加的stride值较少,所以有更多的调度机会,即pass值与调度次数成近似反比
fn find_next_task_stride(&self) -> Option<usize> {
let inner = self.inner.borrow();
let current = inner.current_task;
let mut ans: Option<usize> = None;
let mut min_stride = isize::MAX;
for index in (0..self.num_app) {
if inner.tasks[index].task_status == TaskStatus::Ready {
if inner.tasks[index].stride < min_stride {
ans = Some(index);
min_stride = inner.tasks[index].stride;
}
}
}
ans
}
fn run_next_task_stride(&self) {
if let Some(next) = self.find_next_task_stride() {
let mut inner = self.inner.borrow_mut();
let current = inner.current_task;
inner.tasks[current].stride += inner.tasks[current].pass;
inner.tasks[next].task_status = TaskStatus::Running;
inner.current_task = next;
let current_task_cx_ptr2 = inner.tasks[current].get_task_cx_ptr2();
let next_task_cx_ptr2 = inner.tasks[next].get_task_cx_ptr2();
core::mem::drop(inner);
unsafe {
__switch(
current_task_cx_ptr2,
next_task_cx_ptr2,
);
}
} else {
panic!("All applications completed!");
}
}
- 如果有兴趣进一步了解 stride 调度相关内容,可以尝试看看:
作者 Carl A. Waldspurger 写这个调度算法的原论文
作者 Carl A. Waldspurger 的博士生答辩slide
南开大学实验指导中对Stride算法的部分介绍
NYU OS课关于Stride Scheduling的Slide
- 如果有兴趣进一步了解用户态线程实现的相关内容,可以尝试看看:
user-multitask in rv64
绿色线程 in x86
x86版绿色线程的设计实现
用户级多线程的切换原理