mirror of
https://github.com/LearningOS/rust-based-os-comp2022.git
synced 2026-05-10 07:41:44 +08:00
add os[1-8]-ref for os refereces, add guide, add README
This commit is contained in:
199
os5-ref/src/task/task.rs
Normal file
199
os5-ref/src/task/task.rs
Normal file
@@ -0,0 +1,199 @@
|
||||
//! Types related to task management & Functions for completely changing TCB
|
||||
|
||||
use super::TaskContext;
|
||||
use super::{pid_alloc, KernelStack, PidHandle};
|
||||
use crate::config::TRAP_CONTEXT;
|
||||
use crate::mm::{MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE};
|
||||
use crate::sync::UPSafeCell;
|
||||
use crate::trap::{trap_handler, TrapContext};
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefMut;
|
||||
|
||||
/// Task control block structure
|
||||
///
|
||||
/// Directly save the contents that will not change during running
|
||||
pub struct TaskControlBlock {
|
||||
// immutable
|
||||
/// Process identifier
|
||||
pub pid: PidHandle,
|
||||
/// Kernel stack corresponding to PID
|
||||
pub kernel_stack: KernelStack,
|
||||
// mutable
|
||||
inner: UPSafeCell<TaskControlBlockInner>,
|
||||
}
|
||||
|
||||
/// Structure containing more process content
|
||||
///
|
||||
/// Store the contents that will change during operation
|
||||
/// and are wrapped by UPSafeCell to provide mutual exclusion
|
||||
pub struct TaskControlBlockInner {
|
||||
/// The physical page number of the frame where the trap context is placed
|
||||
pub trap_cx_ppn: PhysPageNum,
|
||||
/// Application data can only appear in areas
|
||||
/// where the application address space is lower than base_size
|
||||
pub base_size: usize,
|
||||
/// Save task context
|
||||
pub task_cx: TaskContext,
|
||||
/// Maintain the execution status of the current process
|
||||
pub task_status: TaskStatus,
|
||||
/// Application address space
|
||||
pub memory_set: MemorySet,
|
||||
/// Parent process of the current process.
|
||||
/// Weak will not affect the reference count of the parent
|
||||
pub parent: Option<Weak<TaskControlBlock>>,
|
||||
/// A vector containing TCBs of all child processes of the current process
|
||||
pub children: Vec<Arc<TaskControlBlock>>,
|
||||
/// It is set when active exit or execution error occurs
|
||||
pub exit_code: i32,
|
||||
}
|
||||
|
||||
/// Simple access to its internal fields
|
||||
impl TaskControlBlockInner {
|
||||
/*
|
||||
pub fn get_task_cx_ptr2(&self) -> *const usize {
|
||||
&self.task_cx_ptr as *const usize
|
||||
}
|
||||
*/
|
||||
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()
|
||||
}
|
||||
fn get_status(&self) -> TaskStatus {
|
||||
self.task_status
|
||||
}
|
||||
pub fn is_zombie(&self) -> bool {
|
||||
self.get_status() == TaskStatus::Zombie
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskControlBlock {
|
||||
/// Get the mutex to get the RefMut TaskControlBlockInner
|
||||
pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskControlBlockInner> {
|
||||
self.inner.exclusive_access()
|
||||
}
|
||||
|
||||
/// Create a new process
|
||||
///
|
||||
/// At present, it is only used for the creation of initproc
|
||||
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();
|
||||
// push a task context which goes to trap_return to the top of kernel stack
|
||||
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,
|
||||
})
|
||||
},
|
||||
};
|
||||
// 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
|
||||
}
|
||||
/// Load a new elf to replace the original application address space and start execution
|
||||
pub fn exec(&self, elf_data: &[u8]) {
|
||||
// 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();
|
||||
|
||||
// **** access inner 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 trap_cx = inner.get_trap_cx();
|
||||
*trap_cx = TrapContext::app_init_context(
|
||||
entry_point,
|
||||
user_sp,
|
||||
KERNEL_SPACE.exclusive_access().token(),
|
||||
self.kernel_stack.get_top(),
|
||||
trap_handler as usize,
|
||||
);
|
||||
// **** release inner automatically
|
||||
}
|
||||
/// Fork from parent to child
|
||||
pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> {
|
||||
// ---- access parent PCB exclusively
|
||||
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();
|
||||
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,
|
||||
})
|
||||
},
|
||||
});
|
||||
// add child
|
||||
parent_inner.children.push(task_control_block.clone());
|
||||
// modify kernel_sp in trap_cx
|
||||
// **** access children 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 parent PCB automatically
|
||||
// **** release children PCB automatically
|
||||
}
|
||||
pub fn getpid(&self) -> usize {
|
||||
self.pid.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
/// task status: UnInit, Ready, Running, Exited
|
||||
pub enum TaskStatus {
|
||||
UnInit,
|
||||
Ready,
|
||||
Running,
|
||||
Zombie,
|
||||
}
|
||||
Reference in New Issue
Block a user