rCore第三章练习
获取任务信息
ch3
中,我们的系统已经能够支持多个任务分时轮流运行,我们希望引入一个新的系统调用 sys_task_info
以获取任务的信息,定义如下:
fn sys_task_info(id: usize, ts: *mut TaskInfo) -> isize
syscall ID
: 410- 根据任务 ID 查询任务信息,任务信息包括任务 ID、任务控制块相关信息(任务状态)、任务使用的系统调用及调用次数、任务总运行时长。
struct TaskInfo {
id: usize,
status: TaskStatus,
call: [SyscallInfo; MAX_SYSCALL_NUM],
time: usize
}
- 系统调用信息采用数组形式对每个系统调用的次数进行统计,相关结构定义如下:
struct SyscallInfo {
id: usize,
times: usize
}
-
-
参数:
id
: 待查询任务idts
: 待查询任务信息
-
-
返回值:执行成功返回0,错误返回-1
-
-
说明:
相关结构已在框架中给出,只需添加逻辑实现功能需求即可。
-
-
-
提示:
大胆修改已有框架!除了配置文件,你几乎可以随意修改已有框架的内容。程序运行时间可以通过调用
get_time()
获取。系统调用次数可以考虑在进入内核态系统调用异常处理函数之后,进入具体系统调用函数之前维护。阅读TaskManager
的实现,思考如何维护内核控制块信息(可以在控制块可变部分加入其他需要的信息)
-
我的实现
简述
在user
目录中实现一个sys_task_info
,系统调用返回后,传入的*mut TaskInfo
中将获得要查询的app
的信息。而在os
端,要从创建这个app
的控制块开始就维护这个信息,我在task.rs
中创建TaskInfo
的结构体,并在TASK_MANAGER
初始化时也对每个app
的TaskInfo
进行初始化。同时这里控制块处理再添加一个TaskInfo
外,还要加入一个last_time
,用于记录这个任务被调度的时间。于是suspend
,exit
,run
等行为会修改控制块中的status
和time
,time
可以每次加上get_time() - last_time
。
而syscall
的信息在syscall_handler
的match
语句前调用record(syscall_id)
函数,对current
的app
的syscall_id
调用加1。
代码分析
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
set_syscall_record(syscall_id);
match syscall_id {
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32),
SYSCALL_YIELD => sys_yield(),
SYSCALL_GET_TIME => sys_get_time(),
SYSCALL_TASK_INFO => sys_task_info(args[0], args[1] as *mut TaskInfo),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}
这里第二条语句对于当前这个系统调用进行了记录,还有倒数第4行添加了sys_task_info
的系统调用。
fn set_syscall_record(&self, syscall_id: usize) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
inner.tasks[current].task_info.call[syscall_id].id = syscall_id;
inner.tasks[current].task_info.call[syscall_id].times += 1;
drop(inner);
}
fn get_task_info(&self, id: usize, task_info: *mut TaskInfo) -> isize {
if id < MAX_APP_NUM {
let inner = self.inner.exclusive_access();
let current = inner.current_task;
unsafe {
(*task_info).id = id;
(*task_info).status = inner.tasks[current].task_status;
(*task_info).time = inner.tasks[current].task_info.time;
(*task_info).call = inner.tasks[current].task_info.call;
}
drop(inner);
0
} else {
-1
}
}
这里可以看到对应的实现,set_syscall_record
将对应的syscall_id
中的id
赋值,表示这个系统调用被执行过。get_task_info
将kernel
记录的信息,一项一项地拷贝到了app
传入的结构体中。