obkrnl/lock/mutex/
mod.rs

1use super::MTX_UNOWNED;
2use crate::context::{BorrowedArc, current_thread};
3use alloc::rc::Rc;
4use core::cell::UnsafeCell;
5use core::marker::PhantomData;
6use core::ops::{Deref, DerefMut};
7use core::sync::atomic::{AtomicUsize, Ordering};
8
9/// Implementation of `mtx` structure.
10pub struct Mutex<T> {
11    data: UnsafeCell<T>,
12    owning: AtomicUsize,          // mtx_lock
13    phantom: PhantomData<Rc<()>>, // For !Send and !Sync.
14}
15
16impl<T> Mutex<T> {
17    /// See `mtx_init` on the PS4 for a reference.
18    pub const fn new(data: T) -> Self {
19        Self {
20            data: UnsafeCell::new(data),
21            owning: AtomicUsize::new(MTX_UNOWNED),
22            phantom: PhantomData,
23        }
24    }
25
26    /// See `_mtx_lock_flags` on the PS4 for a reference.
27    pub fn lock(&self) -> MutexGuard<T> {
28        // Check if the current thread can sleep.
29        let td = current_thread();
30
31        if !td.can_sleep() {
32            panic!("locking a mutex in a non-sleeping context is not supported");
33        }
34
35        // Take ownership.
36        if self
37            .owning
38            .compare_exchange(
39                MTX_UNOWNED,
40                BorrowedArc::as_ptr(&td) as usize,
41                Ordering::Acquire,
42                Ordering::Relaxed,
43            )
44            .is_err()
45        {
46            todo!()
47        }
48
49        td.set_active_mutexes(td.active_mutexes() + 1);
50
51        MutexGuard {
52            data: self.data.get(),
53            lock: &self.owning,
54            phantom: PhantomData,
55        }
56    }
57
58    /// See `_mtx_unlock_flags` on the PS4 for a reference.
59    ///
60    /// # Safety
61    /// Must be called by the thread that own `lock`.
62    unsafe fn unlock(lock: &AtomicUsize) {
63        let td = current_thread();
64
65        td.set_active_mutexes(td.active_mutexes() - 1);
66
67        // TODO: There is a check for (m->lock_object).lo_data == 0 on the PS4.
68        if lock
69            .compare_exchange(
70                BorrowedArc::as_ptr(&td) as usize,
71                MTX_UNOWNED,
72                Ordering::Release,
73                Ordering::Relaxed,
74            )
75            .is_err()
76        {
77            todo!()
78        }
79    }
80}
81
82impl<T: Default> Default for Mutex<T> {
83    fn default() -> Self {
84        Self::new(T::default())
85    }
86}
87
88unsafe impl<T: Send> Send for Mutex<T> {}
89unsafe impl<T: Send> Sync for Mutex<T> {}
90
91/// An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (falls out
92/// of scope), the lock will be unlocked.
93///
94/// This struct must not implement [`Send`].
95pub struct MutexGuard<'a, T> {
96    data: *mut T,
97    lock: *const AtomicUsize,
98    phantom: PhantomData<&'a Mutex<T>>,
99}
100
101impl<'a, T> MutexGuard<'a, T> {
102    pub fn map<O, F>(this: Self, f: F) -> MappedMutex<'a, O>
103    where
104        F: FnOnce(&'a mut T) -> O + 'a,
105    {
106        let data = unsafe { f(&mut *this.data) };
107        let lock = this.lock;
108
109        core::mem::forget(this);
110
111        MappedMutex {
112            data,
113            lock,
114            phantom: PhantomData,
115        }
116    }
117}
118
119impl<T> Drop for MutexGuard<'_, T> {
120    fn drop(&mut self) {
121        // SAFETY: This struct does not implement Send.
122        unsafe { Mutex::<T>::unlock(&*self.lock) };
123    }
124}
125
126impl<T> Deref for MutexGuard<'_, T> {
127    type Target = T;
128
129    fn deref(&self) -> &Self::Target {
130        unsafe { &*self.data }
131    }
132}
133
134impl<T> DerefMut for MutexGuard<'_, T> {
135    fn deref_mut(&mut self) -> &mut Self::Target {
136        unsafe { &mut *self.data }
137    }
138}
139
140unsafe impl<T: Sync> Sync for MutexGuard<'_, T> {}
141
142/// An RAII mutex guard returned by [`MutexGuard::map()`].
143///
144/// This struct must not implement [`Send`].
145pub struct MappedMutex<'a, T> {
146    data: T,
147    lock: *const AtomicUsize,
148    phantom: PhantomData<&'a Mutex<T>>,
149}
150
151impl<T> Drop for MappedMutex<'_, T> {
152    fn drop(&mut self) {
153        // SAFETY: This struct does not implement Send.
154        unsafe { Mutex::<T>::unlock(&*self.lock) };
155    }
156}
157
158impl<T> Deref for MappedMutex<'_, T> {
159    type Target = T;
160
161    fn deref(&self) -> &Self::Target {
162        &self.data
163    }
164}
165
166impl<T> DerefMut for MappedMutex<'_, T> {
167    fn deref_mut(&mut self) -> &mut Self::Target {
168        &mut self.data
169    }
170}
171
172unsafe impl<T: Sync> Sync for MappedMutex<'_, T> {}