From 0ec5ad80562c8a030554d0448c5d7bc299707f05 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 25 Jan 2019 22:58:49 +0800 Subject: [PATCH] split Process and Thread --- docs/2_OSLab/g2/context.md | 8 +- kernel/src/process/mod.rs | 22 +++-- kernel/src/process/{context.rs => structs.rs} | 88 +++++++++++-------- kernel/src/shell.rs | 6 +- kernel/src/syscall.rs | 35 ++++---- 5 files changed, 92 insertions(+), 67 deletions(-) rename kernel/src/process/{context.rs => structs.rs} (75%) diff --git a/docs/2_OSLab/g2/context.md b/docs/2_OSLab/g2/context.md index 1372c65..6805901 100644 --- a/docs/2_OSLab/g2/context.md +++ b/docs/2_OSLab/g2/context.md @@ -1,6 +1,6 @@ # 上下文切换 -平台无关的代码位于 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs) 中,而平台相关(aarch64)的代码位于 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs) 中。 +平台无关的代码位于 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs) 中,而平台相关(aarch64)的代码位于 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs) 中。 ## 相关数据结构 @@ -56,7 +56,7 @@ } ``` - 每个进程控制块 `Process` ([kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L13)) 都会维护一个平台相关的 `Context` 对象,在 AArch64 中包含下列信息: + 每个进程控制块 `Process` ([kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L13)) 都会维护一个平台相关的 `Context` 对象,在 AArch64 中包含下列信息: 1. `stack_top`:内核栈顶地址 2. `ttbr`:页表基址 @@ -64,7 +64,7 @@ ## 切换流程 -在 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L22) 里,`switch_to()` 是平台无关的切换函数,最终会调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L129) 里平台相关的切换函数 `Context::switch()`: +在 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L22) 里,`switch_to()` 是平台无关的切换函数,最终会调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L129) 里平台相关的切换函数 `Context::switch()`: ```rust pub unsafe fn switch(&mut self, target: &mut Self) { @@ -190,7 +190,7 @@ ret 2. 创建新的**用户线程**:解析 ELF 文件。 3. 从一个线程 **fork** 出一个新线程:通过 `fork` 系统调用。 -三种线程的平台无关创建流程实现在 [kernel/src/process/context.rs](../../../kernel/src/process/context.rs#L40) 里,最终会分别调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L146) 里的 `new_kernel_thread()`、`new_user_thread()` 和 `new_fork()` 这三个函数创建平台相关的 `Context` 结构。 +三种线程的平台无关创建流程实现在 [kernel/src/process/context.rs](../../../kernel/src/process/structs.rs#L40) 里,最终会分别调用 [kernel/src/arch/aarch64/interrupt/context.rs](../../../kernel/src/arch/aarch64/interrupt/context.rs#L146) 里的 `new_kernel_thread()`、`new_user_thread()` 和 `new_fork()` 这三个函数创建平台相关的 `Context` 结构。 在这三个函数里,会构造 `ContextData` 与 `TrapFrame` 结构,构成一个 `InitStack`,并向新线程的内核栈压入 `InitStack` 结构,最后将新内核栈顶地址、页表基址等信息构成 `Context` 结构返回。这两个结构的构造方式如下: diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 73cbb23..fe5dd21 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,11 +1,12 @@ -pub use self::context::Process; +pub use self::structs::*; pub use rcore_thread::*; use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM}; use crate::arch::cpu; use alloc::{boxed::Box, sync::Arc}; +use spin::MutexGuard; use log::*; -pub mod context; +pub mod structs; pub fn init() { // NOTE: max_time_slice <= 5 to ensure 'priority' test pass @@ -14,7 +15,7 @@ pub fn init() { unsafe { for cpu_id in 0..MAX_CPU_NUM { - PROCESSORS[cpu_id].init(cpu_id, Process::new_init(), manager.clone()); + PROCESSORS[cpu_id].init(cpu_id, Thread::new_init(), manager.clone()); } } @@ -25,7 +26,7 @@ pub fn init() { use core::str::FromStr; let cores = usize::from_str(env!("SMP")).unwrap(); for i in 0..cores { - manager.add(Process::new_kernel(idle, i), 0); + manager.add(Thread::new_kernel(idle, i), 0); } crate::shell::run_user_shell(); @@ -34,12 +35,17 @@ pub fn init() { static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()]; -/// Get current thread struct +/// Get current process +pub fn process() -> MutexGuard<'static, Process> { + current_thread().proc.lock() +} + +/// Get current thread /// /// FIXME: It's obviously unsafe to get &mut ! -pub fn process() -> &'static mut Process { +pub fn current_thread() -> &'static mut Thread { use core::mem::transmute; - let (process, _): (&mut Process, *const ()) = unsafe { + let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) }; process @@ -55,5 +61,5 @@ pub fn processor() -> &'static Processor { #[no_mangle] pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box { - Process::new_kernel(entry, arg) + Thread::new_kernel(entry, arg) } diff --git a/kernel/src/process/context.rs b/kernel/src/process/structs.rs similarity index 75% rename from kernel/src/process/context.rs rename to kernel/src/process/structs.rs index ac6dbca..7a66a4c 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/structs.rs @@ -3,54 +3,64 @@ use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::V use log::*; use simple_filesystem::file::File; use spin::Mutex; -use rcore_thread::Context; use xmas_elf::{ElfFile, header, program::{Flags, Type}}; -use crate::arch::interrupt::{Context as ArchContext, TrapFrame}; +use crate::arch::interrupt::{Context, TrapFrame}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; // TODO: avoid pub +pub struct Thread { + pub context: Context, + pub kstack: KernelStack, + pub proc: Arc>, +} + pub struct Process { - pub arch: ArchContext, pub memory_set: MemorySet, - pub kstack: KernelStack, pub files: BTreeMap>>, pub cwd: String, } -impl Context for Process { - unsafe fn switch_to(&mut self, target: &mut Context) { +/// Let `rcore_thread` can switch between our `Thread` +impl rcore_thread::Context for Thread { + unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) { use core::mem::transmute; - let (target, _): (&mut Process, *const ()) = transmute(target); - self.arch.switch(&mut target.arch); + let (target, _): (&mut Thread, *const ()) = transmute(target); + self.context.switch(&mut target.context); } } -impl Process { - pub unsafe fn new_init() -> Box { - Box::new(Process { - arch: ArchContext::null(), - memory_set: MemorySet::new(), +impl Thread { + /// Make a struct for the init thread + pub unsafe fn new_init() -> Box { + Box::new(Thread { + context: Context::null(), kstack: KernelStack::new(), - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set: MemorySet::new(), + files: BTreeMap::default(), + cwd: String::new(), + })), }) } - pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { + /// Make a new kernel thread starting from `entry` with `arg` + pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { let memory_set = MemorySet::new(); let kstack = KernelStack::new(); - Box::new(Process { - arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, - memory_set, + Box::new(Thread { + context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, kstack, - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files: BTreeMap::default(), + cwd: String::new(), + })), }) } - /// Make a new user thread from ELF data - pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box + /// Make a new user process from ELF `data` + pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box where Iter: Iterator { // Parse elf @@ -94,23 +104,25 @@ impl Process { let kstack = KernelStack::new(); - Box::new(Process { - arch: unsafe { - ArchContext::new_user_thread( + Box::new(Thread { + context: unsafe { + Context::new_user_thread( entry_addr, ustack_top, kstack.top(), is32, memory_set.token()) }, - memory_set, kstack, - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files: BTreeMap::default(), + cwd: String::new(), + })), }) } - /// Fork - pub fn fork(&self, tf: &TrapFrame) -> Box { + /// Fork a new process from current one + pub fn fork(&self, tf: &TrapFrame) -> Box { info!("COME into fork!"); // Clone memory set, make a new page table - let memory_set = self.memory_set.clone(); + let memory_set = self.proc.lock().memory_set.clone(); info!("finish mmset clone in fork!"); // MMU: copy data to the new space @@ -126,12 +138,14 @@ impl Process { info!("temporary copy data!"); let kstack = KernelStack::new(); - Box::new(Process { - arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) }, - memory_set, + Box::new(Thread { + context: unsafe { Context::new_fork(tf, kstack.top(), memory_set.token()) }, kstack, - files: BTreeMap::default(), - cwd: String::new(), + proc: Arc::new(Mutex::new(Process { + memory_set, + files: BTreeMap::default(), + cwd: String::new(), + })), }) } } diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index bdfea25..e2ed691 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -10,9 +10,9 @@ pub fn run_user_shell() { println!("Going to user mode shell."); println!("Use 'ls' to list available programs."); let data = inode.read_as_vec().unwrap(); - processor().manager().add(Process::new_user(data.as_slice(), "sh".split(' ')), 0); + processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')), 0); } else { - processor().manager().add(Process::new_kernel(shell, 0), 0); + processor().manager().add(Thread::new_kernel(shell, 0), 0); } } @@ -29,7 +29,7 @@ pub extern fn shell(_arg: usize) -> ! { let name = cmd.split(' ').next().unwrap(); if let Ok(file) = ROOT_INODE.lookup(name) { let data = file.read_as_vec().unwrap(); - let pid = processor().manager().add(Process::new_user(data.as_slice(), cmd.split(' ')), thread::current().id()); + let pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')), thread::current().id()); unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); } else { println!("Program not exist"); diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index a9efc21..cad1e50 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -3,7 +3,7 @@ use simple_filesystem::{INode, file::File, FileInfo, FileType, FsError}; use core::{slice, str}; use alloc::{sync::Arc, vec::Vec, string::String}; -use spin::Mutex; +use spin::{Mutex, MutexGuard}; use log::*; use bitflags::bitflags; use crate::arch::interrupt::TrapFrame; @@ -61,7 +61,8 @@ fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { // TODO: check ptr info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts_mut(base, len) }; - let len = get_file(fd)?.lock().read(slice)?; + let proc = process(); + let len = get_file(&proc, fd)?.lock().read(slice)?; Ok(len as isize) } @@ -69,7 +70,8 @@ fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { // TODO: check ptr info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts(base, len) }; - let len = get_file(fd)?.lock().write(slice)?; + let proc = process(); + let len = get_file(&proc, fd)?.lock().write(slice)?; Ok(len as isize) } @@ -103,7 +105,8 @@ fn sys_close(fd: usize) -> SysResult { fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { // TODO: check ptr info!("fstat: {}", fd); - let file = get_file(fd)?; + let proc = process(); + let file = get_file(&proc, fd)?; let stat = Stat::from(file.lock().info()?); unsafe { stat_ptr.write(stat); } Ok(0) @@ -115,7 +118,8 @@ fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { // TODO: check ptr info!("getdirentry: {}", fd); - let file = get_file(fd)?; + let proc = process(); + let file = get_file(&proc, fd)?; let dentry = unsafe { &mut *dentry_ptr }; if !dentry.check() { return Err(SysError::Inval); @@ -131,7 +135,8 @@ fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { fn sys_dup(fd1: usize, fd2: usize) -> SysResult { info!("dup: {} {}", fd1, fd2); - let file = get_file(fd1)?; + let proc = process(); + let file = get_file(&proc, fd1)?; if process().files.contains_key(&fd2) { return Err(SysError::Inval); } @@ -141,7 +146,7 @@ fn sys_dup(fd1: usize, fd2: usize) -> SysResult { /// Fork the current process. Return the child's PID. fn sys_fork(tf: &TrapFrame) -> SysResult { - let context = process().fork(tf); + let context = current_thread().fork(tf); let pid = processor().manager().add(context, thread::current().id()); info!("fork: {} -> {}", thread::current().id(), pid); Ok(pid as isize) @@ -207,19 +212,19 @@ fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapF unsafe { buf.set_len(size); } inode.read_at(0, buf.as_mut_slice())?; - // Make new Context + // Make new Thread let iter = args.iter().map(|s| s.as_str()); - let mut context = Process::new_user(buf.as_slice(), iter); + let mut thread = Thread::new_user(buf.as_slice(), iter); // Activate new page table - unsafe { context.memory_set.activate(); } + unsafe { thread.proc.lock().memory_set.activate(); } // Modify the TrapFrame - *tf = unsafe { context.arch.get_init_tf() }; + *tf = unsafe { thread.context.get_init_tf() }; // Swap Context but keep KStack - ::core::mem::swap(&mut process().kstack, &mut context.kstack); - ::core::mem::swap(process(), &mut *context); + ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); + ::core::mem::swap(current_thread(), &mut *thread); Ok(0) } @@ -278,8 +283,8 @@ fn sys_putc(c: char) -> SysResult { Ok(0) } -fn get_file(fd: usize) -> Result<&'static Arc>, SysError> { - process().files.get(&fd).ok_or(SysError::Inval) +fn get_file<'a>(proc: &'a MutexGuard<'static, Process>, fd: usize) -> Result<&'a Arc>, SysError> { + proc.files.get(&fd).ok_or(SysError::Inval) } pub type SysResult = Result;