Files
ygglibc/src/sync.rs
T
2024-01-09 19:30:43 +02:00

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