diff --git a/kernel/rustkernel/src/console/mod.rs b/kernel/rustkernel/src/console/mod.rs index fc387fd..0747162 100644 --- a/kernel/rustkernel/src/console/mod.rs +++ b/kernel/rustkernel/src/console/mod.rs @@ -13,7 +13,7 @@ pub mod uart; use crate::{ fs::file::{devsw, CONSOLE}, - proc::{killed, myproc, procdump, sleep_mutex, wakeup}, + proc::{killed, myproc, procdump, wakeup}, sync::spinmutex::SpinMutex, }; use core::{ffi::c_void, ptr::addr_of_mut}; @@ -120,9 +120,8 @@ pub fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) -> i32 { // cons.lock.unlock(); return -1; } - // let channel = addr_of_mut!(console.read_index).cast(); - // console.sleep(channel); - sleep_mutex(addr_of_mut!(console.read_index).cast(), &mut console); + let channel = addr_of_mut!(console.read_index).cast(); + console.sleep(channel); } c = *console.read_byte(); diff --git a/kernel/rustkernel/src/proc.rs b/kernel/rustkernel/src/proc.rs index cca0d33..074f3b4 100644 --- a/kernel/rustkernel/src/proc.rs +++ b/kernel/rustkernel/src/proc.rs @@ -3,8 +3,7 @@ use crate::{ mem::kalloc::kfree, riscv::{self, Pagetable, PTE_W}, - sync::spinlock::Spinlock, - sync::spinmutex::SpinMutexGuard, + sync::spinlock::{Spinlock, SpinlockGuard}, }; use core::{ ffi::{c_char, c_void}, @@ -341,53 +340,13 @@ pub unsafe extern "C" fn sched() { (*c).previous_interrupts_enabled = previous_interrupts_enabled; } -/// Atomically release lock and sleep on chan. -/// Reacquires lock when awakened. +/// 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 p = myproc(); - - // Must acquire p->lock in order to - // change p->state and then call sched. - // Once we hold p->lock, we can be - // guaranteed that we won't miss any wakeup - // (wakeup locks p->lock), - // so it's okay to release lk. - - let _guard = (*p).lock.lock(); - (*lock).unlock(); - - // Go to sleep. - (*p).chan = chan; - (*p).state = ProcState::Sleeping; - - sched(); - - // Tidy up. - (*p).chan = null_mut(); - - // Reacquire original lock. - (*lock).lock_unguarded(); -} - -pub unsafe fn sleep_mutex(chan: *mut c_void, mutex: &mut SpinMutexGuard) { - let p = myproc(); - let mutex = mutex.mutex; - - let _guard = (*p).lock.lock(); - mutex.unlock(); - - // Go to sleep. - (*p).chan = chan; - (*p).state = ProcState::Sleeping; - - sched(); - - // Tidy up. - (*p).chan = null_mut(); - - // Reacquire original lock. - let guard = mutex.lock(); + let lock: &Spinlock = &*lock; + let guard = SpinlockGuard { lock }; + guard.sleep(chan); core::mem::forget(guard); } diff --git a/kernel/rustkernel/src/sync/mod.rs b/kernel/rustkernel/src/sync/mod.rs index cc007cb..3d543ce 100644 --- a/kernel/rustkernel/src/sync/mod.rs +++ b/kernel/rustkernel/src/sync/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod mutex; pub mod sleeplock; pub mod spinlock; pub mod spinmutex; diff --git a/kernel/rustkernel/src/sync/mutex.rs b/kernel/rustkernel/src/sync/mutex.rs deleted file mode 100644 index 89c664a..0000000 --- a/kernel/rustkernel/src/sync/mutex.rs +++ /dev/null @@ -1,85 +0,0 @@ -// use core::{ -// cell::UnsafeCell, -// ops::{Deref, DerefMut, Drop}, -// sync::atomic::{AtomicBool, Ordering}, -// ffi::c_void, -// ptr::addr_of, -// }; -// use crate::proc::{sleep, wakeup, sched, myproc, ProcState}; -// -// pub struct Mutex { -// locked: AtomicBool, -// inner: UnsafeCell, -// } -// impl Mutex { -// pub const fn new(value: T) -> Mutex { -// Mutex { -// locked: AtomicBool::new(false), -// inner: UnsafeCell::new(value), -// } -// } -// pub unsafe fn get_inner(&self) -> *mut T { -// self.inner.get() -// } -// /// Spin until the mutex is unlocked, acquiring afterwards. -// pub fn spin_lock(&self) -> MutexGuard<'_, T> { -// while self.locked.swap(true, Ordering::Acquire) { -// core::hint::spin_loop(); -// } -// -// MutexGuard { mutex: self } -// } -// /// Sleep until the mutex is unlocked, acquiring afterwards. -// pub fn sleep_lock(&self) -> MutexGuard<'_, T> { -// while self.locked.swap(true, Ordering::Acquire) { -// unsafe { -// sleep(addr_of!(*self).cast_mut().cast()); -// } -// } -// -// MutexGuard { mutex: self } -// } -// pub unsafe fn unlock(&self) { -// self.locked.store(false, Ordering::Release); -// wakeup(addr_of!(*self).cast_mut().cast()); -// } -// } -// unsafe impl Sync for Mutex where T: Send {} -// -// pub struct MutexGuard<'m, T> { -// pub mutex: &'m Mutex, -// } -// impl<'m, T> MutexGuard<'m, T> { -// pub unsafe fn sleep(&mut self, channel: *mut c_void){ -// let p = myproc(); -// let _guard = (*p).lock.lock(); -// self.mutex.unlock(); -// -// // Go to sleep. -// (*p).chan = channel; -// (*p).state = ProcState::Sleeping; -// sched(); -// -// // Clean up. -// let guard = self.mutex.spin_lock(); -// core::mem::forget(guard); -// } -// } -// impl<'m, T> Deref for MutexGuard<'m, T> { -// type Target = T; -// -// fn deref(&self) -> &Self::Target { -// unsafe { &*self.mutex.get_inner() } -// } -// } -// impl<'m, T> DerefMut for MutexGuard<'m, T> { -// fn deref_mut(&mut self) -> &mut Self::Target { -// unsafe { &mut *self.mutex.get_inner() } -// } -// } -// impl<'m, T> Drop for MutexGuard<'m, T> { -// fn drop(&mut self) { -// unsafe { self.mutex.unlock() } -// } -// } -// diff --git a/kernel/rustkernel/src/sync/sleeplock.rs b/kernel/rustkernel/src/sync/sleeplock.rs index 9d0401e..9ede6b2 100644 --- a/kernel/rustkernel/src/sync/sleeplock.rs +++ b/kernel/rustkernel/src/sync/sleeplock.rs @@ -1,4 +1,4 @@ -use crate::proc::{wakeup, sleep}; +use crate::proc::{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 5bed774..a034940 100644 --- a/kernel/rustkernel/src/sync/spinlock.rs +++ b/kernel/rustkernel/src/sync/spinlock.rs @@ -1,6 +1,10 @@ -use crate::trap::{pop_intr_off, push_intr_off}; +use crate::{ + proc::{myproc, sched, ProcState}, + trap::{pop_intr_off, push_intr_off}, +}; use core::{ ffi::c_char, + ptr::null_mut, sync::atomic::{AtomicBool, Ordering}, }; @@ -39,6 +43,23 @@ impl Spinlock { pub struct SpinlockGuard<'l> { pub lock: &'l Spinlock, } +impl<'l> SpinlockGuard<'l> { + /// Sleep until `wakeup(chan)` is called somewhere else, yielding the lock until then. + pub unsafe fn sleep(&self, chan: *mut core::ffi::c_void) { + let p = myproc(); + let _guard = (*p).lock.lock(); + self.lock.unlock(); + + // Put the process to sleep. + (*p).chan = chan; + (*p).state = ProcState::Sleeping; + sched(); + + // Tidy up and reacquire the lock. + (*p).chan = null_mut(); + self.lock.lock_unguarded(); + } +} impl<'l> Drop for SpinlockGuard<'l> { fn drop(&mut self) { unsafe { self.lock.unlock() } diff --git a/kernel/rustkernel/src/sync/spinmutex.rs b/kernel/rustkernel/src/sync/spinmutex.rs index 5a618e6..ec9330e 100644 --- a/kernel/rustkernel/src/sync/spinmutex.rs +++ b/kernel/rustkernel/src/sync/spinmutex.rs @@ -1,38 +1,39 @@ +use crate::{ + proc::{myproc, sched, ProcState}, + sync::spinlock::Spinlock, +}; use core::{ cell::UnsafeCell, convert::{AsMut, AsRef}, ops::{Deref, DerefMut, Drop}, - sync::atomic::{AtomicBool, Ordering}, + ptr::null_mut, }; pub struct SpinMutex { - locked: AtomicBool, - pub inner: UnsafeCell, + lock: Spinlock, + inner: UnsafeCell, } impl SpinMutex { pub const fn new(value: T) -> SpinMutex { SpinMutex { - locked: AtomicBool::new(false), + lock: Spinlock::new(), inner: UnsafeCell::new(value), } } + pub unsafe fn as_inner(&self) -> *mut T { + self.inner.get() + } + pub unsafe fn lock_unguarded(&self) { + self.lock.lock_unguarded(); + } pub fn lock(&self) -> SpinMutexGuard<'_, T> { unsafe { - crate::trap::push_intr_off(); + self.lock_unguarded(); } - - while self.locked.swap(true, Ordering::Acquire) { - core::hint::spin_loop(); - } - SpinMutexGuard { mutex: self } } pub unsafe fn unlock(&self) { - self.locked.store(false, Ordering::Release); - - unsafe { - crate::trap::pop_intr_off(); - } + self.lock.unlock(); } } unsafe impl Sync for SpinMutex where T: Send {} @@ -40,16 +41,33 @@ unsafe impl Sync for SpinMutex where T: Send {} pub struct SpinMutexGuard<'m, T> { pub mutex: &'m SpinMutex, } +impl<'m, T> SpinMutexGuard<'m, T> { + /// Sleep until `wakeup(chan)` is called somewhere else, yielding access to the mutex until then. + pub unsafe fn sleep(&mut self, chan: *mut core::ffi::c_void) { + let p = myproc(); + let _guard = (*p).lock.lock(); + self.mutex.unlock(); + + // Put the process to sleep. + (*p).chan = chan; + (*p).state = ProcState::Sleeping; + sched(); + + // Tidy up and reacquire the mutex. + (*p).chan = null_mut(); + self.mutex.lock_unguarded(); + } +} impl<'m, T> Deref for SpinMutexGuard<'m, T> { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*self.mutex.inner.get() } + unsafe { &*self.mutex.as_inner() } } } impl<'m, T> DerefMut for SpinMutexGuard<'m, T> { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.mutex.inner.get() } + unsafe { &mut *self.mutex.as_inner() } } } impl<'m, T> AsRef for SpinMutexGuard<'m, T> {