• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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