获取任务信息

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初始化时也对每个appTaskInfo进行初始化。同时这里控制块处理再添加一个TaskInfo外,还要加入一个last_time,用于记录这个任务被调度的时间。于是suspend,exit,run等行为会修改控制块中的statustimetime可以每次加上get_time() - last_time

​ 而syscall的信息在syscall_handlermatch语句前调用record(syscall_id)函数,对currentappsyscall_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_infokernel记录的信息,一项一项地拷贝到了app传入的结构体中。