"伤齿龙" 增加堆空间功能

ch4
zhangxinyu 2 years ago
parent c273398dfa
commit 7fcb653679

@ -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
}
}
}

@ -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),
}
}

@ -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;
/// 任务退出, 并立即切换任务
@ -19,3 +19,12 @@ 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
}
}

@ -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<usize> {
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<usize> {
TASK_MANAGER.change_current_program_brk(size)
}
// 得到当前运行任务的 trap context 的地址
pub fn current_trap_cx() -> &'static mut TrapContext {

@ -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<usize> {
// 堆顶
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 {

Loading…
Cancel
Save