Skip to content

Commit 984ee7e

Browse files
committed
111
1 parent 36abdda commit 984ee7e

File tree

5 files changed

+156
-5
lines changed

5 files changed

+156
-5
lines changed

os/src/syscall/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ mod process;
2626

2727
use fs::*;
2828
use process::*;
29+
use crate::task::record_current_syscall;
2930

3031
/// handle syscall exception with `syscall_id` and other arguments
3132
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
33+
record_current_syscall(syscall_id);
3234
match syscall_id {
3335
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
3436
SYSCALL_EXIT => sys_exit(args[0] as i32),

os/src/syscall/process.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Process management syscalls
22
use crate::{
3-
task::{exit_current_and_run_next, suspend_current_and_run_next},
3+
task::{current_task_syscall_count, exit_current_and_run_next, suspend_current_and_run_next},
44
timer::get_time_us,
55
};
66

@@ -38,8 +38,17 @@ pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize {
3838
0
3939
}
4040

41-
// TODO: implement the syscall
42-
pub fn sys_trace(_trace_request: usize, _id: usize, _data: usize) -> isize {
41+
pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
4342
trace!("kernel: sys_trace");
44-
-1
43+
match trace_request {
44+
0 => unsafe { *(id as *const u8) as isize },
45+
1 => {
46+
unsafe {
47+
*(id as *mut u8) = data as u8;
48+
}
49+
0
50+
}
51+
2 => current_task_syscall_count(id) as isize,
52+
_ => -1,
53+
}
4554
}

os/src/task/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::loader::{get_num_app, init_app_cx};
1919
use crate::sync::UPSafeCell;
2020
use lazy_static::*;
2121
use switch::__switch;
22-
pub use task::{TaskControlBlock, TaskStatus};
22+
pub use task::{TaskControlBlock, TaskStatus, MAX_SYSCALL_NUM};
2323

2424
pub use context::TaskContext;
2525

@@ -54,6 +54,7 @@ lazy_static! {
5454
let mut tasks = [TaskControlBlock {
5555
task_cx: TaskContext::zero_init(),
5656
task_status: TaskStatus::UnInit,
57+
syscall_times: [0; MAX_SYSCALL_NUM],
5758
}; MAX_APP_NUM];
5859
for (i, task) in tasks.iter_mut().enumerate() {
5960
task.task_cx = TaskContext::goto_restore(init_app_cx(i));
@@ -169,3 +170,23 @@ pub fn exit_current_and_run_next() {
169170
mark_current_exited();
170171
run_next_task();
171172
}
173+
174+
/// Record one syscall for current running task.
175+
pub fn record_current_syscall(syscall_id: usize) {
176+
if syscall_id >= MAX_SYSCALL_NUM {
177+
return;
178+
}
179+
let mut inner = TASK_MANAGER.inner.exclusive_access();
180+
let current = inner.current_task;
181+
inner.tasks[current].syscall_times[syscall_id] += 1;
182+
}
183+
184+
/// Get syscall count of current running task by syscall id.
185+
pub fn current_task_syscall_count(syscall_id: usize) -> usize {
186+
if syscall_id >= MAX_SYSCALL_NUM {
187+
return 0;
188+
}
189+
let inner = TASK_MANAGER.inner.exclusive_access();
190+
let current = inner.current_task;
191+
inner.tasks[current].syscall_times[syscall_id]
192+
}

os/src/task/task.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
33
use super::TaskContext;
44

5+
/// The max syscall id tracked by ch3 trace.
6+
pub const MAX_SYSCALL_NUM: usize = 512;
7+
58
/// The task control block (TCB) of a task.
69
#[derive(Copy, Clone)]
710
pub struct TaskControlBlock {
811
/// The task status in it's lifecycle
912
pub task_status: TaskStatus,
1013
/// The task context
1114
pub task_cx: TaskContext,
15+
/// Per-task syscall counter indexed by syscall id.
16+
pub syscall_times: [usize; MAX_SYSCALL_NUM],
1217
}
1318

1419
/// The status of a task

reports/ch3_sys_trace.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# ch3 `sys_trace` 实验报告
2+
3+
## 1. 实验目标
4+
在 ch3 已支持多任务分时调度的基础上,实现新的系统调用:
5+
6+
- 接口:`fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize`
7+
- 系统调用号:`410`
8+
9+
并满足三种行为:
10+
11+
1. `trace_request = 0`:读取当前任务地址 `id` 处 1 字节数据并返回。
12+
2. `trace_request = 1`:向当前任务地址 `id` 写入 `data as u8`,返回 `0`
13+
3. `trace_request = 2`:查询当前任务系统调用编号为 `id` 的调用次数,且本次 `sys_trace` 也要计入统计。
14+
4. 其他 `trace_request` 返回 `-1`
15+
16+
## 2. 需求分析与设计思路
17+
18+
### 2.1 关键需求
19+
- 需要按“任务”维度统计系统调用次数,而不是全局统计。
20+
- `trace_request = 2` 时,本次 `sys_trace` 调用本身也要被统计。
21+
- 本章不要求地址安全检查,允许直接读写用户地址。
22+
23+
### 2.2 设计决策
24+
为保证统计逻辑统一、且不遗漏任何系统调用,采用如下方案:
25+
26+
- 在内核系统调用总入口 `syscall()` 中统一计数。
27+
- 每个任务维护一个独立的 syscall 计数数组。
28+
- `sys_trace(request=2)` 仅做查询,不在 `sys_trace` 内重复计数。
29+
30+
这样可确保:
31+
- 任何 syscall 都会被自动统计;
32+
- 查询 `SYSCALL_TRACE(410)` 时,本次调用一定已经被计入。
33+
34+
## 3. 具体实现
35+
36+
### 3.1 数据结构扩展(按任务统计)
37+
文件:`os/src/task/task.rs`
38+
39+
- 新增常量:`MAX_SYSCALL_NUM: usize = 512`
40+
-`TaskControlBlock` 中新增字段:
41+
- `syscall_times: [usize; MAX_SYSCALL_NUM]`
42+
43+
作用:为每个任务保存独立的 syscall 计数表,索引即 syscall id。
44+
45+
### 3.2 任务初始化与访问接口
46+
文件:`os/src/task/mod.rs`
47+
48+
- 在任务数组初始化时,将 `syscall_times` 全部置零。
49+
- 新增接口:
50+
- `record_current_syscall(syscall_id: usize)`:给当前运行任务对应 syscall 计数加一。
51+
- `current_task_syscall_count(syscall_id: usize) -> usize`:读取当前任务某个 syscall 的计数。
52+
- 边界处理:当 `syscall_id >= MAX_SYSCALL_NUM` 时,写入忽略、查询返回 `0`,避免越界。
53+
54+
### 3.3 在 syscall 总入口统一计数
55+
文件:`os/src/syscall/mod.rs`
56+
57+
`pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize``match` 分发前增加:
58+
59+
```rust
60+
record_current_syscall(syscall_id);
61+
```
62+
63+
这一步是本次实现的核心:
64+
- 统一入口计数,避免分散在各个 `sys_xxx` 中导致遗漏;
65+
- 满足“本次 `sys_trace` 也计入统计”的要求。
66+
67+
### 3.4 实现 `sys_trace` 三种语义
68+
文件:`os/src/syscall/process.rs`
69+
70+
实现如下逻辑:
71+
72+
- `trace_request == 0``id``*const u8` 解引用并返回。
73+
- `trace_request == 1``id``*mut u8` 写入 `data as u8`,返回 `0`
74+
- `trace_request == 2`:返回 `current_task_syscall_count(id) as isize`
75+
- 其他:返回 `-1`
76+
77+
## 4. 关键正确性说明
78+
79+
### 4.1 为什么本次 `sys_trace` 会被计入?
80+
调用路径是:
81+
82+
用户态 `ecall` -> 内核 `syscall()` 总入口 -> `record_current_syscall(410)` -> 分发到 `sys_trace()`
83+
84+
因此在 `sys_trace(request=2)` 查询时,当前这次 `sys_trace` 已经先被统计,满足题目要求。
85+
86+
### 4.2 为什么使用“每任务计数”而不是全局计数?
87+
题目要求追踪“当前任务”的系统调用历史。使用 TCB 内部计数数组可天然保证任务间互不干扰。
88+
89+
## 5. 测试与验证
90+
执行命令:
91+
92+
```bash
93+
cd os
94+
make run CHAPTER=3 TEST=3 BASE=0
95+
```
96+
97+
该命令会构建并运行 ch3 普通测试(包含 `ch3_trace`)。
98+
99+
关键输出包含:
100+
- `Test trace OK!`
101+
- `Test sleep1 passed!`
102+
- `Test sleep OK!`
103+
104+
说明:`sys_trace` 的读/写/计数语义均通过当前实验用例验证。
105+
106+
## 6. 结果总结
107+
本次修改完成了 ch3 对 `sys_trace(410)` 的支持,核心点是:
108+
109+
- 在 syscall 总入口统一计数;
110+
- 将计数数据放入任务控制块实现“按任务追踪”;
111+
- 按题目定义实现 `sys_trace` 三种请求语义;
112+
- 通过 `ch3_trace` 用例验证功能正确。
113+
114+
后续在实现地址空间后,可进一步为读写地址行为增加合法性检查与隔离机制。

0 commit comments

Comments
 (0)