diff --git a/kernel/rustkernel/src/console/mod.rs b/kernel/rustkernel/src/console/mod.rs index 5a528ae..6efb13b 100644 --- a/kernel/rustkernel/src/console/mod.rs +++ b/kernel/rustkernel/src/console/mod.rs @@ -13,7 +13,10 @@ pub mod uart; use crate::{ fs::file::{devsw, CONSOLE}, - proc::process::{procdump, wakeup, Process}, + proc::{ + process::{procdump, Process}, + scheduler::wakeup, + }, sync::mutex::Mutex, }; use core::{ffi::c_void, ptr::addr_of_mut}; diff --git a/kernel/rustkernel/src/console/uart.rs b/kernel/rustkernel/src/console/uart.rs index 05f681e..6f79ee7 100644 --- a/kernel/rustkernel/src/console/uart.rs +++ b/kernel/rustkernel/src/console/uart.rs @@ -2,7 +2,7 @@ #![allow(non_upper_case_globals)] use crate::{ - console::consoleintr, proc::process::wakeup, queue::Queue, sync::mutex::Mutex, + console::consoleintr, proc::scheduler::wakeup, queue::Queue, sync::mutex::Mutex, trap::InterruptBlocker, }; use core::ptr::addr_of; diff --git a/kernel/rustkernel/src/io/pipe.rs b/kernel/rustkernel/src/io/pipe.rs index acffa76..7cf16a3 100644 --- a/kernel/rustkernel/src/io/pipe.rs +++ b/kernel/rustkernel/src/io/pipe.rs @@ -4,7 +4,7 @@ use crate::{ kalloc::{kalloc, kfree}, virtual_memory::{copyin, copyout}, }, - proc::process::{wakeup, Process}, + proc::{process::Process, scheduler::wakeup}, sync::spinlock::Spinlock, }; use core::ptr::{addr_of, addr_of_mut}; diff --git a/kernel/rustkernel/src/lib.rs b/kernel/rustkernel/src/lib.rs index a5a2f5d..15920ce 100644 --- a/kernel/rustkernel/src/lib.rs +++ b/kernel/rustkernel/src/lib.rs @@ -82,7 +82,7 @@ pub unsafe fn main() -> ! { arch::riscv::plic::plicinithart(); } - proc::process::scheduler(); + proc::scheduler::scheduler(); } #[panic_handler] diff --git a/kernel/rustkernel/src/proc/mod.rs b/kernel/rustkernel/src/proc/mod.rs index b27cf63..a6a58bb 100644 --- a/kernel/rustkernel/src/proc/mod.rs +++ b/kernel/rustkernel/src/proc/mod.rs @@ -1,4 +1,5 @@ pub mod context; pub mod cpu; pub mod process; +pub mod scheduler; pub mod trapframe; diff --git a/kernel/rustkernel/src/proc/process.rs b/kernel/rustkernel/src/proc/process.rs index f5e1a09..28cbc6b 100644 --- a/kernel/rustkernel/src/proc/process.rs +++ b/kernel/rustkernel/src/proc/process.rs @@ -1,11 +1,11 @@ #![allow(clippy::comparison_chain)] -use super::{context::Context, cpu::Cpu, trapframe::Trapframe}; +use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe}; use crate::{ - arch::riscv::{intr_get, Pagetable, PTE_W}, + arch::riscv::{Pagetable, PTE_W}, fs::file::{File, Inode}, mem::kalloc::kfree, - sync::spinlock::{Spinlock, SpinlockGuard}, + sync::spinlock::Spinlock, }; use core::{ ffi::{c_char, c_void}, @@ -36,14 +36,9 @@ extern "C" { pub fn proc_mapstacks(kpgtbl: Pagetable); pub fn proc_pagetable(p: *mut Process) -> Pagetable; pub fn proc_freepagetable(pagetable: Pagetable, sz: u64); - pub fn wakeup(chan: *const c_void); pub fn allocproc() -> *mut Process; - // pub fn freeproc(p: *mut Process); pub fn uvmalloc(pagetable: Pagetable, oldsz: u64, newsz: u64, xperm: i32) -> u64; pub fn uvmdealloc(pagetable: Pagetable, oldsz: u64, newsz: u64) -> u64; - // pub fn sched(); - pub fn scheduler() -> !; - pub fn swtch(a: *mut Context, b: *mut Context); } pub static NEXT_PID: AtomicI32 = AtomicI32::new(1); @@ -238,64 +233,6 @@ pub unsafe fn growproc(n: i32) -> i32 { 0 } -/// Give up the CPU for one scheduling round. -pub unsafe fn r#yield() { - let p = Process::current().unwrap(); - let _guard = p.lock.lock(); - p.state = ProcessState::Runnable; - sched(); -} - -/// Switch to scheduler. Must hold only p->lock -/// and have changed proc->state. Saves and restores -/// previous_interrupts_enabled because previous_interrupts_enabled is a property of this -/// kernel thread, not this CPU. It should -/// be proc->previous_interrupts_enabled and proc->interrupt_disable_layers, but that would -/// break in the few places where a lock is held but -/// there's no process. -#[no_mangle] -pub unsafe extern "C" fn sched() { - let p = Process::current().unwrap(); - let cpu = Cpu::current(); - - if cpu.interrupt_disable_layers != 1 { - panic!("sched locks"); - } else if p.state == ProcessState::Running { - panic!("sched running"); - } else if intr_get() > 0 { - panic!("sched interruptible"); - } - - let previous_interrupts_enabled = cpu.previous_interrupts_enabled; - swtch(addr_of_mut!(p.context), addr_of_mut!(cpu.context)); - cpu.previous_interrupts_enabled = previous_interrupts_enabled; -} - -/// The lock should already be locked. -/// Unsafely create a new guard for it so that we can call SpinlockGuard.sleep(). -#[no_mangle] -pub unsafe extern "C" fn sleep_lock(chan: *mut c_void, lock: *mut Spinlock) { - let lock: &Spinlock = &*lock; - let guard = SpinlockGuard { lock }; - guard.sleep(chan); - core::mem::forget(guard); -} - -/// Sleep until `wakeup(chan)` is called somewhere else. -pub unsafe fn sleep(chan: *mut c_void) { - let p = Process::current().unwrap(); - let _guard = p.lock.lock(); - - // Go to sleep. - p.chan = chan; - p.state = ProcessState::Sleeping; - - sched(); - - // Tidy up. - p.chan = null_mut(); -} - /// Kill the process with the given pid. /// The victim won't exit until it tries to return /// to user space (see usertrap() in trap.c). diff --git a/kernel/rustkernel/src/proc/scheduler.rs b/kernel/rustkernel/src/proc/scheduler.rs new file mode 100644 index 0000000..ef9b883 --- /dev/null +++ b/kernel/rustkernel/src/proc/scheduler.rs @@ -0,0 +1,77 @@ +use super::{ + context::Context, + cpu::Cpu, + process::{Process, ProcessState}, +}; +use crate::{ + arch::riscv::intr_get, + sync::spinlock::{Spinlock, SpinlockGuard}, +}; +use core::{ + ffi::c_void, + ptr::{addr_of_mut, null_mut}, +}; + +extern "C" { + pub fn wakeup(chan: *const c_void); + pub fn scheduler() -> !; + pub fn swtch(a: *mut Context, b: *mut Context); +} + +/// Give up the CPU for one scheduling round. +pub unsafe fn r#yield() { + let p = Process::current().unwrap(); + let _guard = p.lock.lock(); + p.state = ProcessState::Runnable; + sched(); +} + +/// Switch to scheduler. Must hold only p->lock +/// and have changed proc->state. Saves and restores +/// previous_interrupts_enabled because previous_interrupts_enabled is a property of this +/// kernel thread, not this CPU. It should +/// be proc->previous_interrupts_enabled and proc->interrupt_disable_layers, but that would +/// break in the few places where a lock is held but +/// there's no process. +#[no_mangle] +pub unsafe extern "C" fn sched() { + let p = Process::current().unwrap(); + let cpu = Cpu::current(); + + if cpu.interrupt_disable_layers != 1 { + panic!("sched locks"); + } else if p.state == ProcessState::Running { + panic!("sched running"); + } else if intr_get() > 0 { + panic!("sched interruptible"); + } + + let previous_interrupts_enabled = cpu.previous_interrupts_enabled; + swtch(addr_of_mut!(p.context), addr_of_mut!(cpu.context)); + cpu.previous_interrupts_enabled = previous_interrupts_enabled; +} + +/// The lock should already be locked. +/// Unsafely create a new guard for it so that we can call SpinlockGuard.sleep(). +#[no_mangle] +pub unsafe extern "C" fn sleep_lock(chan: *mut c_void, lock: *mut Spinlock) { + let lock: &Spinlock = &*lock; + let guard = SpinlockGuard { lock }; + guard.sleep(chan); + core::mem::forget(guard); +} + +/// Sleep until `wakeup(chan)` is called somewhere else. +pub unsafe fn sleep(chan: *mut c_void) { + let p = Process::current().unwrap(); + let _guard = p.lock.lock(); + + // Go to sleep. + p.chan = chan; + p.state = ProcessState::Sleeping; + + sched(); + + // Tidy up. + p.chan = null_mut(); +} diff --git a/kernel/rustkernel/src/sync/lock.rs b/kernel/rustkernel/src/sync/lock.rs index 252d91a..c48876b 100644 --- a/kernel/rustkernel/src/sync/lock.rs +++ b/kernel/rustkernel/src/sync/lock.rs @@ -1,5 +1,8 @@ use super::LockStrategy; -use crate::proc::process::{sched, sleep, wakeup, Process, ProcessState}; +use crate::proc::{ + process::{Process, ProcessState}, + scheduler::{sched, sleep, wakeup}, +}; use core::{ cell::UnsafeCell, ops::Drop, diff --git a/kernel/rustkernel/src/sync/sleeplock.rs b/kernel/rustkernel/src/sync/sleeplock.rs index 46f769e..101fc9f 100644 --- a/kernel/rustkernel/src/sync/sleeplock.rs +++ b/kernel/rustkernel/src/sync/sleeplock.rs @@ -1,4 +1,4 @@ -use crate::proc::process::{sleep, wakeup}; +use crate::proc::scheduler::{sleep, wakeup}; use core::{ ffi::c_char, ptr::addr_of, diff --git a/kernel/rustkernel/src/sync/spinlock.rs b/kernel/rustkernel/src/sync/spinlock.rs index 3d2ecce..d6ea3bc 100644 --- a/kernel/rustkernel/src/sync/spinlock.rs +++ b/kernel/rustkernel/src/sync/spinlock.rs @@ -1,5 +1,8 @@ use crate::{ - proc::process::{sched, Process, ProcessState}, + proc::{ + process::{Process, ProcessState}, + scheduler::sched, + }, trap::{pop_intr_off, push_intr_off}, }; use core::{ diff --git a/kernel/rustkernel/src/trap.rs b/kernel/rustkernel/src/trap.rs index b3f6848..8e733f9 100644 --- a/kernel/rustkernel/src/trap.rs +++ b/kernel/rustkernel/src/trap.rs @@ -3,7 +3,8 @@ use crate::{ println, proc::{ cpu::Cpu, - process::{exit, r#yield, wakeup, Process, ProcessState}, + process::{exit, Process, ProcessState}, + scheduler::{r#yield, wakeup}, }, sync::mutex::Mutex, syscall::syscall,