mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
Re-implement mutex with waiter queue
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
25b45326ab
commit
b3a7899428
@ -1,30 +1,59 @@
|
|||||||
use super::spin::{SpinLock, SpinLockGuard};
|
use super::WaitQueue;
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
/// A mutex with waitqueue.
|
||||||
pub struct Mutex<T> {
|
pub struct Mutex<T> {
|
||||||
inner: SpinLock<T>,
|
val: UnsafeCell<T>,
|
||||||
|
lock: AtomicBool,
|
||||||
|
queue: WaitQueue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Mutex<T> {
|
impl<T> Mutex<T> {
|
||||||
#[inline(always)]
|
/// Create a new mutex.
|
||||||
pub const fn new(val: T) -> Self {
|
pub fn new(val: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: SpinLock::new(val),
|
val: UnsafeCell::new(val),
|
||||||
|
lock: AtomicBool::new(false),
|
||||||
|
queue: WaitQueue::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Acquire the mutex.
|
||||||
|
///
|
||||||
|
/// This method runs in a block way until the mutex can be acquired.
|
||||||
pub fn lock(&self) -> MutexGuard<T> {
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
MutexGuard {
|
self.queue.wait_until(|| self.try_lock())
|
||||||
lock: self.inner.lock(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try Acquire the mutex immedidately.
|
||||||
|
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
||||||
|
self.acquire_lock().then(|| MutexGuard { mutex: &self })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the mutex and wake up one thread which is blocked on this mutex.
|
||||||
|
fn unlock(&self) {
|
||||||
|
self.release_lock();
|
||||||
|
self.queue.wake_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn acquire_lock(&self) -> bool {
|
||||||
|
self.lock
|
||||||
|
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_lock(&self) {
|
||||||
|
self.lock.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for Mutex<T> {
|
impl<T: fmt::Debug> fmt::Debug for Mutex<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Debug::fmt(&self.inner, f)
|
fmt::Debug::fmt(&self.val, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,20 +61,26 @@ unsafe impl<T: Send> Send for Mutex<T> {}
|
|||||||
unsafe impl<T: Send> Sync for Mutex<T> {}
|
unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||||
|
|
||||||
pub struct MutexGuard<'a, T> {
|
pub struct MutexGuard<'a, T> {
|
||||||
lock: SpinLockGuard<'a, T>,
|
mutex: &'a Mutex<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Deref for MutexGuard<'a, T> {
|
impl<'a, T> Deref for MutexGuard<'a, T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.lock.deref()
|
unsafe { &*self.mutex.val.get() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.lock.deref_mut()
|
unsafe { &mut *self.mutex.val.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.mutex.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use super::SpinLock;
|
||||||
use alloc::{collections::VecDeque, sync::Arc};
|
use alloc::{collections::VecDeque, sync::Arc};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
use crate::task::schedule;
|
use crate::task::schedule;
|
||||||
|
|
||||||
use super::SpinLock;
|
|
||||||
|
|
||||||
/// A wait queue.
|
/// A wait queue.
|
||||||
///
|
///
|
||||||
/// One may wait on a wait queue to put its executing thread to sleep.
|
/// One may wait on a wait queue to put its executing thread to sleep.
|
||||||
@ -80,7 +79,9 @@ impl WaitQueue {
|
|||||||
|
|
||||||
/// removes all waiters that have finished wait
|
/// removes all waiters that have finished wait
|
||||||
fn finish_wait(&self) {
|
fn finish_wait(&self) {
|
||||||
self.waiters.lock_irq_disabled().retain(|waiter| !waiter.is_finished())
|
self.waiters
|
||||||
|
.lock_irq_disabled()
|
||||||
|
.retain(|waiter| !waiter.is_finished())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ unsafe impl<const ORDER: usize> GlobalAlloc for LockedHeap<ORDER> {
|
|||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
debug_assert!(ptr as usize != 0);
|
debug_assert!(ptr as usize != 0);
|
||||||
self.0.lock_irq_disabled().dealloc(NonNull::new_unchecked(ptr), layout)
|
self.0
|
||||||
|
.lock_irq_disabled()
|
||||||
|
.dealloc(NonNull::new_unchecked(ptr), layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user