Lab1 编程作业
读完前 3 章终于迎来了第一个 Lab,感觉前面都忘完了
先跟着敲了一遍第 3
章(os3-ref
)的代码,稍微对代码框架了解了一点
首先考虑实现获取
syscall_times
,注意是查询当前任务的调用次数,不是所有任务调用的总和
在 TaskControlBlock
中维护,调用 syscall
的时候修改即可。
1 2 3 4 5 6 7
|
pub struct TaskControlBlock { pub task_status: TaskStatus, pub task_cx: TaskContext, pub syscall_times: [u32; MAX_SYSCALL_NUM], }
|
1 2 3 4 5 6 7 8 9 10
|
use crate::task::count_syscall;
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { count_syscall(syscall_id); match syscall_id { ... } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
lazy_static! { ... let mut tasks = [TaskControlBlock { task_cx: TaskContext::zero_init(), task_status: TaskStatus::UnInit, syscall_times: [0; MAX_SYSCALL_NUM], }; MAX_APP_NUM]; ... }
impl TaskManager { fn count_syscall(&self, syscall_id: usize) { if syscall_id < MAX_SYSCALL_NUM { let mut inner = TASK_MANAGER.inner.exclusive_access(); let current_task = inner.current_task; inner.tasks[current_task].syscall_times[syscall_id] += 1; } }
fn get_syscall_times(&self) -> [u32; MAX_SYSCALL_NUM] { let inner = TASK_MANAGER.inner.exclusive_access(); inner.tasks[inner.current_task].syscall_times } }
pub fn count_syscall(syscall_id: usize) { TASK_MANAGER.count_syscall(syscall_id); }
pub fn get_syscall_times() -> [u32; MAX_SYSCALL_NUM] { TASK_MANAGER.get_syscall_times() }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
use crate::task::get_syscall_times
pub fn sys_task_info(ti: *mut TaskInfo) -> isize { unsafe { *ti = TaskInfo { status: ?, syscall_times: get_syscall_times(), time: ?, } } 0 }
|
接着考虑实现获取当前任务状态(虽然一定是
TaskStatus::Running
)
往上回溯,TaskStatus
-> TaskControlBlock
-> TaskManagerInner
-> TaskManager
->
static ref TASK_MANAGER
同时可以在 TaskManagerInner
中找到
current_task
于是可以直接调用得到状态,在 TaskManager
中实现接口:
1 2 3 4 5 6 7 8 9 10 11 12
|
impl TaskManager { fn get_current_task_status(&self) -> TaskStatus { let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task].task_status } }
pub fn get_current_task_status() -> TaskStatus { TASK_MANAGER.get_current_task_status() }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
use crate::task::get_current_task_status;
pub fn sys_task_info(ti: *mut TaskInfo) -> isize { unsafe { *ti = TaskInfo { status: get_current_task_status(), syscall_times: get_syscall_times(), time: ?, } } 0 }
|
对于任务总运行时长,同样在 TaskControlBlock
中维护,记一个 start_time: Option<usize>
变量表示开始运行的时间,初始化为 None
。
然后调用是判断是否是初次运行并记录,查询时直接计算即可。
而所有任务运行前都会调用 __switch
进行上下文切换,考虑在调用 __switch
前后对
start_time
进行记录。
1 2 3 4 5 6 7 8
|
pub struct TaskControlBlock { pub task_status: TaskStatus, pub task_cx: TaskContext, pub syscall_times: [u32; MAX_SYSCALL_NUM], pub start_time: Option<usize>, }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
lazy_static! { ... let mut tasks = [TaskControlBlock { task_cx: TaskContext::zero_init(), task_status: TaskStatus::UnInit, syscall_times: [0; MAX_SYSCALL_NUM], start_time: None, }; MAX_APP_NUM]; ... }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
impl TaskManager { fn run_first_task(&self) -> ! { ... let next_task_cx_ptr = &task0.task_cx as *const TaskContext; task0.start_time = Some(get_time()); drop(inner); ... }
fn run_next_task(&self) { ... let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; if inner.tasks[next].start_time.is_none() { inner.tasks[next].start_time = Some(get_time()); } drop(inner); ... }
fn get_current_run_time(&self) -> usize { let inner = TASK_MANAGER.inner.exclusive_access(); (get_time() - inner.tasks[inner.current_task].start_time.unwrap()) / (CLOCK_FREQ / 1000) } }
pub fn get_current_run_time() -> usize { TASK_MANAGER.get_current_run_time() }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
use crate::task::get_current_run_time;
pub fn sys_task_info(ti: *mut TaskInfo) -> isize { unsafe { *ti = TaskInfo { status: get_current_task_status(), syscall_times: get_syscall_times(), time: get_current_run_time(), } } 0 }
|
然后这时直接进行测试的话会发现直接卡在启动前了,根据 Github 中一个 issue
提到,大概是因为开的 syscall_times
爆栈了,解决方案里面写了几种,我选择把数组用 Box
包起来分配到堆上,因为 Box
没有实现
Copy Trait
,注意要把 TaskManagerInner
中的
tasks
改为 Vec
实现。
最后,发现得到的任务运行时间总和测例有差距,看了看测例发现用了一种很奇怪的算法(反正我是没看懂),直接搬了
1 2 3 4 5 6
|
pub fn get_time_ms() -> usize { let t = get_time(); (t / CLOCK_FREQ & 0xffff) * 1000 + (t / (CLOCK_FREQ / 1_000_000) % 1_000_000 / 1000) }
|
Github
Repository