diff --git a/crate/thread/src/interrupt.rs b/crate/thread/src/interrupt.rs index e23eb12..6f034b3 100644 --- a/crate/thread/src/interrupt.rs +++ b/crate/thread/src/interrupt.rs @@ -16,6 +16,12 @@ pub unsafe fn restore(flags: usize) { } } +#[inline(always)] +#[cfg(target_arch = "x86_64")] +pub unsafe fn enable_and_wfi() { + asm!("sti; hlt" :::: "volatile"); +} + #[inline(always)] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] pub unsafe fn disable_and_store() -> usize { @@ -40,6 +46,16 @@ pub unsafe fn restore(flags: usize) { } } +#[inline(always)] +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +pub unsafe fn enable_and_wfi() { + if env!("M_MODE") == "1" { + asm!("csrsi mstatus, 1 << 3; wfi" :::: "volatile"); + } else { + asm!("csrsi sstatus, 1 << 1; wfi" :::: "volatile"); + } +} + #[inline(always)] #[cfg(target_arch = "aarch64")] pub unsafe fn disable_and_store() -> usize { @@ -53,3 +69,9 @@ pub unsafe fn disable_and_store() -> usize { pub unsafe fn restore(flags: usize) { asm!("msr DAIF, $0" :: "r"(flags as u32) :: "volatile"); } + +#[inline(always)] +#[cfg(target_arch = "aarch64")] +pub unsafe fn enable_and_wfi() { + asm!("msr daifclr, #2; wfi" :::: "volatile"); +} diff --git a/crate/thread/src/processor.rs b/crate/thread/src/processor.rs index 27a3ca2..f46d62e 100644 --- a/crate/thread/src/processor.rs +++ b/crate/thread/src/processor.rs @@ -53,20 +53,28 @@ impl Processor { let inner = self.inner(); unsafe { interrupt::disable_and_store(); } 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); + if let Some(proc) = inner.manager.run(inner.id) { + trace!("CPU{} begin running thread {}", 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 thread {}", inner.id, pid); + inner.manager.stop(pid, context); + } else { + trace!("CPU{} idle", inner.id); + unsafe { interrupt::enable_and_wfi(); } + // wait for a timer interrupt + unsafe { interrupt::disable_and_store(); } } - let (pid, context) = inner.proc.take().unwrap(); - trace!("CPU{} stop running process {}", inner.id, pid); - inner.manager.stop(pid, context); } } /// Called by process running on this Processor. /// Yield and reschedule. + /// + /// The interrupt may be enabled. pub fn yield_now(&self) { let inner = self.inner(); unsafe { @@ -88,11 +96,14 @@ impl Processor { &*self.inner().manager } + /// Called by timer interrupt handler. + /// + /// The interrupt should be disabled in the handler. pub fn tick(&self) { - let flags = unsafe { interrupt::disable_and_store() }; - let need_reschedule = self.manager().tick(self.tid()); - unsafe { interrupt::restore(flags); } - + // If I'm idle, tid == None, need_reschedule == false. + // Will go back to `run()` after interrupt return. + let tid = self.inner().proc.as_ref().map(|p| p.0); + let need_reschedule = self.manager().tick(self.inner().id, tid); if need_reschedule { self.yield_now(); } diff --git a/crate/thread/src/thread_pool.rs b/crate/thread/src/thread_pool.rs index 8d16de6..93d159f 100644 --- a/crate/thread/src/thread_pool.rs +++ b/crate/thread/src/thread_pool.rs @@ -78,15 +78,20 @@ impl ThreadPool { /// Make process `tid` time slice -= 1. /// Return true if time slice == 0. /// Called by timer interrupt handler. - pub fn tick(&self, tid: Tid) -> bool { - let mut timer = self.timer.lock(); - timer.tick(); - while let Some(event) = timer.pop() { - match event { - Event::Wakeup(tid) => self.set_status(tid, Status::Ready), + pub(crate) fn tick(&self, cpu_id: usize, tid: Option) -> bool { + if cpu_id == 0 { + let mut timer = self.timer.lock(); + timer.tick(); + while let Some(event) = timer.pop() { + match event { + Event::Wakeup(tid) => self.set_status(tid, Status::Ready), + } } } - self.scheduler.lock().tick(tid) + match tid { + Some(tid) => self.scheduler.lock().tick(tid), + None => false, + } } /// Set the priority of process `tid` @@ -97,20 +102,21 @@ impl ThreadPool { /// 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) -> (Tid, Box) { + pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box)> { let mut scheduler = self.scheduler.lock(); - let tid = scheduler.select() - .expect("failed to select a runnable process"); - scheduler.remove(tid); - let mut proc_lock = self.threads[tid].lock(); - let mut proc = proc_lock.as_mut().expect("process not exist"); - proc.status = Status::Running(cpu_id); - (tid, proc.context.take().expect("context not exist")) + scheduler.select() + .map(|tid| { + scheduler.remove(tid); + let mut proc_lock = self.threads[tid].lock(); + let mut proc = proc_lock.as_mut().expect("process not exist"); + proc.status = Status::Running(cpu_id); + (tid, proc.context.take().expect("context not exist")) + }) } /// Called by Processor to finish running a process /// and give its context back. - pub fn stop(&self, tid: Tid, context: Box) { + pub(crate) fn stop(&self, tid: Tid, context: Box) { let mut proc_lock = self.threads[tid].lock(); let mut proc = proc_lock.as_mut().expect("process not exist"); proc.status = proc.status_after_stop.clone(); diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index c7488c9..7626841 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -20,15 +20,6 @@ pub fn init() { } } - // Add idle threads - extern fn idle(_arg: usize) -> ! { - loop { cpu::halt(); } - } - use core::str::FromStr; - let cores = usize::from_str(env!("SMP")).unwrap(); - for i in 0..cores { - manager.add(Thread::new_kernel(idle, i), 0); - } crate::shell::run_user_shell(); info!("process init end");