Skip to content

Commit 137881d

Browse files
committed
ch5 ok
1 parent b0a1419 commit 137881d

File tree

7 files changed

+138
-17
lines changed

7 files changed

+138
-17
lines changed

os/src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE;
2121
pub const CLOCK_FREQ: usize = 12500000;
2222
/// the physical memory end
2323
pub const MEMORY_END: usize = 0x88000000;
24+
25+
/// BigStride
26+
pub const BIG_STRIDE: usize = 1000;

os/src/mm/memory_set.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,6 @@ impl MemorySet {
304304
/// find target area by start_va, then insert it to areas
305305
pub fn find_area_insert(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) -> bool {
306306
if let Some(_area) = self.areas.iter().find(|area| {
307-
debug!("=============== insert ===============");
308-
debug!("area start: {}, end: {}", area.vpn_range.get_start().0, area.vpn_range.get_end().0);
309-
debug!("target area start: {}, end: {}", start_va.floor().0, end_va.ceil().0);
310-
debug!("======================================");
311307
area.vpn_range.get_start() < end_va.ceil() && area.vpn_range.get_end() > start_va.floor()
312308
}) {
313309
debug!("!!! find area has been used !!!");
@@ -321,10 +317,6 @@ impl MemorySet {
321317
/// find target area by start_va, then remove it from areas
322318
pub fn find_area_remove(&mut self, start_va: VirtAddr, end_va: VirtAddr) -> bool {
323319
if let Some(index) = self.areas.iter().position(|area| {
324-
debug!("=============== remove ===============");
325-
debug!("area start: {}, end: {}", area.vpn_range.get_start().0, area.vpn_range.get_end().0);
326-
debug!("target area start: {}, end: {}", start_va.floor().0, end_va.ceil().0);
327-
debug!("======================================");
328320
area.vpn_range.get_start() == start_va.floor() && area.vpn_range.get_end() == end_va.ceil()
329321
}) {
330322
self.areas[index].unmap(&mut self.page_table);

os/src/syscall/process.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use alloc::sync::Arc;
33

44
use crate::{
5-
loader::get_app_data_by_name, mm::{translated_physaddr, translated_refmut, translated_str, MapPermission, VirtAddr}, task::{add_task, current_task, current_user_token, exit_current_and_run_next, suspend_current_and_run_next}, timer::get_time_us
5+
loader::get_app_data_by_name, mm::{translated_physaddr, translated_refmut, translated_str, MapPermission, VirtAddr}, task::{add_task, current_task, current_user_token, exit_current_and_run_next, suspend_current_and_run_next, TaskControlBlock}, timer::get_time_us
66
};
77

88
#[repr(C)]
@@ -73,6 +73,7 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
7373
.iter()
7474
.any(|p| pid == -1 || pid as usize == p.getpid())
7575
{
76+
debug!("no such pid[{}]", pid);
7677
return -1;
7778
// ---- release current PCB
7879
}
@@ -90,8 +91,10 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
9091
let exit_code = child.inner_exclusive_access().exit_code;
9192
// ++++ release child PCB
9293
*translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code;
94+
debug!("found pid[{}]", found_pid);
9395
found_pid as isize
9496
} else {
97+
// debug!("pid[{}] is running", pid);
9598
-2
9699
}
97100
// ---- release current PCB automatically
@@ -197,7 +200,18 @@ pub fn sys_spawn(_path: *const u8) -> isize {
197200
"kernel:pid[{}] sys_spawn NOT IMPLEMENTED",
198201
current_task().unwrap().pid.0
199202
);
200-
-1
203+
let token = current_user_token();
204+
let path = translated_str(token, _path);
205+
if let Some(data) = get_app_data_by_name(&path) {
206+
let new_task: Arc<TaskControlBlock> = current_task().unwrap().spawn(data);
207+
let pid = new_task.getpid() as isize;
208+
add_task(new_task);
209+
debug!("add task pid[{}]", pid);
210+
return pid;
211+
} else {
212+
debug!("kernel: sys spawn error...");
213+
return -1;
214+
}
201215
}
202216

203217
// YOUR JOB: Set task priority.
@@ -206,5 +220,9 @@ pub fn sys_set_priority(_prio: isize) -> isize {
206220
"kernel:pid[{}] sys_set_priority NOT IMPLEMENTED",
207221
current_task().unwrap().pid.0
208222
);
209-
-1
223+
if _prio < 2 {
224+
return -1;
225+
}
226+
current_task().unwrap().set_priority(_prio as usize);
227+
return _prio;
210228
}

os/src/task/manager.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,41 @@
11
//!Implementation of [`TaskManager`]
22
use super::TaskControlBlock;
3+
use crate::config::BIG_STRIDE;
34
use crate::sync::UPSafeCell;
4-
use alloc::collections::VecDeque;
55
use alloc::sync::Arc;
6+
use alloc::vec::Vec;
67
use lazy_static::*;
78
///A array of `TaskControlBlock` that is thread-safe
89
pub struct TaskManager {
9-
ready_queue: VecDeque<Arc<TaskControlBlock>>,
10+
ready_queue: Vec<Arc<TaskControlBlock>>,
1011
}
1112

1213
/// A simple FIFO scheduler.
1314
impl TaskManager {
1415
///Creat an empty TaskManager
1516
pub fn new() -> Self {
1617
Self {
17-
ready_queue: VecDeque::new(),
18+
ready_queue: Vec::new(),
1819
}
1920
}
2021
/// Add process back to ready queue
2122
pub fn add(&mut self, task: Arc<TaskControlBlock>) {
22-
self.ready_queue.push_back(task);
23+
self.ready_queue.push(task);
2324
}
2425
/// Take a process out of the ready queue
2526
pub fn fetch(&mut self) -> Option<Arc<TaskControlBlock>> {
26-
self.ready_queue.pop_front()
27+
let mut min_stride_idx = 0;
28+
let mut min_stride = BIG_STRIDE;
29+
for (idx, task) in self.ready_queue.iter().enumerate() {
30+
let stride = task.inner_exclusive_access().stride as usize;
31+
if stride < min_stride {
32+
min_stride_idx = idx;
33+
min_stride = stride;
34+
}
35+
}
36+
let ret = self.ready_queue[min_stride_idx].clone();
37+
self.ready_queue.remove(min_stride_idx);
38+
return Some(ret);
2739
}
2840
}
2941

os/src/task/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub fn suspend_current_and_run_next() {
4848
drop(task_inner);
4949
// ---- release current PCB
5050

51+
task.update_stride();
5152
// push back to ready queue.
5253
add_task(task);
5354
// jump to scheduling cycle

os/src/task/task.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use super::TaskContext;
33
use super::{kstack_alloc, pid_alloc, KernelStack, PidHandle};
44
use crate::mm::{MapPermission, MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE};
5-
use crate::config::TRAP_CONTEXT_BASE;
5+
use crate::config::{BIG_STRIDE, TRAP_CONTEXT_BASE};
66
use crate::sync::UPSafeCell;
77
use crate::trap::{trap_handler, TrapContext};
88
use alloc::sync::{Arc, Weak};
@@ -68,6 +68,12 @@ pub struct TaskControlBlockInner {
6868

6969
/// Program break
7070
pub program_brk: usize,
71+
72+
/// Stride
73+
pub stride: u8,
74+
75+
/// Priority
76+
pub priority: usize
7177
}
7278

7379
impl TaskControlBlockInner {
@@ -118,6 +124,8 @@ impl TaskControlBlock {
118124
exit_code: 0,
119125
heap_bottom: user_sp,
120126
program_brk: user_sp,
127+
stride: 0,
128+
priority: 16
121129
})
122130
},
123131
};
@@ -191,6 +199,8 @@ impl TaskControlBlock {
191199
exit_code: 0,
192200
heap_bottom: parent_inner.heap_bottom,
193201
program_brk: parent_inner.program_brk,
202+
stride: parent_inner.stride,
203+
priority: parent_inner.priority
194204
})
195205
},
196206
});
@@ -206,6 +216,14 @@ impl TaskControlBlock {
206216
// ---- release parent PCB
207217
}
208218

219+
/// parent process spawn child process
220+
pub fn spawn(self: &Arc<Self>, elf_data: &[u8]) -> Arc<Self> {
221+
let new_tcb = Arc::new(TaskControlBlock::new(elf_data));
222+
new_tcb.inner_exclusive_access().parent = Some(Arc::downgrade(self));
223+
self.inner_exclusive_access().children.push(new_tcb.clone());
224+
new_tcb
225+
}
226+
209227
/// get pid of process
210228
pub fn getpid(&self) -> usize {
211229
self.pid.0
@@ -244,6 +262,18 @@ impl TaskControlBlock {
244262
pub fn find_area_remove(&self, start_va: VirtAddr, end_va: VirtAddr) -> bool {
245263
self.inner_exclusive_access().memory_set.find_area_remove(start_va, end_va)
246264
}
265+
266+
/// Set priority
267+
pub fn set_priority(&self, prio: usize) {
268+
self.inner_exclusive_access().priority = prio;
269+
}
270+
271+
/// Update stride
272+
pub fn update_stride(&self) {
273+
let mut inner = self.inner_exclusive_access();
274+
let pass = BIG_STRIDE / inner.priority;
275+
inner.stride += pass as u8;
276+
}
247277
}
248278

249279
#[derive(Copy, Clone, PartialEq)]

reports/lab3.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
### 总结实现的功能
2+
1. 由于获取当前进程的接口在本章发生了改变,因此修改了ch4中的mmap相关代码。
3+
2. 完成了`sys_spawn`系统调用的实现,通过调用`TaskControlBlock::new`方法直接新建一个进程,然后将新进程的`parent`设置为当前进程,向当前进程的`child`列表增加新进程的指针,最后通过`add_task()`方法将新进程加入到进程调度的队列中。
4+
3. 实现stride调度算法:
5+
-`TaskControlBlockInner`结构中加入新的成员`stride``priority`,新增了两个方法`set_priority()`(设置优先级),`update_stride()`(自动更新stride变量的值),在`suspend_current_and_run_next()`方法将当前任务状态更改时,调用`update_stride()`方法更新进程的stride值即可实现stride调度算法。
6+
- 修改`TaskManager.ready_queue`的类型为`Vec`,对应的`fetch()`方法将遍历`ready_queue`找到stride值最小的进程返回,同时将该进程从`ready_queue`中移除
7+
8+
### 问答题
9+
#### stride 算法深入
10+
stride 算法原理非常简单,但是有一个比较大的问题。例如两个 pass = 10 的进程,使用 8bit 无符号整形储存 stride, p1.stride = 255, p2.stride = 250,在 p2 执行一个时间片后,理论上下一次应该 p1 执行。
11+
12+
**实际情况是轮到 p1 执行吗?为什么?**
13+
*不是,由于使用 8bit 无符号整形储存 stride,因此p2在执行完一个时间片后,p2.stride = 250 + 10 = 260,此时会产生溢出,最后p2.stride = 4, 此时p2.stride < p1.stride,因此实际情况是p2会继续执行(不产生溢出异常的情况下)*
14+
15+
我们之前要求进程优先级 >= 2 其实就是为了解决这个问题。可以证明, 在不考虑溢出的情况下 , 在进程优先级全部 >= 2 的情况下,如果严格按照算法执行,那么 STRIDE_MAX – STRIDE_MIN <= BigStride / 2。
16+
17+
为什么?尝试简单说明(不要求严格证明)。
18+
已知 `P.pass = BigStride / P.prio`,且 `P.prio >= 2`的情况下,
19+
可得`P.pass <= (BigStride / 2)`
20+
为了让算法中程序运行的次数大致与其优先级呈正比,那么
21+
`STRIDE_MAX – STRIDE_MIN <= MAX(P.pass)`,也就是`STRIDE_MAX – STRIDE_MIN <= BigStride / 2`
22+
23+
24+
已知以上结论,考虑溢出的情况下,可以为 Stride 设计特别的比较器,让 BinaryHeap<Stride> 的 pop 方法能返回真正最小的 Stride。补全下列代码中的 partial_cmp 函数,假设两个 Stride 永远不会相等。
25+
``` rust
26+
use core::cmp::Ordering;
27+
28+
struct Stride(u64);
29+
30+
impl PartialOrd for Stride {
31+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
32+
let self_value = self.0 as i8;
33+
let other_value = other.0 as i8;
34+
let pass_max = BigStride / 2;
35+
if self_value > 0 && other_value < 0 && self_value - other_value > pass_max {
36+
Some(Ordering::Less)
37+
} else if self_value < 0 && other_value > 0 && other_value - self_value > pass_max {
38+
Some(Ordering::Grater)
39+
} else {
40+
Some(self_value.cmp(&other_value))
41+
}
42+
}
43+
}
44+
45+
impl PartialEq for Stride {
46+
fn eq(&self, other: &Self) -> bool {
47+
false
48+
}
49+
}
50+
51+
```
52+
53+
54+
### 荣誉准则
55+
1. 在完成本次实验的过程(含此前学习的过程)中,我曾分别与 以下各位 就(与本次实验相关的)以下方面做过交流,还在代码中对应的位置以注释形式记录了具体的交流对象及内容:
56+
57+
向claude3.7老师请教了许多问题,感谢它的帮助
58+
59+
2. 此外,我也参考了 以下资料 ,还在代码中对应的位置以注释形式记录了具体的参考来源及内容:
60+
61+
参考了 https://cheats.rs/ 手册的一些语法细节。
62+
63+
3. 我独立完成了本次实验除以上方面之外的所有工作,包括代码与文档。 我清楚地知道,从以上方面获得的信息在一定程度上降低了实验难度,可能会影响起评分。
64+
65+
4. 我从未使用过他人的代码,不管是原封不动地复制,还是经过了某些等价转换。 我未曾也不会向他人(含此后各届同学)复制或公开我的实验代码,我有义务妥善保管好它们。 我提交至本实验的评测系统的代码,均无意于破坏或妨碍任何计算机系统的正常运转。 我清楚地知道,以上情况均为本课程纪律所禁止,若违反,对应的实验成绩将按“-100”分计。

0 commit comments

Comments
 (0)