Move sleep_lock and sleep_mutex functionality as methods of Spinlock and SpinMutex
This commit is contained in:
parent
9f23b68c00
commit
585da48917
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub(crate) mod mutex;
|
||||
pub mod sleeplock;
|
||||
pub mod spinlock;
|
||||
pub mod spinmutex;
|
||||
|
@ -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() }
|
||||
// }
|
||||
// }
|
||||
//
|
@ -1,4 +1,4 @@
|
||||
use crate::proc::{wakeup, sleep};
|
||||
use crate::proc::{sleep, wakeup};
|
||||
use core::{
|
||||
ffi::c_char,
|
||||
ptr::addr_of,
|
||||
|
@ -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() }
|
||||
|
@ -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> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user