1 /*
2 * Copyright (c) 2024 Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 use core::cell::UnsafeCell;
25 use core::mem;
26 use core::ops::Deref;
27 use core::ops::DerefMut;
28
29 use alloc::boxed::Box;
30
31 use crate::Error;
32
33 use crate::sys::mutex_acquire_timeout;
34 use crate::sys::mutex_destroy;
35 use crate::sys::mutex_init;
36 use crate::sys::mutex_release;
37 use crate::sys::mutex_t;
38 use crate::sys::status_t;
39
40 // TODO: `INFINITE_TIME` is defined in `lk/types.h` as `UINT32_MAX`,
41 // which in turn is defined as `UINT_MAX`, which is not recognized
42 // by bindgen according to the bug below so we use `u32::MAX`.
43 // See <https://github.com/rust-lang/rust-bindgen/issues/1636>.
44 const INFINITE_TIME: u32 = u32::MAX;
45
46 /// Try to acquire the mutex with a timeout value.
47 ///
48 /// # Safety
49 ///
50 /// Same requirements as [`mutex_acquire_timeout`].
51 #[inline]
mutex_acquire(mutex: *mut mutex_t) -> status_t52 unsafe fn mutex_acquire(mutex: *mut mutex_t) -> status_t {
53 // SAFETY: Delegated.
54 unsafe { mutex_acquire_timeout(mutex, INFINITE_TIME) }
55 }
56
57 /// A mutex that does not encapsulate the data it protects.
58 ///
59 /// This is done so that there is no manual `impl<T> Drop for Mutex<T>`,
60 /// as that prevents moving out of it.
61 struct LoneMutex {
62 /// We need to [`Box`] the C [`mutex_t`] because
63 /// it contains a [`list_node`], which cannot be moved.
64 /// `std` does a similar thing for immovable mutexes,
65 /// though they now use a `LazyBox` so that `fn new` can be a `const fn`.
66 /// We don't need that (yet), and `LazyBox` is tricky and not exposed by `std`,
67 /// so we just always allocate upfront.
68 ///
69 /// We need to put the [`mutex_t`] in an [`UnsafeCell`], too,
70 /// because it has interior mutability.
71 inner: Box<UnsafeCell<mutex_t>>,
72 }
73
74 impl LoneMutex {
new() -> Self75 fn new() -> Self {
76 // SAFETY: C types like `mutex_t` are zeroizable.
77 let mutex = unsafe { mem::zeroed() };
78 let mut inner = Box::new(UnsafeCell::new(mutex));
79 // SAFETY: `mutex_init` only writes to each field of a `mutex_t`
80 unsafe { mutex_init(inner.get_mut()) };
81 Self { inner }
82 }
83
get_raw(&self) -> *mut mutex_t84 fn get_raw(&self) -> *mut mutex_t {
85 self.inner.get()
86 }
87 }
88
89 impl Drop for LoneMutex {
drop(&mut self)90 fn drop(&mut self) {
91 // SAFETY: `mutex_destroy` is thread safe and it was `mutex_init`ialized.
92 unsafe {
93 mutex_destroy(self.get_raw());
94 }
95 }
96 }
97
98 impl Default for LoneMutex {
default() -> Self99 fn default() -> Self {
100 Self::new()
101 }
102 }
103
104 /// A mutex wrapping the C [`mutex_t`].
105 /// Its API is modeled after [`std::sync::Mutex`].
106 ///
107 /// The main differences are that [`Mutex`]:
108 ///
109 /// * doesn't support poisoning (it eagerly panics).
110 ///
111 /// * doesn't lazily [`Box`] in [`Self::new`],
112 /// so [`Self::new`] isn't a `const fn` either.
113 #[derive(Default)]
114 pub struct Mutex<T: ?Sized> {
115 mutex: LoneMutex,
116 value: UnsafeCell<T>,
117 }
118
119 impl<T> Mutex<T> {
new(value: T) -> Self120 pub fn new(value: T) -> Self {
121 Self { mutex: LoneMutex::new(), value: UnsafeCell::new(value) }
122 }
123
into_inner(self) -> T124 pub fn into_inner(self) -> T {
125 self.value.into_inner()
126 }
127 }
128
129 impl<T: ?Sized> Mutex<T> {
get_mut(&mut self) -> &mut T130 pub fn get_mut(&mut self) -> &mut T {
131 self.value.get_mut()
132 }
133 }
134
135 pub struct MutexGuard<'a, T: ?Sized> {
136 lock: &'a Mutex<T>,
137 }
138
139 impl<T: ?Sized> Mutex<T> {
lock(&self) -> MutexGuard<'_, T>140 pub fn lock(&self) -> MutexGuard<'_, T> {
141 // SAFETY: `mutex_acquire` is thread safe and it was `mutex_init`ialized.
142 let status = unsafe { mutex_acquire(self.mutex.get_raw()) };
143 assert_eq!(Error::from_lk(status), Ok(()));
144 MutexGuard { lock: &self }
145 }
146 }
147
148 impl<T: ?Sized> Drop for MutexGuard<'_, T> {
drop(&mut self)149 fn drop(&mut self) {
150 // SAFETY: `mutex_release` is thread safe and it was `mutex_init`ialized.
151 let status = unsafe { mutex_release(self.lock.mutex.get_raw()) };
152 assert_eq!(Error::from_lk(status), Ok(()));
153 }
154 }
155
156 impl<T: ?Sized> Deref for MutexGuard<'_, T> {
157 type Target = T;
158
deref(&self) -> &Self::Target159 fn deref(&self) -> &Self::Target {
160 // SAFETY: Interior mutability checked by `mutex_t`.
161 unsafe { &*self.lock.value.get() }
162 }
163 }
164
165 impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
deref_mut(&mut self) -> &mut Self::Target166 fn deref_mut(&mut self) -> &mut Self::Target {
167 // SAFETY: Interior mutability checked by `mutex_t`.
168 unsafe { &mut *self.lock.value.get() }
169 }
170 }
171
172 /// SAFETY: This is a mutex wrapping [`mutex_t`].
173 unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
174
175 /// SAFETY: This is a mutex wrapping [`mutex_t`].
176 unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
177
178 // Note: We don't impl `UnwindSafe` and `RefUnwindSafe`
179 // because we don't poison our `Mutex` upon panicking
180 // like `std::sync::Mutex` does.
181
182 impl<T> From<T> for Mutex<T> {
from(value: T) -> Self183 fn from(value: T) -> Self {
184 Self::new(value)
185 }
186 }
187