From f7eb09e85625cb7b605bc74e2bd1cf1991292741 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 24 Oct 2018 00:27:25 +0800 Subject: [PATCH] Multicore processing WORKS! Basically ... - Rewrite processor.rs Refactor to `Processor` & `ProcessManager` - Use Box instead of generic. - Wait/sleep/wakeup is not supported yet. I'm considering to implement them with WaitQueue. --- crate/process/Cargo.toml | 1 + crate/process/src/lib.rs | 1 + crate/process/src/processor.rs | 395 ++++++++++++++------------------- crate/process/src/thread.rs | 49 ++-- kernel/Cargo.lock | 1 + kernel/src/arch/x86_64/mod.rs | 3 +- kernel/src/fs.rs | 4 +- kernel/src/lib.rs | 11 +- kernel/src/process/context.rs | 56 ++--- kernel/src/process/mod.rs | 56 ++--- kernel/src/syscall.rs | 33 +-- kernel/src/trap.rs | 23 +- 12 files changed, 273 insertions(+), 360 deletions(-) diff --git a/crate/process/Cargo.toml b/crate/process/Cargo.toml index c73e482..72a3883 100644 --- a/crate/process/Cargo.toml +++ b/crate/process/Cargo.toml @@ -5,3 +5,4 @@ authors = ["WangRunji "] [dependencies] log = "0.4" +spin = "0.4" \ No newline at end of file diff --git a/crate/process/src/lib.rs b/crate/process/src/lib.rs index e3d2554..625e2b6 100644 --- a/crate/process/src/lib.rs +++ b/crate/process/src/lib.rs @@ -5,6 +5,7 @@ extern crate alloc; #[macro_use] extern crate log; +extern crate spin; // To use `println!` in test #[cfg(test)] diff --git a/crate/process/src/processor.rs b/crate/process/src/processor.rs index 7db17f6..8de3075 100644 --- a/crate/process/src/processor.rs +++ b/crate/process/src/processor.rs @@ -1,273 +1,208 @@ -use alloc::{boxed::Box, collections::BTreeMap}; -use scheduler::*; -use event_hub::EventHub; -use util::GetMut2; -use core::fmt::Debug; - -#[derive(Debug)] -pub struct Process { - pid: Pid, - parent: Pid, - status: Status, - context: T, +use alloc::boxed::Box; +use alloc::vec::Vec; +use alloc::sync::Arc; +use spin::Mutex; +use scheduler::Scheduler; +use core::cell::UnsafeCell; + +/// Process executor +/// +/// Per-CPU struct. Defined at global. +/// Only accessed by associated CPU with interrupt disabled. +#[derive(Default)] +pub struct Processor { + inner: UnsafeCell>, } -pub type Pid = usize; -pub type ErrorCode = usize; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Status { - Ready, - Running, - Waiting(Pid), - Sleeping, - Exited(ErrorCode), -} +unsafe impl Sync for Processor {} -pub trait Context: Debug { - unsafe fn switch(&mut self, target: &mut Self); - fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self; +struct ProcessorInner { + id: usize, + proc: Option<(Pid, Box)>, + loop_context: Box, + manager: Arc, } -pub struct Processor_ { - procs: BTreeMap>, - current_pid: Pid, - event_hub: EventHub, - // WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow - scheduler: S, -} - -impl Process { - fn exit_code(&self) -> Option { - match self.status { - Status::Exited(code) => Some(code), - _ => None, - } +impl Processor { + pub const fn new() -> Self { + Processor { inner: UnsafeCell::new(None) } } -} -// TODO: 除schedule()外的其它函数,应该只设置进程状态,不应调用schedule -impl Processor_ { - pub fn new(init_context: T, scheduler: S) -> Self { - let init_proc = Process { - pid: 0, - parent: 0, - status: Status::Running, - context: init_context, - }; - Processor_ { - procs: { - let mut map = BTreeMap::>::new(); - map.insert(0, init_proc); - map - }, - current_pid: 0, - event_hub: EventHub::new(), - scheduler, + pub unsafe fn init(&self, id: usize, context: Box, manager: Arc) { + unsafe { + *self.inner.get() = Some(ProcessorInner { + id, + proc: None, + loop_context: context, + manager, + }); } } - pub fn set_priority(&mut self, priority: u8) { - self.scheduler.set_priority(self.current_pid, priority); - } - - pub fn yield_now(&mut self) { - let pid = self.current_pid; - self.set_status(pid, Status::Ready); - } - - fn alloc_pid(&self) -> Pid { - let mut next: Pid = 0; - for &i in self.procs.keys() { - if i != next { - return next; - } else { - next = i + 1; + fn inner(&self) -> &mut ProcessorInner { + unsafe { &mut *self.inner.get() }.as_mut() + .expect("Processor is not initialized") + } + + /// Begin running processes after CPU setup. + /// + /// This function never returns. It loops, doing: + /// - choose a process to run + /// - switch to start running that process + /// - eventually that process transfers control + /// via switch back to the scheduler. + pub fn run(&self) -> ! { + let inner = self.inner(); + loop { + let proc = inner.manager.run(inner.id); + trace!("CPU{} begin running process {}", inner.id, proc.0); + inner.proc = Some(proc); + unsafe { + inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1); } + let (pid, context) = inner.proc.take().unwrap(); + trace!("CPU{} stop running process {}", inner.id, pid); + inner.manager.stop(pid, context); } - return next; } - fn set_status(&mut self, pid: Pid, status: Status) { - let status0 = self.get(pid).status.clone(); - match (&status0, &status) { - (&Status::Ready, &Status::Ready) => return, - (&Status::Ready, _) => self.scheduler.remove(pid), - (_, &Status::Ready) => self.scheduler.insert(pid), - _ => {} + /// Called by process running on this Processor. + /// Yield and reschedule. + pub fn yield_now(&self) { + let inner = self.inner(); + unsafe { + inner.proc.as_mut().unwrap().1.switch_to(&mut *inner.loop_context); } - trace!("process {} {:?} -> {:?}", pid, status0, status); - self.get_mut(pid).status = status; } - /// Called by timer. - /// Handle events. - pub fn tick(&mut self) { - let current_pid = self.current_pid; - if self.scheduler.tick(current_pid) { - self.yield_now(); - } - self.event_hub.tick(); - while let Some(event) = self.event_hub.pop() { - debug!("event {:?}", event); - match event { - Event::Schedule => { - self.event_hub.push(10, Event::Schedule); - self.yield_now(); - }, - Event::Wakeup(pid) => { - self.set_status(pid, Status::Ready); - self.yield_now(); - self.scheduler.move_to_head(pid); - }, - } - } + pub fn pid(&self) -> Pid { + self.inner().proc.as_ref().unwrap().0 } - pub fn get_time(&self) -> usize { - self.event_hub.get_time() + pub fn manager(&self) -> &ProcessManager { + &*self.inner().manager } - pub fn add(&mut self, context: T) -> Pid { - let pid = self.alloc_pid(); - let process = Process { - pid, - parent: self.current_pid, - status: Status::Ready, - context, - }; - self.scheduler.insert(pid); - self.procs.insert(pid, process); - pid - } - - /// Called every interrupt end - /// Do schedule ONLY IF current status != Running - pub fn schedule(&mut self) { - if self.get(self.current_pid).status == Status::Running { - return; + pub fn tick(&self) { + let need_reschedule = self.manager().tick(self.pid()); + if need_reschedule { + self.yield_now(); } - let pid = self.scheduler.select().unwrap(); - self.switch_to(pid); } +} - /// Switch to process `pid`. - /// The current status must be set before, and not be `Running`. - /// The target status must be `Ready`. - fn switch_to(&mut self, pid: Pid) { - // for debug print - let pid0 = self.current_pid; - - if pid == self.current_pid { - if self.get(self.current_pid).status != Status::Running { - self.set_status(pid, Status::Running); - } - return; - } - self.current_pid = pid; +struct Process { + id: Pid, + status: Status, + status_after_stop: Status, + context: Option>, +} - let (from, to) = self.procs.get_mut2(pid0, pid); +type Pid = usize; +type ExitCode = usize; +const MAX_PROC_NUM: usize = 32; - assert_ne!(from.status, Status::Running); - assert_eq!(to.status, Status::Ready); - to.status = Status::Running; - self.scheduler.remove(pid); +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Status { + Ready, + Running(usize), + Waiting(Pid), + Sleeping, + Exited(ExitCode), +} - info!("switch from {} to {} {:x?}", pid0, pid, to.context); - unsafe { from.context.switch(&mut to.context); } - } +pub trait Context { + unsafe fn switch_to(&mut self, target: &mut Context); +} - fn get(&self, pid: Pid) -> &Process { - self.procs.get(&pid).unwrap() - } - fn get_mut(&mut self, pid: Pid) -> &mut Process { - self.procs.get_mut(&pid).unwrap() - } - pub fn current_context(&self) -> &T { - &self.get(self.current_pid).context - } - pub fn current_pid(&self) -> Pid { - self.current_pid - } +pub struct ProcessManager { + procs: [Mutex>; MAX_PROC_NUM], + scheduler: Mutex>, +} - pub fn kill(&mut self, pid: Pid) { - self.exit(pid, 0x1000); // TODO: error code for killed - } +impl ProcessManager { - pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) { - info!("{} exit, code: {}", pid, error_code); - self.set_status(pid, Status::Exited(error_code)); - if let Some(waiter) = self.find_waiter(pid) { - info!(" then wakeup {}", waiter); - self.set_status(waiter, Status::Ready); - self.scheduler.move_to_head(waiter); + pub fn new(scheduler: Box) -> Self { + ProcessManager { + procs: Default::default(), + scheduler: Mutex::new(scheduler), } } - pub fn sleep(&mut self, pid: Pid, time: usize) { - self.set_status(pid, Status::Sleeping); - self.event_hub.push(time, Event::Wakeup(pid)); - } - pub fn sleep_(&mut self, pid: Pid) { - self.set_status(pid, Status::Sleeping); - } - pub fn wakeup_(&mut self, pid: Pid) { - self.set_status(pid, Status::Ready); + fn alloc_pid(&self) -> Pid { + for i in 0..MAX_PROC_NUM { + if self.procs[i].lock().is_none() { + return i; + } + } + panic!("Process number exceeded"); } - /// Let current process wait for another - pub fn current_wait_for(&mut self, pid: Pid) -> WaitResult { - info!("current {} wait for {:?}", self.current_pid, pid); - if self.procs.values().filter(|&p| p.parent == self.current_pid).next().is_none() { - return WaitResult::NotExist; - } - let pid = self.try_wait(pid).unwrap_or_else(|| { - let current_pid = self.current_pid; - self.set_status(current_pid, Status::Waiting(pid)); - self.schedule(); // yield - self.try_wait(pid).unwrap() + /// Add a new process + pub fn add(&self, context: Box) -> Pid { + let pid = self.alloc_pid(); + // TODO: check parent + *self.procs[pid].lock() = Some(Process { + id: pid, + status: Status::Ready, + status_after_stop: Status::Ready, + context: Some(context), }); - let exit_code = self.get(pid).exit_code().unwrap(); - info!("{} wait end and remove {}", self.current_pid, pid); - self.procs.remove(&pid); - WaitResult::Ok(pid, exit_code) + self.scheduler.lock().insert(pid); + pid } - /// Try to find a exited wait target - fn try_wait(&mut self, pid: Pid) -> Option { - match pid { - 0 => self.procs.values() - .find(|&p| p.parent == self.current_pid && p.exit_code().is_some()) - .map(|p| p.pid), - _ => self.get(pid).exit_code().map(|_| pid), + /// Make process `pid` time slice -= 1. + /// Return true if time slice == 0. + /// Called by timer interrupt handler. + pub fn tick(&self, pid: Pid) -> bool { + self.scheduler.lock().tick(pid) + } + + /// Called by Processor to get a process to run. + /// The manager first mark it `Running`, + /// then take out and return its Context. + pub fn run(&self, cpu_id: usize) -> (Pid, Box) { + let mut scheduler = self.scheduler.lock(); + let pid = scheduler.select() + .expect("failed to select a runnable process"); + scheduler.remove(pid); + let mut proc_lock = self.procs[pid].lock(); + let mut proc = proc_lock.as_mut().unwrap(); + proc.status = Status::Running(cpu_id); + (pid, proc.context.take().unwrap()) + } + + /// Called by Processor to finish running a process + /// and give its context back. + pub fn stop(&self, pid: Pid, context: Box) { + let mut proc_lock = self.procs[pid].lock(); + let mut proc = proc_lock.as_mut().unwrap(); + proc.status = proc.status_after_stop.clone(); + proc.status_after_stop = Status::Ready; + proc.context = Some(context); + if proc.status == Status::Ready { + self.scheduler.lock().insert(pid); } } - fn find_waiter(&self, pid: Pid) -> Option { - self.procs.values().find(|&p| { - p.status == Status::Waiting(pid) || - (p.status == Status::Waiting(0) && self.get(pid).parent == p.pid) - }).map(|ref p| p.pid) - } -} - -#[derive(Debug)] -pub enum WaitResult { - /// The target process is exited with `ErrorCode`. - Ok(Pid, ErrorCode), - /// The target process is not exist. - NotExist, -} - -#[derive(Debug)] -enum Event { - Schedule, - Wakeup(Pid), -} - -impl GetMut2 for BTreeMap> { - type Output = Process; - fn get_mut(&mut self, id: Pid) -> &mut Process { - self.get_mut(&id).unwrap() + /// Switch the status of a process. + /// Insert/Remove it to/from scheduler if necessary. + pub fn set_status(&self, pid: Pid, status: Status) { + let mut scheduler = self.scheduler.lock(); + let mut proc_lock = self.procs[pid].lock(); + let mut proc = proc_lock.as_mut().unwrap(); + match (&proc.status, &status) { + (Status::Ready, Status::Ready) => return, + (Status::Ready, _) => scheduler.remove(pid), + (Status::Running(_), _) => {}, + (_, Status::Ready) => scheduler.insert(pid), + _ => {} + } + trace!("process {} {:?} -> {:?}", pid, proc.status, status); + match proc.status { + Status::Running(_) => proc.status_after_stop = status, + _ => proc.status = status, + } } } \ No newline at end of file diff --git a/crate/process/src/thread.rs b/crate/process/src/thread.rs index 818a28a..b72ebfe 100644 --- a/crate/process/src/thread.rs +++ b/crate/process/src/thread.rs @@ -38,10 +38,8 @@ use scheduler::Scheduler; /// All dependencies for thread mod. pub trait ThreadSupport { - type Context: Context; - type Scheduler: Scheduler; - type ProcessorGuard: DerefMut>; - fn processor() -> Self::ProcessorGuard; + fn processor() -> &'static Processor; + fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box; } /// Root structure served as thread mod @@ -53,7 +51,7 @@ impl ThreadMod { /// Gets a handle to the thread that invokes it. pub fn current() -> Thread { Thread { - pid: S::processor().current_pid(), + pid: S::processor().pid(), mark: PhantomData, } } @@ -62,10 +60,8 @@ impl ThreadMod { pub fn sleep(dur: Duration) { let time = dur_to_ticks(dur); info!("sleep: {:?} ticks", time); - let mut processor = S::processor(); - let pid = processor.current_pid(); - processor.sleep(pid, time); - processor.schedule(); + // TODO: register wakeup + Self::park(); fn dur_to_ticks(dur: Duration) -> usize { return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; @@ -111,16 +107,17 @@ impl ThreadMod { // unsafe { LocalKey::::get_map() }.clear(); // 让Processor退出当前线程 // 把f返回值在堆上的指针,以线程返回码的形式传递出去 - let mut processor = S::processor(); - let pid = processor.current_pid(); - processor.exit(pid, Box::into_raw(ret) as usize); - processor.schedule(); + let pid = S::processor().pid(); + let exit_code = Box::into_raw(ret) as usize; + S::processor().manager().set_status(pid, Status::Exited(exit_code)); + S::processor().yield_now(); // 再也不会被调度回来了 unreachable!() } // 在Processor中创建新的线程 - let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::, f as usize)); + let context = S::new_kernel(kernel_thread_entry::, f as usize); + let pid = S::processor().manager().add(context); // 接下来看看`JoinHandle::join()`的实现 // 了解是如何获取f返回值的 @@ -133,18 +130,15 @@ impl ThreadMod { /// Cooperatively gives up a timeslice to the OS scheduler. pub fn yield_now() { info!("yield:"); - let mut processor = S::processor(); - processor.yield_now(); - processor.schedule(); + S::processor().yield_now(); } /// Blocks unless or until the current thread's token is made available. pub fn park() { info!("park:"); - let mut processor = S::processor(); - let pid = processor.current_pid(); - processor.sleep_(pid); - processor.schedule(); + let pid = S::processor().pid(); + S::processor().manager().set_status(pid, Status::Sleeping); + S::processor().yield_now(); } } @@ -157,8 +151,7 @@ pub struct Thread { impl Thread { /// Atomically makes the handle's token available if it is not already. pub fn unpark(&self) { - let mut processor = S::processor(); - processor.wakeup_(self.pid); + S::processor().manager().set_status(self.pid, Status::Ready); } /// Gets the thread's unique identifier. pub fn id(&self) -> usize { @@ -179,14 +172,8 @@ impl JoinHandle { } /// Waits for the associated thread to finish. pub fn join(self) -> Result { - let mut processor = S::processor(); - match processor.current_wait_for(self.thread.pid) { - WaitResult::Ok(_, exit_code) => unsafe { - // Find return value on the heap from the exit code. - Ok(*Box::from_raw(exit_code as *mut T)) - } - WaitResult::NotExist => Err(()), - } + // TODO: wait for the thread + unimplemented!() } } diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 83938d6..6d9f445 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -285,6 +285,7 @@ name = "ucore-process" version = "0.1.0" dependencies = [ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index db30cf9..b9a57f8 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -57,6 +57,5 @@ fn other_start() -> ! { idt::init(); gdt::init(); cpu::init(); -// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault - loop {} + ::kmain(); } \ No newline at end of file diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index 6c9c958..41954c0 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -46,8 +46,8 @@ pub fn shell() { if let Ok(file) = root.borrow().lookup(name.as_str()) { use process::*; let len = file.borrow().read_at(0, &mut *buf).unwrap(); - let pid = processor().add(Context::new_user(&buf[..len])); - processor().current_wait_for(pid); + processor().manager().add(ContextImpl::new_user(&buf[..len])); + // TODO: wait for new process } else { println!("Program not exist"); } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 4a23294..73c6dbb 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -9,6 +9,7 @@ #![feature(panic_info_message)] #![feature(global_asm)] #![feature(compiler_builtins_lib)] +#![feature(raw)] #![no_std] @@ -61,18 +62,18 @@ pub mod arch; pub mod arch; pub fn kmain() -> ! { - process::init(); - unsafe { arch::interrupt::enable(); } + if arch::cpu::id() == 0 { + process::init(); + thread::spawn(fs::shell); + } - fs::shell(); + process::processor().run(); // thread::test::local_key(); // thread::test::unpack(); // sync::test::philosopher_using_mutex(); // sync::test::philosopher_using_monitor(); // sync::mpsc::test::test_all(); - - loop {} } /// Global heap allocator diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index d4ebd96..eb311e4 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -2,39 +2,45 @@ use arch::interrupt::{TrapFrame, Context as ArchContext}; use memory::{MemoryArea, MemoryAttr, MemorySet}; use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use core::fmt::{Debug, Error, Formatter}; +use ucore_process::processor::Context; +use alloc::boxed::Box; -pub struct Context { +pub struct ContextImpl { arch: ArchContext, memory_set: MemorySet, } -impl ::ucore_process::processor::Context for Context { - unsafe fn switch(&mut self, target: &mut Self) { - super::PROCESSOR.try().unwrap().force_unlock(); - self.arch.switch(&mut target.arch); - use core::mem::forget; - forget(super::processor()); - } +impl Context for ContextImpl { + unsafe fn switch_to(&mut self, target: &mut Context) { + use core::raw::TraitObject; + use core::mem::transmute; - fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self { - let ms = MemorySet::new(); - Context { - arch: unsafe { ArchContext::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) }, - memory_set: ms, - } + // Cast &mut Context -> &mut ContextImpl + let raw: TraitObject = transmute(target); + let target = &mut *(raw.data as *mut ContextImpl); + + self.arch.switch(&mut target.arch); } } -impl Context { - pub unsafe fn new_init() -> Self { - Context { +impl ContextImpl { + pub unsafe fn new_init() -> Box { + Box::new(ContextImpl { arch: ArchContext::null(), memory_set: MemorySet::new(), - } + }) + } + + pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { + let ms = MemorySet::new(); + Box::new(ContextImpl { + arch: unsafe { ArchContext::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) }, + memory_set: ms, + }) } /// Make a new user thread from ELF data - pub fn new_user(data: &[u8]) -> Self { + pub fn new_user(data: &[u8]) -> Box { // Parse elf let elf = ElfFile::new(data).expect("failed to read elf"); let is32 = match elf.header.pt2 { @@ -81,17 +87,17 @@ impl Context { }); } - Context { + Box::new(ContextImpl { arch: unsafe { ArchContext::new_user_thread( entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token()) }, memory_set, - } + }) } /// Fork - pub fn fork(&self, tf: &TrapFrame) -> Self { + pub fn fork(&self, tf: &TrapFrame) -> Box { // Clone memory set, make a new page table let memory_set = self.memory_set.clone(); @@ -110,14 +116,14 @@ impl Context { }); } - Context { + Box::new(ContextImpl { arch: unsafe { ArchContext::new_fork(tf, memory_set.kstack_top(), memory_set.token()) }, memory_set, - } + }) } } -impl Debug for Context { +impl Debug for ContextImpl { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "{:x?}", self.arch) } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 569f3d2..5bc17a3 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,36 +1,41 @@ use spin::Once; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; -pub use self::context::Context; -pub use ucore_process::processor::{*, Context as _whatever}; +pub use self::context::ContextImpl; +pub use ucore_process::processor::*; pub use ucore_process::scheduler::*; pub use ucore_process::thread::*; +use alloc::boxed::Box; +use consts::MAX_CPU_NUM; +use arch::cpu; +use alloc::sync::Arc; +use alloc::vec::Vec; mod context; -type Processor = Processor_; - pub fn init() { - PROCESSOR.call_once(|| - SpinNoIrqLock::new({ - let mut processor = Processor::new( - unsafe { Context::new_init() }, - // NOTE: max_time_slice <= 5 to ensure 'priority' test pass - StrideScheduler::new(5), - ); - extern fn idle(arg: usize) -> ! { - loop {} - } - processor.add(Context::new_kernel(idle, 0)); - processor - }) - ); + // NOTE: max_time_slice <= 5 to ensure 'priority' test pass + let scheduler = Box::new(RRScheduler::new(5)); + let manager = Arc::new(ProcessManager::new(scheduler)); + + extern fn idle(_arg: usize) -> ! { + loop { cpu::halt(); } + } + for i in 0..MAX_CPU_NUM { + manager.add(ContextImpl::new_kernel(idle, i)); + } + + unsafe { + for cpu_id in 0..MAX_CPU_NUM { + PROCESSORS[cpu_id].init(cpu_id, ContextImpl::new_init(), manager.clone()); + } + } info!("process init end"); } -pub static PROCESSOR: Once> = Once::new(); +static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()]; -pub fn processor() -> MutexGuard<'static, Processor, SpinNoIrq> { - PROCESSOR.try().unwrap().lock() +pub fn processor() -> &'static Processor { + &PROCESSORS[cpu::id()] } #[allow(non_camel_case_types)] @@ -43,11 +48,10 @@ pub mod thread_ { pub struct ThreadSupportImpl; impl ThreadSupport for ThreadSupportImpl { - type Context = Context; - type Scheduler = StrideScheduler; - type ProcessorGuard = MutexGuard<'static, Processor, SpinNoIrq>; - - fn processor() -> Self::ProcessorGuard { + fn processor() -> &'static Processor { processor() } + fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { + ContextImpl::new_kernel(entry, arg) + } } \ No newline at end of file diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 80a170c..5c48ecf 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -58,26 +58,13 @@ fn sys_close(fd: usize) -> i32 { /// Fork the current process. Return the child's PID. fn sys_fork(tf: &TrapFrame) -> i32 { - let mut processor = processor(); - let context = processor.current_context().fork(tf); - let pid = processor.add(context); - info!("fork: {} -> {}", processor.current_pid(), pid); - pid as i32 + unimplemented!(); } /// Wait the process exit. /// Return the PID. Store exit code to `code` if it's not null. fn sys_wait(pid: usize, code: *mut i32) -> i32 { - let mut processor = processor(); - match processor.current_wait_for(pid) { - WaitResult::Ok(pid, error_code) => { - if !code.is_null() { - unsafe { *code = error_code as i32 }; - } - 0 - } - WaitResult::NotExist => -1, - } + unimplemented!(); } fn sys_yield() -> i32 { @@ -87,7 +74,7 @@ fn sys_yield() -> i32 { /// Kill the process fn sys_kill(pid: usize) -> i32 { - processor().kill(pid); + processor().manager().set_status(pid, Status::Exited(0x100)); 0 } @@ -97,10 +84,10 @@ fn sys_getpid() -> i32 { } /// Exit the current process -fn sys_exit(error_code: usize) -> i32 { - let mut processor = processor(); - let pid = processor.current_pid(); - processor.exit(pid, error_code); +fn sys_exit(exit_code: usize) -> i32 { + let pid = processor().pid(); + processor().manager().set_status(pid, Status::Exited(exit_code)); + processor().yield_now(); 0 } @@ -111,13 +98,11 @@ fn sys_sleep(time: usize) -> i32 { } fn sys_get_time() -> i32 { - let processor = processor(); - processor.get_time() as i32 + unimplemented!(); } fn sys_lab6_set_priority(priority: usize) -> i32 { - let mut processor = processor(); - processor.set_priority(priority as u8); + unimplemented!(); 0 } diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 42c7abc..6cd4556 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -1,26 +1,19 @@ use process::*; use arch::interrupt::TrapFrame; +use arch::cpu; pub fn timer() { - let mut processor = processor(); - processor.tick(); + processor().tick(); } pub fn before_return() { - if let Some(processor) = PROCESSOR.try() { - processor.lock().schedule(); - } } pub fn error(tf: &TrapFrame) -> ! { - if let Some(processor) = PROCESSOR.try() { - let mut processor = processor.lock(); - let pid = processor.current_pid(); - error!("Process {} error:\n{:#x?}", pid, tf); - processor.exit(pid, 0x100); // TODO: Exit code for error - processor.schedule(); - unreachable!(); - } else { - panic!("Exception when processor not inited\n{:#x?}", tf); - } + let pid = processor().pid(); + error!("On CPU{} Process {}:\n{:#x?}", cpu::id(), pid, tf); + + processor().manager().set_status(pid, Status::Exited(0x100)); + processor().yield_now(); + unreachable!(); } \ No newline at end of file