From 183716869d0abbbac84d89fccd672164580c38ef Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 20 Oct 2021 16:37:07 +0300 Subject: [PATCH] refactor: move sched to separate module --- kernel/src/proc/mod.rs | 159 ++------------------------------------- kernel/src/proc/sched.rs | 140 ++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 154 deletions(-) create mode 100644 kernel/src/proc/sched.rs diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index acbcba3..ab3eb50 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -2,145 +2,18 @@ use crate::mem; use crate::sync::IrqSafeNullLock; -use crate::util::InitOnce; use alloc::{ boxed::Box, - collections::{BTreeMap, VecDeque}, - rc::Rc, + collections::{BTreeMap}, }; pub mod elf; pub mod process; pub use process::{Pid, Process, ProcessRef, State as ProcessState}; -struct SchedulerInner { - queue: VecDeque, - idle: Option, - current: Option, -} - -/// Process scheduler state and queues -pub struct Scheduler { - inner: InitOnce>, -} - -impl SchedulerInner { - fn new() -> Self { - let mut this = Self { - queue: VecDeque::new(), - idle: None, - current: None, - }; - - this.idle = Some(Process::new_kernel(idle_fn, 0).unwrap().id()); - - this - } -} - -impl Scheduler { - /// Initializes inner data structure: - /// - /// * idle thread - /// * process list/queue data structs - pub fn init(&self) { - self.inner.init(IrqSafeNullLock::new(SchedulerInner::new())); - } - - /// Schedules a thread for execution - pub fn enqueue(&self, pid: Pid) { - self.inner.get().lock().queue.push_back(pid); - } - - /// - pub fn dequeue(&self, pid: Pid) { - self.inner.get().lock().queue.retain(|&p| p != pid) - } - - /// Performs initial process entry. - /// - /// # Safety - /// - /// Unsafe: may only be called once, repeated calls will cause UB. - pub unsafe fn enter(&self) -> ! { - let thread = { - let mut inner = self.inner.get().lock(); - let id = if inner.queue.is_empty() { - inner.idle.unwrap() - } else { - inner.queue.pop_front().unwrap() - }; - - inner.current = Some(id); - PROCESSES.lock().get(&id).unwrap().clone() - }; - - asm!("msr daifclr, #2"); - Process::enter(thread) - } - - /// This hack is required to be called from execve() when downgrading current - /// process from kernel to user. - /// - /// # Safety - /// - /// Unsafe: only allowed to be called from Process::execve() - pub unsafe fn hack_current_pid(&self, new: Pid) { - self.inner.get().lock().current = Some(new); - } - - /// Switches to the next task scheduled for execution. If there're - /// none present in the queue, switches to the idle task. - pub fn switch(&self, discard: bool) { - let (from, to) = { - let mut inner = self.inner.get().lock(); - let current = inner.current.unwrap(); - - if !discard && current != Pid::IDLE { - // Put the process into the back of the queue - inner.queue.push_back(current); - } - - let next = if inner.queue.is_empty() { - inner.idle.unwrap() - } else { - inner.queue.pop_front().unwrap() - }; - - inner.current = Some(next); - let (from, to) = { - let lock = PROCESSES.lock(); - ( - lock.get(¤t).unwrap().clone(), - lock.get(&next).unwrap().clone(), - ) - }; - - (from, to) - }; - - if !Rc::ptr_eq(&from, &to) { - unsafe { - asm!("msr daifclr, #2"); - Process::switch(from, to, discard); - } - } - } - - /// Returns a Rc-reference to currently running process - pub fn current_process(&self) -> ProcessRef { - let inner = self.inner.get().lock(); - let current = inner.current.unwrap(); - PROCESSES.lock().get(¤t).unwrap().clone() - } -} - -#[inline(never)] -extern "C" fn idle_fn(_a: usize) -> ! { - loop { - cortex_a::asm::wfi(); - } -} +pub mod sched; +pub use sched::Scheduler; +pub(self) use sched::SCHED; macro_rules! spawn { (fn ($dst_arg:ident : usize) $body:block, $src_arg:expr) => {{ @@ -168,14 +41,8 @@ pub fn switch() { SCHED.switch(false); } -// TODO maybe move this into a per-CPU struct -/// Global scheduler struct -pub static SCHED: Scheduler = Scheduler { - inner: InitOnce::new(), -}; - /// Global list of all processes in the system -pub static PROCESSES: IrqSafeNullLock> = +pub(self) static PROCESSES: IrqSafeNullLock> = IrqSafeNullLock::new(BTreeMap::new()); /// Sets up initial process and enters it. @@ -197,22 +64,6 @@ pub unsafe fn enter(initrd: Option<(usize, usize)>) -> ! { Process::execve(|space| elf::load_elf(space, start as *const u8), 0).unwrap(); panic!("This code should not run"); }, initrd as usize); - - spawn!(fn () { - debugln!("Terminator process started"); - - for _ in 0..2000000 { - cortex_a::asm::nop(); - } - - let pid = Pid::user(1); - debugln!("Killing {}", pid); - PROCESSES.lock().get(&pid).unwrap().exit(123); - let status = Process::waitpid(pid).unwrap(); - debugln!("{} exit status was {:?}", pid, status); - - 1 - }); } SCHED.enter(); } diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs new file mode 100644 index 0000000..f124fb4 --- /dev/null +++ b/kernel/src/proc/sched.rs @@ -0,0 +1,140 @@ +//! +use crate::proc::{Pid, Process, ProcessRef, PROCESSES}; +use crate::util::InitOnce; +use crate::sync::IrqSafeNullLock; +use alloc::{rc::Rc, collections::VecDeque}; + +struct SchedulerInner { + queue: VecDeque, + idle: Option, + current: Option, +} + +/// Process scheduler state and queues +pub struct Scheduler { + inner: InitOnce>, +} + +impl SchedulerInner { + fn new() -> Self { + let mut this = Self { + queue: VecDeque::new(), + idle: None, + current: None, + }; + + this.idle = Some(Process::new_kernel(idle_fn, 0).unwrap().id()); + + this + } +} + +impl Scheduler { + /// Initializes inner data structure: + /// + /// * idle thread + /// * process list/queue data structs + pub fn init(&self) { + self.inner.init(IrqSafeNullLock::new(SchedulerInner::new())); + } + + /// Schedules a thread for execution + pub fn enqueue(&self, pid: Pid) { + self.inner.get().lock().queue.push_back(pid); + } + + /// + pub fn dequeue(&self, pid: Pid) { + self.inner.get().lock().queue.retain(|&p| p != pid) + } + + /// Performs initial process entry. + /// + /// # Safety + /// + /// Unsafe: may only be called once, repeated calls will cause UB. + pub unsafe fn enter(&self) -> ! { + let thread = { + let mut inner = self.inner.get().lock(); + let id = if inner.queue.is_empty() { + inner.idle.unwrap() + } else { + inner.queue.pop_front().unwrap() + }; + + inner.current = Some(id); + PROCESSES.lock().get(&id).unwrap().clone() + }; + + asm!("msr daifclr, #2"); + Process::enter(thread) + } + + /// This hack is required to be called from execve() when downgrading current + /// process from kernel to user. + /// + /// # Safety + /// + /// Unsafe: only allowed to be called from Process::execve() + pub unsafe fn hack_current_pid(&self, new: Pid) { + self.inner.get().lock().current = Some(new); + } + + /// Switches to the next task scheduled for execution. If there're + /// none present in the queue, switches to the idle task. + pub fn switch(&self, discard: bool) { + let (from, to) = { + let mut inner = self.inner.get().lock(); + let current = inner.current.unwrap(); + + if !discard && current != Pid::IDLE { + // Put the process into the back of the queue + inner.queue.push_back(current); + } + + let next = if inner.queue.is_empty() { + inner.idle.unwrap() + } else { + inner.queue.pop_front().unwrap() + }; + + inner.current = Some(next); + let (from, to) = { + let lock = PROCESSES.lock(); + ( + lock.get(¤t).unwrap().clone(), + lock.get(&next).unwrap().clone(), + ) + }; + + (from, to) + }; + + if !Rc::ptr_eq(&from, &to) { + unsafe { + asm!("msr daifclr, #2"); + Process::switch(from, to, discard); + } + } + } + + /// Returns a Rc-reference to currently running process + pub fn current_process(&self) -> ProcessRef { + let inner = self.inner.get().lock(); + let current = inner.current.unwrap(); + PROCESSES.lock().get(¤t).unwrap().clone() + } +} + +#[inline(never)] +extern "C" fn idle_fn(_a: usize) -> ! { + loop { + cortex_a::asm::wfi(); + } +} + +// TODO maybe move this into a per-CPU struct +/// Global scheduler struct +pub static SCHED: Scheduler = Scheduler { + inner: InitOnce::new(), +};