From 7fcb6536797716ed87c3b55624d8265e10d50ab9 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Thu, 1 Jun 2023 17:38:56 +0800 Subject: [PATCH] =?UTF-8?q?"=E4=BC=A4=E9=BD=BF=E9=BE=99"=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=A0=86=E7=A9=BA=E9=97=B4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch4/os/src/mm/memory_set.rs | 57 +++++++++++++++++++++++++++++++++-- ch4/os/src/syscall/mod.rs | 1 + ch4/os/src/syscall/process.rs | 11 ++++++- ch4/os/src/task/mod.rs | 11 +++++++ ch4/os/src/task/task.rs | 36 ++++++++++++++++++++-- 5 files changed, 111 insertions(+), 5 deletions(-) diff --git a/ch4/os/src/mm/memory_set.rs b/ch4/os/src/mm/memory_set.rs index 937ff32..ad8b250 100644 --- a/ch4/os/src/mm/memory_set.rs +++ b/ch4/os/src/mm/memory_set.rs @@ -152,6 +152,34 @@ impl MapArea { current_vpn = (current_vpn.0 + 1).into(); } } + // 当前段, 缩小到新的结束位置, 即把new_end后面的页, 都还给物理页帧管理器, 并取消映射(通过unmap_one方法即可) + pub fn shrink_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) { + let tmp_vpn_range = VPNRange{ + l: self.vpn_range.l, + r: new_end, + }; + for vpn in tmp_vpn_range { + self.unmap_one(page_table, vpn) + } + + // 注意 当前段的区间 也要调整哦new(self.vpn_range.get_start(), new_end); + self.vpn_range.r = new_end; + } + + + // 当前段, 把当前结束的位置, 扩展到新的结束的位置 + pub fn append_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) { + let tmp_vpn_range = VPNRange{ + l: self.vpn_range.r, + r: new_end, + }; + + for vpn in tmp_vpn_range { + self.map_one(page_table, vpn) + } + + self.vpn_range.r = new_end; + } } @@ -169,7 +197,6 @@ impl MemorySet { } } - pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) { let mut memory_set = Self::new(); // map trampoline @@ -245,7 +272,7 @@ impl MemorySet { None, ); - // used in sbrk + // 用户的堆空间段 只有一个起始位置即可, 因为 user_stack_top上面全是堆的空间(除了最后两页) memory_set.push( MapArea::from( user_stack_top.into(), @@ -391,4 +418,30 @@ impl MemorySet { ); memory_set } + + + // 当前地址空间, 缩小 虚拟地址start位置到虚拟地址 new end的位置 + pub fn shrink_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool { + // 起始虚拟地址所在的页 + let start_vpn = start.floor(); + + // 找到起始地址所在的段, 传入页表, 把当前段缩小到指定结束位置new_end + if let Some(area) = self.areas.iter_mut().find(|area| area.vpn_range.l == start_vpn) { + area.shrink_to(&mut self.page_table, new_end.ceil()); + true + } else { + false + } + } + + // 增加当前的地址空间 扩展为 start到 新的结束的位置 + pub fn append_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool { + // 同上, 找到逻辑段之后, 只不过这里是 扩展 + if let Some(area) = self.areas.iter_mut().find(|area| area.vpn_range.l == start.floor()) { + area.append_to(&mut self.page_table, new_end.ceil()); + true + } else { + false + } + } } diff --git a/ch4/os/src/syscall/mod.rs b/ch4/os/src/syscall/mod.rs index d2fb9e6..41d7c4e 100644 --- a/ch4/os/src/syscall/mod.rs +++ b/ch4/os/src/syscall/mod.rs @@ -18,6 +18,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_YIELD => sys_yield(), SYSCALL_GET_TIME => sys_get_time(), + SYSCALL_SBRK => sys_sbrk(args[0] as i32), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } \ No newline at end of file diff --git a/ch4/os/src/syscall/process.rs b/ch4/os/src/syscall/process.rs index 0f9b085..80706ef 100644 --- a/ch4/os/src/syscall/process.rs +++ b/ch4/os/src/syscall/process.rs @@ -1,7 +1,7 @@ //! App management syscalls // use crate::batch::run_next_app; use crate::println; -use crate::task::{exit_current_and_run_next, suspend_current_and_run_next}; +use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current_and_run_next}; use crate::timer::get_time_ms; /// 任务退出, 并立即切换任务 @@ -18,4 +18,13 @@ pub fn sys_yield() -> isize { pub fn sys_get_time() -> isize { get_time_ms() as isize +} + +// 根据传入的 size 对当前堆进行扩容和缩小 +pub fn sys_sbrk(size: i32) -> isize { + if let Some(old_brk) = change_program_brk(size) { + old_brk as isize + } else { + -1 + } } \ No newline at end of file diff --git a/ch4/os/src/task/mod.rs b/ch4/os/src/task/mod.rs index a289804..255bccb 100644 --- a/ch4/os/src/task/mod.rs +++ b/ch4/os/src/task/mod.rs @@ -151,6 +151,13 @@ impl TaskManager { let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task_id].get_user_token() } + + // 扩张/缩减, 当前应用的地址空间中的堆段, 指定字节的数据 + pub fn change_current_program_brk(&self, size: i32) -> Option { + let mut inner = self.inner.exclusive_access(); + let current_task_id = inner.current_task_id; + inner.tasks[current_task_id].change_program_brk(size) + } } @@ -217,6 +224,10 @@ pub fn exit_current_and_run_next(){ TASK_MANAGER.run_next_task(); } +// 扩张/缩减, 当前应用的地址空间中的堆段, 指定字节的数据 +pub fn change_program_brk(size: i32) -> Option { + TASK_MANAGER.change_current_program_brk(size) +} // 得到当前运行任务的 trap context 的地址 pub fn current_trap_cx() -> &'static mut TrapContext { diff --git a/ch4/os/src/task/task.rs b/ch4/os/src/task/task.rs index aa1ec83..4dfb19c 100644 --- a/ch4/os/src/task/task.rs +++ b/ch4/os/src/task/task.rs @@ -23,8 +23,9 @@ pub struct TaskControlBlock { pub memory_set: MemorySet, // tcb他自己的地址空间 pub trap_cx_ppn: PhysPageNum, // tcb访问 trap context所在的真实的物理页, 它对应逻辑页的次高页 pub base_size: usize, // 应用地址空间中从0x0开始到用户栈结束一共包含多少字节, 就是用户数据有多大 - pub heap_bottom: usize, // 堆底 - pub program_brk: usize, + pub heap_bottom: usize, // 堆的起始地址 这个一开始和base_size 是一样的 + pub program_brk: usize, // 这个一开始和base_size 是一样的, 表示进程当前的堆边界, 即堆的顶部地址, 它指向堆中最后一个已分配内存块的末尾, 下一个内存分配将从该地址开始 + // base_size(低地址) --- TRAP_CONTEXT(次高页) 的虚拟空间, 可以当做堆来使用 } impl TaskControlBlock { @@ -94,6 +95,37 @@ impl TaskControlBlock { // base_size 用户栈顶距离0x0的距离, 即用户应用已知的大小 // } + + // 扩张/缩减, 当前应用的地址空间中的堆段, 指定字节的数据 + pub fn change_program_brk(&mut self, size: i32) -> Option { + // 堆顶 + let old_break = self.program_brk; + // 申请后新的堆顶 + let new_brk = self.program_brk as isize + size as isize; + + // 如果新的堆顶 小于 堆底 直接返回(防止过度释放) + if new_brk < self.heap_bottom as isize { + return None; + } + + // 如果是小于0 说明需要释放,缩小堆的大小 + // 传入两个参数 堆底虚拟地址, 和 新的堆顶地址 + let result = if size < 0 { + self.memory_set + .shrink_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize)) + } else { + self.memory_set + .append_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize)) + }; + + // 如果成功就把新的堆顶的地址, 复制到结构提上记录, 并把旧的堆顶返回 + if result { + self.program_brk = new_brk as usize; + Some(old_break) + } else { + None + } + } } impl TaskControlBlock {