|
|
|
@ -1,16 +1,17 @@
|
|
|
|
|
use crate::mm::{
|
|
|
|
|
MemorySet,
|
|
|
|
|
KERNEL_SPACE,
|
|
|
|
|
VirtAddr,
|
|
|
|
|
translated_refmut,
|
|
|
|
|
};
|
|
|
|
|
use crate::task::TaskContext;
|
|
|
|
|
use crate::task::id::TaskUserRes;
|
|
|
|
|
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 super::TaskControlBlock;
|
|
|
|
|
use super::{PidHandle, pid_alloc};
|
|
|
|
|
use super::add_task;
|
|
|
|
|
use alloc::sync::{Weak, Arc};
|
|
|
|
|
use alloc::vec;
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
@ -25,14 +26,13 @@ pub struct ProcessControlBlock {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 tasks: Vec<Option<Arc<TaskControlBlock>>>,
|
|
|
|
|
pub task_res_allocator: RecycleAllocator,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -40,6 +40,7 @@ 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()) {
|
|
|
|
@ -49,9 +50,21 @@ impl ProcessControlBlockInner {
|
|
|
|
|
self.fd_table.len() - 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pub fn dealloc_trap_cx(&mut self, tid: usize) {
|
|
|
|
|
unimplemented!();
|
|
|
|
|
//self.memory_set.remove_area_with_start_vpn()
|
|
|
|
|
|
|
|
|
|
pub fn alloc_tid(&mut self) -> usize {
|
|
|
|
|
self.task_res_allocator.alloc()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn dealloc_tid(&mut self, tid: usize){
|
|
|
|
|
self.task_res_allocator.dealloc(tid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn thread_count(&self) -> usize {
|
|
|
|
|
self.tasks.len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_task(&self, tid: usize) -> Arc<TaskControlBlock> {
|
|
|
|
|
self.tasks[tid].as_ref().unwrap().clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -60,25 +73,15 @@ impl ProcessControlBlock {
|
|
|
|
|
self.inner.exclusive_access()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new(elf_data: &[u8]) -> Self {
|
|
|
|
|
pub fn new(elf_data: &[u8]) -> Arc<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 (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data);
|
|
|
|
|
// allocate a pid
|
|
|
|
|
let pid_handle = pid_alloc();
|
|
|
|
|
let kstack = kstack_alloc();
|
|
|
|
|
let kernel_stack_top = kstack.get_top();
|
|
|
|
|
let task_control_block = Self {
|
|
|
|
|
let process = Arc::new(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,
|
|
|
|
|
inner: unsafe { UPSafeCell::new(ProcessControlBlockInner {
|
|
|
|
|
is_zombie: false,
|
|
|
|
|
memory_set,
|
|
|
|
|
parent: None,
|
|
|
|
|
children: Vec::new(),
|
|
|
|
@ -91,33 +94,61 @@ impl ProcessControlBlock {
|
|
|
|
|
// 2 -> stderr
|
|
|
|
|
Some(Arc::new(Stdout)),
|
|
|
|
|
],
|
|
|
|
|
})},
|
|
|
|
|
};
|
|
|
|
|
// prepare TrapContext in user space
|
|
|
|
|
let trap_cx = task_control_block.inner_exclusive_access().get_trap_cx();
|
|
|
|
|
tasks: Vec::new(),
|
|
|
|
|
task_res_allocator: RecycleAllocator::new(),
|
|
|
|
|
})}
|
|
|
|
|
});
|
|
|
|
|
// create a main thread, we should allocate ustack and trap_cx here
|
|
|
|
|
let task = Arc::new(TaskControlBlock::new(
|
|
|
|
|
Arc::clone(&process),
|
|
|
|
|
ustack_base,
|
|
|
|
|
true,
|
|
|
|
|
));
|
|
|
|
|
// prepare trap_cx of main thread
|
|
|
|
|
let task_inner = task.inner_exclusive_access();
|
|
|
|
|
let trap_cx = task_inner.get_trap_cx();
|
|
|
|
|
let ustack_top = task_inner.res.ustack_top();
|
|
|
|
|
let kstack_top = task_inner.res.kstack_top();
|
|
|
|
|
drop(task_inner);
|
|
|
|
|
*trap_cx = TrapContext::app_init_context(
|
|
|
|
|
entry_point,
|
|
|
|
|
user_sp,
|
|
|
|
|
ustack_top,
|
|
|
|
|
KERNEL_SPACE.exclusive_access().token(),
|
|
|
|
|
kernel_stack_top,
|
|
|
|
|
kstack_top,
|
|
|
|
|
trap_handler as usize,
|
|
|
|
|
);
|
|
|
|
|
task_control_block
|
|
|
|
|
// add main thread to the process
|
|
|
|
|
let mut process_inner = process.inner_exclusive_access();
|
|
|
|
|
process_inner.tasks.push(Some(Arc::clone(&task)));
|
|
|
|
|
drop(process_inner);
|
|
|
|
|
// add main thread to scheduler
|
|
|
|
|
add_task(task);
|
|
|
|
|
process
|
|
|
|
|
}
|
|
|
|
|
pub fn exec(&self, elf_data: &[u8], args: Vec<String>) {
|
|
|
|
|
|
|
|
|
|
/// Only support processes with a single thread.
|
|
|
|
|
pub fn exec(self: &Arc<Self>, elf_data: &[u8], args: Vec<String>) {
|
|
|
|
|
assert_eq!(self.inner_exclusive_access().thread_count(), 1);
|
|
|
|
|
// 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();
|
|
|
|
|
let (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data);
|
|
|
|
|
let new_token = memory_set.token();
|
|
|
|
|
// substitute memory_set
|
|
|
|
|
self.inner_exclusive_access().memory_set = memory_set;
|
|
|
|
|
// then we alloc user resource for main thread again
|
|
|
|
|
// since memory_set has been changed
|
|
|
|
|
let task = self.inner_exclusive_access().get_task(0);
|
|
|
|
|
let mut task_inner = task.inner_exclusive_access();
|
|
|
|
|
task_inner.res.dealloc_tid();
|
|
|
|
|
task_inner.res.ustack_base = ustack_base;
|
|
|
|
|
task_inner.res.alloc_user_res();
|
|
|
|
|
// push arguments on user stack
|
|
|
|
|
let mut user_sp = task_inner.res.ustack_top();
|
|
|
|
|
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(),
|
|
|
|
|
new_token,
|
|
|
|
|
(argv_base + arg * core::mem::size_of::<usize>()) as *mut usize
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
@ -128,86 +159,84 @@ impl ProcessControlBlock {
|
|
|
|
|
*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;
|
|
|
|
|
*translated_refmut(new_token, p as *mut u8) = *c;
|
|
|
|
|
p += 1;
|
|
|
|
|
}
|
|
|
|
|
*translated_refmut(memory_set.token(), p as *mut u8) = 0;
|
|
|
|
|
*translated_refmut(new_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(),
|
|
|
|
|
task_inner.res.kstack_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
|
|
|
|
|
*task_inner.get_trap_cx() = trap_cx;
|
|
|
|
|
task_inner.task_cx = TaskContext::goto_trap_return(task_inner.res.kstack_top());
|
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
/// Only support processes with a single thread.
|
|
|
|
|
pub fn fork(self: &Arc<Self>) -> Arc<Self> {
|
|
|
|
|
let mut parent = self.inner_exclusive_access();
|
|
|
|
|
assert_eq!(parent.thread_count(), 1);
|
|
|
|
|
// clone parent's memory_set completely including trampoline/ustacks/trap_cxs
|
|
|
|
|
let memory_set = MemorySet::from_existed_user(&parent.memory_set);
|
|
|
|
|
// alloc a pid
|
|
|
|
|
let pid = pid_alloc();
|
|
|
|
|
// 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() {
|
|
|
|
|
for fd in parent.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,
|
|
|
|
|
})},
|
|
|
|
|
// create child process pcb
|
|
|
|
|
let child = Arc::new(Self {
|
|
|
|
|
pid,
|
|
|
|
|
inner: unsafe { UPSafeCell::new(ProcessControlBlockInner {
|
|
|
|
|
is_zombie: false,
|
|
|
|
|
memory_set,
|
|
|
|
|
parent: Some(Arc::downgrade(self)),
|
|
|
|
|
children: Vec::new(),
|
|
|
|
|
exit_code: 0,
|
|
|
|
|
fd_table: new_fd_table,
|
|
|
|
|
tasks: Vec::new(),
|
|
|
|
|
task_res_allocator: RecycleAllocator::new(),
|
|
|
|
|
})}
|
|
|
|
|
});
|
|
|
|
|
// 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
|
|
|
|
|
parent.children.push(Arc::clone(&child));
|
|
|
|
|
// create main thread of child process
|
|
|
|
|
let task = Arc::new(TaskControlBlock::new(
|
|
|
|
|
Arc::clone(&child),
|
|
|
|
|
parent.get_task(0).inner_exclusive_access().res.ustack_base(),
|
|
|
|
|
// here we do not allocate trap_cx or ustack again
|
|
|
|
|
// but mention that we allocate a new kstack here
|
|
|
|
|
false,
|
|
|
|
|
));
|
|
|
|
|
// attach task to child process
|
|
|
|
|
let mut child_inner = child.inner_exclusive_access();
|
|
|
|
|
child_inner.tasks.push(Some(Arc::clone(&task)));
|
|
|
|
|
drop(child_inner);
|
|
|
|
|
// modify kstack_top in trap_cx of this thread
|
|
|
|
|
let task_inner = task.inner_exclusive_access();
|
|
|
|
|
let trap_cx = task_inner.get_trap_cx();
|
|
|
|
|
trap_cx.kernel_sp = task_inner.res.kstack_top();
|
|
|
|
|
drop(task_inner);
|
|
|
|
|
// add this thread to scheduler
|
|
|
|
|
add_task(task);
|
|
|
|
|
child
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn getpid(&self) -> usize {
|
|
|
|
|
self.pid.0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|