Move sleep_lock and sleep_mutex functionality as methods of Spinlock and SpinMutex

This commit is contained in:
Garen Tyler 2023-10-29 14:45:47 -06:00
parent 9f23b68c00
commit 585da48917
Signed by: garentyler
GPG Key ID: D7A048C454CB7054
7 changed files with 67 additions and 156 deletions

View File

@ -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();

View File

@ -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<T>(chan: *mut c_void, mutex: &mut SpinMutexGuard<T>) {
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);
}

View File

@ -1,4 +1,3 @@
pub(crate) mod mutex;
pub mod sleeplock;
pub mod spinlock;
pub mod spinmutex;

View File

@ -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<T> {
// locked: AtomicBool,
// inner: UnsafeCell<T>,
// }
// impl<T> Mutex<T> {
// pub const fn new(value: T) -> Mutex<T> {
// 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<T> Sync for Mutex<T> where T: Send {}
//
// pub struct MutexGuard<'m, T> {
// pub mutex: &'m Mutex<T>,
// }
// 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() }
// }
// }
//

View File

@ -1,4 +1,4 @@
use crate::proc::{wakeup, sleep};
use crate::proc::{sleep, wakeup};
use core::{
ffi::c_char,
ptr::addr_of,

View File

@ -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() }

View File

@ -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<T> {
locked: AtomicBool,
pub inner: UnsafeCell<T>,
lock: Spinlock,
inner: UnsafeCell<T>,
}
impl<T> SpinMutex<T> {
pub const fn new(value: T) -> SpinMutex<T> {
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<T> Sync for SpinMutex<T> where T: Send {}
@ -40,16 +41,33 @@ unsafe impl<T> Sync for SpinMutex<T> where T: Send {}
pub struct SpinMutexGuard<'m, T> {
pub mutex: &'m SpinMutex<T>,
}
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<T> for SpinMutexGuard<'m, T> {