use super::TaskContext;
use crate::config::TRAP_CONTEXT_BASE;
use crate::mm::{
kernel_stack_position, MapPermission, MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE,
};
use crate::trap::{trap_handler, TrapContext};
pub struct TaskControlBlock {
pub task_cx: TaskContext,
pub task_status: TaskStatus,
pub memory_set: MemorySet,
pub trap_cx_ppn: PhysPageNum,
pub base_size: usize,
pub heap_bottom: usize,
pub program_brk: usize,
}
impl TaskControlBlock {
pub fn get_trap_cx(&self) -> &'static mut TrapContext {
self.trap_cx_ppn.get_mut()
}
pub fn get_user_token(&self) -> usize {
self.memory_set.token()
}
pub fn new(elf_data: &[u8], app_id: usize) -> Self {
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
let trap_cx_ppn = memory_set
.translate(VirtAddr::from(TRAP_CONTEXT_BASE).into())
.unwrap()
.ppn();
let task_status = TaskStatus::Ready;
let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id);
KERNEL_SPACE.exclusive_access().insert_framed_area(
kernel_stack_bottom.into(),
kernel_stack_top.into(),
MapPermission::R | MapPermission::W,
);
let task_control_block = Self {
task_status,
task_cx: TaskContext::goto_trap_return(kernel_stack_top),
memory_set,
trap_cx_ppn,
base_size: user_sp,
heap_bottom: user_sp,
program_brk: user_sp,
};
let trap_cx = task_control_block.get_trap_cx();
*trap_cx = TrapContext::app_init_context(
entry_point,
user_sp,
KERNEL_SPACE.exclusive_access().token(),
kernel_stack_top,
trap_handler as usize,
);
task_control_block
}
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;
}
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
}
}
}
#[derive(Copy, Clone, PartialEq)]
pub enum TaskStatus {
UnInit,
Ready,
Running,
Exited,
}