113 lines
2.2 KiB
Rust
113 lines
2.2 KiB
Rust
use core::{
|
|
cell::UnsafeCell,
|
|
ops::{Deref, DerefMut},
|
|
sync::atomic::{AtomicU32, Ordering},
|
|
};
|
|
|
|
use yggdrasil_rt::{process::MutexOperation, sys as syscall};
|
|
|
|
pub struct RawMutex {
|
|
value: AtomicU32,
|
|
}
|
|
|
|
pub struct Mutex<T> {
|
|
value: UnsafeCell<T>,
|
|
inner: RawMutex,
|
|
}
|
|
|
|
pub struct MutexGuard<'a, T> {
|
|
lock: &'a Mutex<T>,
|
|
}
|
|
|
|
impl RawMutex {
|
|
const UNLOCKED: u32 = 0;
|
|
const LOCKED: u32 = 1;
|
|
|
|
pub const fn new() -> Self {
|
|
Self {
|
|
value: AtomicU32::new(Self::UNLOCKED),
|
|
}
|
|
}
|
|
|
|
fn try_lock(&self) -> bool {
|
|
self.value
|
|
.compare_exchange(
|
|
Self::UNLOCKED,
|
|
Self::LOCKED,
|
|
Ordering::Acquire,
|
|
Ordering::Relaxed,
|
|
)
|
|
.is_ok()
|
|
}
|
|
|
|
pub fn lock(&self) {
|
|
loop {
|
|
if self.try_lock() {
|
|
// Got a lock
|
|
return;
|
|
}
|
|
|
|
self.wait(Self::LOCKED);
|
|
}
|
|
}
|
|
|
|
pub unsafe fn release(&self) {
|
|
if self.value.swap(Self::UNLOCKED, Ordering::Release) == Self::LOCKED {
|
|
self.wake();
|
|
}
|
|
}
|
|
|
|
fn wait(&self, value: u32) {
|
|
unsafe {
|
|
syscall::mutex(&self.value, &MutexOperation::Wait(value, None)).unwrap();
|
|
}
|
|
}
|
|
|
|
fn wake(&self) {
|
|
unsafe {
|
|
syscall::mutex(&self.value, &MutexOperation::Wake).unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for RawMutex {}
|
|
unsafe impl Sync for RawMutex {}
|
|
|
|
impl<T> Mutex<T> {
|
|
pub const fn new(value: T) -> Self {
|
|
Self {
|
|
value: UnsafeCell::new(value),
|
|
inner: RawMutex::new(),
|
|
}
|
|
}
|
|
|
|
pub fn lock(&self) -> MutexGuard<T> {
|
|
self.inner.lock();
|
|
MutexGuard { lock: self }
|
|
}
|
|
}
|
|
|
|
unsafe impl<T> Sync for Mutex<T> {}
|
|
|
|
impl<T> Deref for MutexGuard<'_, T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
unsafe { &*self.lock.value.get() }
|
|
}
|
|
}
|
|
|
|
impl<T> DerefMut for MutexGuard<'_, T> {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
unsafe { &mut *self.lock.value.get() }
|
|
}
|
|
}
|
|
|
|
impl<T> Drop for MutexGuard<'_, T> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
self.lock.inner.release();
|
|
}
|
|
}
|
|
}
|