Working on ch8
This commit is contained in:
parent
d574e7809a
commit
cb1d46c8ee
8 changed files with 365 additions and 327 deletions
|
@ -181,23 +181,7 @@ impl MemorySet {
|
||||||
// map user stack with U flags
|
// map user stack with U flags
|
||||||
let max_end_va: VirtAddr = max_end_vpn.into();
|
let max_end_va: VirtAddr = max_end_vpn.into();
|
||||||
let mut user_stack_bottom: usize = max_end_va.into();
|
let mut user_stack_bottom: usize = max_end_va.into();
|
||||||
// guard page
|
(memory_set, user_stack_bottom, elf.header.pt2.entry_point() as usize)
|
||||||
user_stack_bottom += PAGE_SIZE;
|
|
||||||
let user_stack_top = user_stack_bottom + USER_STACK_SIZE;
|
|
||||||
memory_set.push(MapArea::new(
|
|
||||||
user_stack_bottom.into(),
|
|
||||||
user_stack_top.into(),
|
|
||||||
MapType::Framed,
|
|
||||||
MapPermission::R | MapPermission::W | MapPermission::U,
|
|
||||||
), None);
|
|
||||||
// map TrapContext
|
|
||||||
memory_set.push(MapArea::new(
|
|
||||||
TRAP_CONTEXT.into(),
|
|
||||||
TRAMPOLINE.into(),
|
|
||||||
MapType::Framed,
|
|
||||||
MapPermission::R | MapPermission::W,
|
|
||||||
), None);
|
|
||||||
(memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
|
|
||||||
}
|
}
|
||||||
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
|
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
|
||||||
let mut memory_set = Self::new_bare();
|
let mut memory_set = Self::new_bare();
|
||||||
|
|
126
os/src/task/id.rs
Normal file
126
os/src/task/id.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use alloc::{vec::Vec, sync::Arc};
|
||||||
|
use lazy_static::*;
|
||||||
|
use crate::sync::UPSafeCell;
|
||||||
|
use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr};
|
||||||
|
use crate::config::{
|
||||||
|
PAGE_SIZE,
|
||||||
|
TRAMPOLINE,
|
||||||
|
KERNEL_STACK_SIZE,
|
||||||
|
};
|
||||||
|
use super::ProcessControlBlock;
|
||||||
|
|
||||||
|
pub struct RecycleAllocator {
|
||||||
|
current: usize,
|
||||||
|
recycled: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecycleAllocator {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
RecycleAllocator {
|
||||||
|
current: 0,
|
||||||
|
recycled: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn alloc(&mut self) -> usize {
|
||||||
|
if let Some(id) = self.recycled.pop() {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
self.current += 1;
|
||||||
|
self.current - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn dealloc(&mut self, id: usize) {
|
||||||
|
assert!(id < self.current);
|
||||||
|
assert!(
|
||||||
|
self.recycled.iter().find(|i| **i == id).is_none(),
|
||||||
|
"id {} has been deallocated!", id
|
||||||
|
);
|
||||||
|
self.recycled.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref PID_ALLOCATOR: UPSafeCell<RecycleAllocator> = unsafe {
|
||||||
|
UPSafeCell::new(RecycleAllocator::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
static ref KSTACK_ALLOCATOR: UPSafeCell<RecycleAllocator> = unsafe {
|
||||||
|
UPSafeCell::new(RecycleAllocator::new())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PidHandle(pub usize);
|
||||||
|
|
||||||
|
pub fn pid_alloc() -> PidHandle {
|
||||||
|
PidHandle(PID_ALLOCATOR.exclusive_access().alloc())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for PidHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
PID_ALLOCATOR.exclusive_access().dealloc(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return (bottom, top) of a kernel stack in kernel space.
|
||||||
|
pub fn kernel_stack_position(kstack_id: usize) -> (usize, usize) {
|
||||||
|
let top = TRAMPOLINE - kstack_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
|
||||||
|
let bottom = top - KERNEL_STACK_SIZE;
|
||||||
|
(bottom, top)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KernelStack(pub usize);
|
||||||
|
|
||||||
|
pub fn kstack_alloc() -> KernelStack {
|
||||||
|
let kstack_id = KSTACK_ALLOCATOR.exclusive_access().alloc();
|
||||||
|
let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id);
|
||||||
|
KERNEL_SPACE
|
||||||
|
.exclusive_access()
|
||||||
|
.insert_framed_area(
|
||||||
|
kstack_bottom.into(),
|
||||||
|
kstack_top.into(),
|
||||||
|
MapPermission::R | MapPermission::W,
|
||||||
|
);
|
||||||
|
KernelStack(kstack_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for KernelStack {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let (kernel_stack_bottom, _) = kernel_stack_position(self.0);
|
||||||
|
let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
|
||||||
|
KERNEL_SPACE
|
||||||
|
.exclusive_access()
|
||||||
|
.remove_area_with_start_vpn(kernel_stack_bottom_va.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KernelStack {
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn push_on_top<T>(&self, value: T) -> *mut T where
|
||||||
|
T: Sized, {
|
||||||
|
let kernel_stack_top = self.get_top();
|
||||||
|
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
|
||||||
|
unsafe { *ptr_mut = value; }
|
||||||
|
ptr_mut
|
||||||
|
}
|
||||||
|
pub fn get_top(&self) -> usize {
|
||||||
|
let (_, kernel_stack_top) = kernel_stack_position(self.0);
|
||||||
|
kernel_stack_top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TaskUserRes {
|
||||||
|
pub tid: usize,
|
||||||
|
pub kstack: KernelStack,
|
||||||
|
pub process: Arc<ProcessControlBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TaskUserRes {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// dealloc tid
|
||||||
|
let process = self.process.inner_exclusive_access();
|
||||||
|
process.task_res_allocator.dealloc(self.tid);
|
||||||
|
// dealloc trap_cx
|
||||||
|
process.dealloc_trap_cx(self.tid);
|
||||||
|
// kstack can be deallocated automatically
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,8 @@ mod switch;
|
||||||
mod task;
|
mod task;
|
||||||
mod manager;
|
mod manager;
|
||||||
mod processor;
|
mod processor;
|
||||||
mod pid;
|
mod id;
|
||||||
|
mod process;
|
||||||
|
|
||||||
use crate::fs::{open_file, OpenFlags};
|
use crate::fs::{open_file, OpenFlags};
|
||||||
use switch::__switch;
|
use switch::__switch;
|
||||||
|
@ -11,8 +12,10 @@ use task::{TaskControlBlock, TaskStatus};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use manager::fetch_task;
|
use manager::fetch_task;
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
pub use context::TaskContext;
|
use process::ProcessControlBlock;
|
||||||
|
use id::RecycleAllocator;
|
||||||
|
|
||||||
|
pub use context::TaskContext;
|
||||||
pub use processor::{
|
pub use processor::{
|
||||||
run_tasks,
|
run_tasks,
|
||||||
current_task,
|
current_task,
|
||||||
|
@ -22,7 +25,12 @@ pub use processor::{
|
||||||
schedule,
|
schedule,
|
||||||
};
|
};
|
||||||
pub use manager::add_task;
|
pub use manager::add_task;
|
||||||
pub use pid::{PidHandle, pid_alloc, KernelStack};
|
pub use id::{
|
||||||
|
PidHandle,
|
||||||
|
pid_alloc,
|
||||||
|
KernelStack,
|
||||||
|
kstack_alloc,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn suspend_current_and_run_next() {
|
pub fn suspend_current_and_run_next() {
|
||||||
// There must be an application running.
|
// There must be an application running.
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
use alloc::vec::Vec;
|
|
||||||
use lazy_static::*;
|
|
||||||
use crate::sync::UPSafeCell;
|
|
||||||
use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr};
|
|
||||||
use crate::config::{
|
|
||||||
PAGE_SIZE,
|
|
||||||
TRAMPOLINE,
|
|
||||||
KERNEL_STACK_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PidAllocator {
|
|
||||||
current: usize,
|
|
||||||
recycled: Vec<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PidAllocator {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
PidAllocator {
|
|
||||||
current: 0,
|
|
||||||
recycled: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn alloc(&mut self) -> PidHandle {
|
|
||||||
if let Some(pid) = self.recycled.pop() {
|
|
||||||
PidHandle(pid)
|
|
||||||
} else {
|
|
||||||
self.current += 1;
|
|
||||||
PidHandle(self.current - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn dealloc(&mut self, pid: usize) {
|
|
||||||
assert!(pid < self.current);
|
|
||||||
assert!(
|
|
||||||
self.recycled.iter().find(|ppid| **ppid == pid).is_none(),
|
|
||||||
"pid {} has been deallocated!", pid
|
|
||||||
);
|
|
||||||
self.recycled.push(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref PID_ALLOCATOR : UPSafeCell<PidAllocator> = unsafe {
|
|
||||||
UPSafeCell::new(PidAllocator::new())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PidHandle(pub usize);
|
|
||||||
|
|
||||||
impl Drop for PidHandle {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
//println!("drop pid {}", self.0);
|
|
||||||
PID_ALLOCATOR.exclusive_access().dealloc(self.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pid_alloc() -> PidHandle {
|
|
||||||
PID_ALLOCATOR.exclusive_access().alloc()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return (bottom, top) of a kernel stack in kernel space.
|
|
||||||
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
|
|
||||||
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
|
|
||||||
let bottom = top - KERNEL_STACK_SIZE;
|
|
||||||
(bottom, top)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct KernelStack {
|
|
||||||
pid: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KernelStack {
|
|
||||||
pub fn new(pid_handle: &PidHandle) -> Self {
|
|
||||||
let pid = pid_handle.0;
|
|
||||||
let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid);
|
|
||||||
KERNEL_SPACE
|
|
||||||
.exclusive_access()
|
|
||||||
.insert_framed_area(
|
|
||||||
kernel_stack_bottom.into(),
|
|
||||||
kernel_stack_top.into(),
|
|
||||||
MapPermission::R | MapPermission::W,
|
|
||||||
);
|
|
||||||
KernelStack {
|
|
||||||
pid: pid_handle.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn push_on_top<T>(&self, value: T) -> *mut T where
|
|
||||||
T: Sized, {
|
|
||||||
let kernel_stack_top = self.get_top();
|
|
||||||
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
|
|
||||||
unsafe { *ptr_mut = value; }
|
|
||||||
ptr_mut
|
|
||||||
}
|
|
||||||
pub fn get_top(&self) -> usize {
|
|
||||||
let (_, kernel_stack_top) = kernel_stack_position(self.pid);
|
|
||||||
kernel_stack_top
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for KernelStack {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let (kernel_stack_bottom, _) = kernel_stack_position(self.pid);
|
|
||||||
let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
|
|
||||||
KERNEL_SPACE
|
|
||||||
.exclusive_access()
|
|
||||||
.remove_area_with_start_vpn(kernel_stack_bottom_va.into());
|
|
||||||
}
|
|
||||||
}
|
|
213
os/src/task/process.rs
Normal file
213
os/src/task/process.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
use crate::mm::{
|
||||||
|
MemorySet,
|
||||||
|
KERNEL_SPACE,
|
||||||
|
VirtAddr,
|
||||||
|
translated_refmut,
|
||||||
|
};
|
||||||
|
use crate::trap::{TrapContext, trap_handler};
|
||||||
|
use crate::config::TRAP_CONTEXT;
|
||||||
|
use crate::sync::UPSafeCell;
|
||||||
|
use core::cell::RefMut;
|
||||||
|
use super::id::RecycleAllocator;
|
||||||
|
use super::{TaskContext, TaskControlBlock};
|
||||||
|
use super::{PidHandle, pid_alloc, KernelStack, kstack_alloc};
|
||||||
|
use alloc::sync::{Weak, Arc};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use alloc::string::String;
|
||||||
|
use crate::fs::{File, Stdin, Stdout};
|
||||||
|
|
||||||
|
pub struct ProcessControlBlock {
|
||||||
|
// immutable
|
||||||
|
pub pid: PidHandle,
|
||||||
|
// mutable
|
||||||
|
inner: UPSafeCell<ProcessControlBlockInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProcessControlBlockInner {
|
||||||
|
pub base_size: usize,
|
||||||
|
pub is_zombie: bool,
|
||||||
|
pub memory_set: MemorySet,
|
||||||
|
pub parent: Option<Weak<ProcessControlBlock>>,
|
||||||
|
pub children: Vec<Arc<ProcessControlBlock>>,
|
||||||
|
pub exit_code: i32,
|
||||||
|
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
|
||||||
|
pub tasks: Vec<Option<Weak<TaskControlBlock>>>,
|
||||||
|
pub task_res_allocator: RecycleAllocator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessControlBlockInner {
|
||||||
|
pub fn get_user_token(&self) -> usize {
|
||||||
|
self.memory_set.token()
|
||||||
|
}
|
||||||
|
pub fn alloc_fd(&mut self) -> usize {
|
||||||
|
if let Some(fd) = (0..self.fd_table.len())
|
||||||
|
.find(|fd| self.fd_table[*fd].is_none()) {
|
||||||
|
fd
|
||||||
|
} else {
|
||||||
|
self.fd_table.push(None);
|
||||||
|
self.fd_table.len() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn dealloc_trap_cx(&mut self, tid: usize) {
|
||||||
|
unimplemented!();
|
||||||
|
//self.memory_set.remove_area_with_start_vpn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessControlBlock {
|
||||||
|
pub fn inner_exclusive_access(&self) -> RefMut<'_, ProcessControlBlockInner> {
|
||||||
|
self.inner.exclusive_access()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(elf_data: &[u8]) -> Self {
|
||||||
|
// memory_set with elf program headers/trampoline/trap context/user stack
|
||||||
|
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
||||||
|
let trap_cx_ppn = memory_set
|
||||||
|
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
||||||
|
.unwrap()
|
||||||
|
.ppn();
|
||||||
|
// alloc a pid and a kernel stack in kernel space
|
||||||
|
let pid_handle = pid_alloc();
|
||||||
|
let kstack = kstack_alloc();
|
||||||
|
let kernel_stack_top = kstack.get_top();
|
||||||
|
let task_control_block = Self {
|
||||||
|
pid: pid_handle,
|
||||||
|
kernel_stack,
|
||||||
|
inner: unsafe { UPSafeCell::new(TaskControlBlockInner {
|
||||||
|
trap_cx_ppn,
|
||||||
|
base_size: user_sp,
|
||||||
|
task_cx: TaskContext::goto_trap_return(kernel_stack_top),
|
||||||
|
task_status: TaskStatus::Ready,
|
||||||
|
memory_set,
|
||||||
|
parent: None,
|
||||||
|
children: Vec::new(),
|
||||||
|
exit_code: 0,
|
||||||
|
fd_table: vec![
|
||||||
|
// 0 -> stdin
|
||||||
|
Some(Arc::new(Stdin)),
|
||||||
|
// 1 -> stdout
|
||||||
|
Some(Arc::new(Stdout)),
|
||||||
|
// 2 -> stderr
|
||||||
|
Some(Arc::new(Stdout)),
|
||||||
|
],
|
||||||
|
})},
|
||||||
|
};
|
||||||
|
// prepare TrapContext in user space
|
||||||
|
let trap_cx = task_control_block.inner_exclusive_access().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 exec(&self, elf_data: &[u8], args: Vec<String>) {
|
||||||
|
// memory_set with elf program headers/trampoline/trap context/user stack
|
||||||
|
let (memory_set, mut user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
||||||
|
let trap_cx_ppn = memory_set
|
||||||
|
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
||||||
|
.unwrap()
|
||||||
|
.ppn();
|
||||||
|
// push arguments on user stack
|
||||||
|
user_sp -= (args.len() + 1) * core::mem::size_of::<usize>();
|
||||||
|
let argv_base = user_sp;
|
||||||
|
let mut argv: Vec<_> = (0..=args.len())
|
||||||
|
.map(|arg| {
|
||||||
|
translated_refmut(
|
||||||
|
memory_set.token(),
|
||||||
|
(argv_base + arg * core::mem::size_of::<usize>()) as *mut usize
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
*argv[args.len()] = 0;
|
||||||
|
for i in 0..args.len() {
|
||||||
|
user_sp -= args[i].len() + 1;
|
||||||
|
*argv[i] = user_sp;
|
||||||
|
let mut p = user_sp;
|
||||||
|
for c in args[i].as_bytes() {
|
||||||
|
*translated_refmut(memory_set.token(), p as *mut u8) = *c;
|
||||||
|
p += 1;
|
||||||
|
}
|
||||||
|
*translated_refmut(memory_set.token(), p as *mut u8) = 0;
|
||||||
|
}
|
||||||
|
// make the user_sp aligned to 8B for k210 platform
|
||||||
|
user_sp -= user_sp % core::mem::size_of::<usize>();
|
||||||
|
|
||||||
|
// **** access current TCB exclusively
|
||||||
|
let mut inner = self.inner_exclusive_access();
|
||||||
|
// substitute memory_set
|
||||||
|
inner.memory_set = memory_set;
|
||||||
|
// update trap_cx ppn
|
||||||
|
inner.trap_cx_ppn = trap_cx_ppn;
|
||||||
|
// initialize trap_cx
|
||||||
|
let mut trap_cx = TrapContext::app_init_context(
|
||||||
|
entry_point,
|
||||||
|
user_sp,
|
||||||
|
KERNEL_SPACE.exclusive_access().token(),
|
||||||
|
self.kernel_stack.get_top(),
|
||||||
|
trap_handler as usize,
|
||||||
|
);
|
||||||
|
trap_cx.x[10] = args.len();
|
||||||
|
trap_cx.x[11] = argv_base;
|
||||||
|
*inner.get_trap_cx() = trap_cx;
|
||||||
|
// **** release current PCB
|
||||||
|
}
|
||||||
|
pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> {
|
||||||
|
// ---- hold parent PCB lock
|
||||||
|
let mut parent_inner = self.inner_exclusive_access();
|
||||||
|
// copy user space(include trap context)
|
||||||
|
let memory_set = MemorySet::from_existed_user(
|
||||||
|
&parent_inner.memory_set
|
||||||
|
);
|
||||||
|
let trap_cx_ppn = memory_set
|
||||||
|
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
||||||
|
.unwrap()
|
||||||
|
.ppn();
|
||||||
|
// alloc a pid and a kernel stack in kernel space
|
||||||
|
let pid_handle = pid_alloc();
|
||||||
|
let kernel_stack = KernelStack::new(&pid_handle);
|
||||||
|
let kernel_stack_top = kernel_stack.get_top();
|
||||||
|
// copy fd table
|
||||||
|
let mut new_fd_table: Vec<Option<Arc<dyn File + Send + Sync>>> = Vec::new();
|
||||||
|
for fd in parent_inner.fd_table.iter() {
|
||||||
|
if let Some(file) = fd {
|
||||||
|
new_fd_table.push(Some(file.clone()));
|
||||||
|
} else {
|
||||||
|
new_fd_table.push(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let task_control_block = Arc::new(TaskControlBlock {
|
||||||
|
pid: pid_handle,
|
||||||
|
kernel_stack,
|
||||||
|
inner: unsafe { UPSafeCell::new(TaskControlBlockInner {
|
||||||
|
trap_cx_ppn,
|
||||||
|
base_size: parent_inner.base_size,
|
||||||
|
task_cx: TaskContext::goto_trap_return(kernel_stack_top),
|
||||||
|
task_status: TaskStatus::Ready,
|
||||||
|
memory_set,
|
||||||
|
parent: Some(Arc::downgrade(self)),
|
||||||
|
children: Vec::new(),
|
||||||
|
exit_code: 0,
|
||||||
|
fd_table: new_fd_table,
|
||||||
|
})},
|
||||||
|
});
|
||||||
|
// add child
|
||||||
|
parent_inner.children.push(task_control_block.clone());
|
||||||
|
// modify kernel_sp in trap_cx
|
||||||
|
// **** access child PCB exclusively
|
||||||
|
let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx();
|
||||||
|
trap_cx.kernel_sp = kernel_stack_top;
|
||||||
|
// return
|
||||||
|
task_control_block
|
||||||
|
// **** release child PCB
|
||||||
|
// ---- release parent PCB
|
||||||
|
}
|
||||||
|
pub fn getpid(&self) -> usize {
|
||||||
|
self.pid.0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,224 +1,39 @@
|
||||||
use crate::mm::{
|
use alloc::sync::Arc;
|
||||||
MemorySet,
|
use crate::{mm::PhysPageNum, sync::UPSafeCell};
|
||||||
PhysPageNum,
|
use crate::trap::TrapContext;
|
||||||
KERNEL_SPACE,
|
use super::{
|
||||||
VirtAddr,
|
KernelStack,
|
||||||
translated_refmut,
|
ProcessControlBlock,
|
||||||
|
TaskContext
|
||||||
};
|
};
|
||||||
use crate::trap::{TrapContext, trap_handler};
|
|
||||||
use crate::config::TRAP_CONTEXT;
|
|
||||||
use crate::sync::UPSafeCell;
|
|
||||||
use core::cell::RefMut;
|
|
||||||
use super::TaskContext;
|
|
||||||
use super::{PidHandle, pid_alloc, KernelStack};
|
|
||||||
use alloc::sync::{Weak, Arc};
|
|
||||||
use alloc::vec;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use alloc::string::String;
|
|
||||||
use crate::fs::{File, Stdin, Stdout};
|
|
||||||
|
|
||||||
pub struct TaskControlBlock {
|
pub struct TaskControlBlock {
|
||||||
// immutable
|
// immutable
|
||||||
pub pid: PidHandle,
|
pub tid: usize,
|
||||||
pub kernel_stack: KernelStack,
|
pub kstack: KernelStack,
|
||||||
|
pub process: Arc<ProcessControlBlock>,
|
||||||
// mutable
|
// mutable
|
||||||
inner: UPSafeCell<TaskControlBlockInner>,
|
inner: UPSafeCell<TaskControlBlockInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TaskControlBlockInner {
|
pub struct TaskControlBlockInner {
|
||||||
pub trap_cx_ppn: PhysPageNum,
|
pub trap_cx_ppn: PhysPageNum,
|
||||||
pub base_size: usize,
|
|
||||||
pub task_cx: TaskContext,
|
pub task_cx: TaskContext,
|
||||||
pub task_status: TaskStatus,
|
pub task_status: TaskStatus,
|
||||||
pub memory_set: MemorySet,
|
|
||||||
pub parent: Option<Weak<TaskControlBlock>>,
|
|
||||||
pub children: Vec<Arc<TaskControlBlock>>,
|
|
||||||
pub exit_code: i32,
|
pub exit_code: i32,
|
||||||
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskControlBlockInner {
|
impl TaskControlBlockInner {
|
||||||
pub fn get_trap_cx(&self) -> &'static mut TrapContext {
|
pub fn get_trap_cx(&self) -> &'static mut TrapContext {
|
||||||
self.trap_cx_ppn.get_mut()
|
self.trap_cx_ppn.get_mut()
|
||||||
}
|
}
|
||||||
pub fn get_user_token(&self) -> usize {
|
|
||||||
self.memory_set.token()
|
|
||||||
}
|
|
||||||
fn get_status(&self) -> TaskStatus {
|
fn get_status(&self) -> TaskStatus {
|
||||||
self.task_status
|
self.task_status
|
||||||
}
|
}
|
||||||
pub fn is_zombie(&self) -> bool {
|
|
||||||
self.get_status() == TaskStatus::Zombie
|
|
||||||
}
|
|
||||||
pub fn alloc_fd(&mut self) -> usize {
|
|
||||||
if let Some(fd) = (0..self.fd_table.len())
|
|
||||||
.find(|fd| self.fd_table[*fd].is_none()) {
|
|
||||||
fd
|
|
||||||
} else {
|
|
||||||
self.fd_table.push(None);
|
|
||||||
self.fd_table.len() - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TaskControlBlock {
|
|
||||||
pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskControlBlockInner> {
|
|
||||||
self.inner.exclusive_access()
|
|
||||||
}
|
|
||||||
pub fn new(elf_data: &[u8]) -> Self {
|
|
||||||
// memory_set with elf program headers/trampoline/trap context/user stack
|
|
||||||
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
|
||||||
let trap_cx_ppn = memory_set
|
|
||||||
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
|
||||||
.unwrap()
|
|
||||||
.ppn();
|
|
||||||
// alloc a pid and a kernel stack in kernel space
|
|
||||||
let pid_handle = pid_alloc();
|
|
||||||
let kernel_stack = KernelStack::new(&pid_handle);
|
|
||||||
let kernel_stack_top = kernel_stack.get_top();
|
|
||||||
let task_control_block = Self {
|
|
||||||
pid: pid_handle,
|
|
||||||
kernel_stack,
|
|
||||||
inner: unsafe { UPSafeCell::new(TaskControlBlockInner {
|
|
||||||
trap_cx_ppn,
|
|
||||||
base_size: user_sp,
|
|
||||||
task_cx: TaskContext::goto_trap_return(kernel_stack_top),
|
|
||||||
task_status: TaskStatus::Ready,
|
|
||||||
memory_set,
|
|
||||||
parent: None,
|
|
||||||
children: Vec::new(),
|
|
||||||
exit_code: 0,
|
|
||||||
fd_table: vec![
|
|
||||||
// 0 -> stdin
|
|
||||||
Some(Arc::new(Stdin)),
|
|
||||||
// 1 -> stdout
|
|
||||||
Some(Arc::new(Stdout)),
|
|
||||||
// 2 -> stderr
|
|
||||||
Some(Arc::new(Stdout)),
|
|
||||||
],
|
|
||||||
})},
|
|
||||||
};
|
|
||||||
// prepare TrapContext in user space
|
|
||||||
let trap_cx = task_control_block.inner_exclusive_access().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 exec(&self, elf_data: &[u8], args: Vec<String>) {
|
|
||||||
// memory_set with elf program headers/trampoline/trap context/user stack
|
|
||||||
let (memory_set, mut user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
|
||||||
let trap_cx_ppn = memory_set
|
|
||||||
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
|
||||||
.unwrap()
|
|
||||||
.ppn();
|
|
||||||
// push arguments on user stack
|
|
||||||
user_sp -= (args.len() + 1) * core::mem::size_of::<usize>();
|
|
||||||
let argv_base = user_sp;
|
|
||||||
let mut argv: Vec<_> = (0..=args.len())
|
|
||||||
.map(|arg| {
|
|
||||||
translated_refmut(
|
|
||||||
memory_set.token(),
|
|
||||||
(argv_base + arg * core::mem::size_of::<usize>()) as *mut usize
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
*argv[args.len()] = 0;
|
|
||||||
for i in 0..args.len() {
|
|
||||||
user_sp -= args[i].len() + 1;
|
|
||||||
*argv[i] = user_sp;
|
|
||||||
let mut p = user_sp;
|
|
||||||
for c in args[i].as_bytes() {
|
|
||||||
*translated_refmut(memory_set.token(), p as *mut u8) = *c;
|
|
||||||
p += 1;
|
|
||||||
}
|
|
||||||
*translated_refmut(memory_set.token(), p as *mut u8) = 0;
|
|
||||||
}
|
|
||||||
// make the user_sp aligned to 8B for k210 platform
|
|
||||||
user_sp -= user_sp % core::mem::size_of::<usize>();
|
|
||||||
|
|
||||||
// **** access current TCB exclusively
|
|
||||||
let mut inner = self.inner_exclusive_access();
|
|
||||||
// substitute memory_set
|
|
||||||
inner.memory_set = memory_set;
|
|
||||||
// update trap_cx ppn
|
|
||||||
inner.trap_cx_ppn = trap_cx_ppn;
|
|
||||||
// initialize trap_cx
|
|
||||||
let mut trap_cx = TrapContext::app_init_context(
|
|
||||||
entry_point,
|
|
||||||
user_sp,
|
|
||||||
KERNEL_SPACE.exclusive_access().token(),
|
|
||||||
self.kernel_stack.get_top(),
|
|
||||||
trap_handler as usize,
|
|
||||||
);
|
|
||||||
trap_cx.x[10] = args.len();
|
|
||||||
trap_cx.x[11] = argv_base;
|
|
||||||
*inner.get_trap_cx() = trap_cx;
|
|
||||||
// **** release current PCB
|
|
||||||
}
|
|
||||||
pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> {
|
|
||||||
// ---- hold parent PCB lock
|
|
||||||
let mut parent_inner = self.inner_exclusive_access();
|
|
||||||
// copy user space(include trap context)
|
|
||||||
let memory_set = MemorySet::from_existed_user(
|
|
||||||
&parent_inner.memory_set
|
|
||||||
);
|
|
||||||
let trap_cx_ppn = memory_set
|
|
||||||
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
|
||||||
.unwrap()
|
|
||||||
.ppn();
|
|
||||||
// alloc a pid and a kernel stack in kernel space
|
|
||||||
let pid_handle = pid_alloc();
|
|
||||||
let kernel_stack = KernelStack::new(&pid_handle);
|
|
||||||
let kernel_stack_top = kernel_stack.get_top();
|
|
||||||
// copy fd table
|
|
||||||
let mut new_fd_table: Vec<Option<Arc<dyn File + Send + Sync>>> = Vec::new();
|
|
||||||
for fd in parent_inner.fd_table.iter() {
|
|
||||||
if let Some(file) = fd {
|
|
||||||
new_fd_table.push(Some(file.clone()));
|
|
||||||
} else {
|
|
||||||
new_fd_table.push(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let task_control_block = Arc::new(TaskControlBlock {
|
|
||||||
pid: pid_handle,
|
|
||||||
kernel_stack,
|
|
||||||
inner: unsafe { UPSafeCell::new(TaskControlBlockInner {
|
|
||||||
trap_cx_ppn,
|
|
||||||
base_size: parent_inner.base_size,
|
|
||||||
task_cx: TaskContext::goto_trap_return(kernel_stack_top),
|
|
||||||
task_status: TaskStatus::Ready,
|
|
||||||
memory_set,
|
|
||||||
parent: Some(Arc::downgrade(self)),
|
|
||||||
children: Vec::new(),
|
|
||||||
exit_code: 0,
|
|
||||||
fd_table: new_fd_table,
|
|
||||||
})},
|
|
||||||
});
|
|
||||||
// add child
|
|
||||||
parent_inner.children.push(task_control_block.clone());
|
|
||||||
// modify kernel_sp in trap_cx
|
|
||||||
// **** access child PCB exclusively
|
|
||||||
let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx();
|
|
||||||
trap_cx.kernel_sp = kernel_stack_top;
|
|
||||||
// return
|
|
||||||
task_control_block
|
|
||||||
// **** release child PCB
|
|
||||||
// ---- release parent PCB
|
|
||||||
}
|
|
||||||
pub fn getpid(&self) -> usize {
|
|
||||||
self.pid.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum TaskStatus {
|
pub enum TaskStatus {
|
||||||
Ready,
|
Ready,
|
||||||
Running,
|
Running,
|
||||||
Zombie,
|
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
nightly-2021-08-25
|
nightly-2021-09-15
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue