sync_linux_no_libc/sync/mutex.rs
1use crate::sys;
2use core::cell::UnsafeCell;
3use core::error::Error;
4use core::fmt;
5use core::ops::{Deref, DerefMut};
6
7/// An enumeration of possible errors associated with a [`TryLockResult`] which
8/// can occur while trying to acquire a lock, from the [`try_lock`] method on a
9/// [`Mutex`].
10///
11/// [`try_lock`]: Mutex::try_lock
12/// [`Mutex`]: Mutex
13pub enum TryLockError {
14 /// The lock could not be acquired at this time because the operation would
15 /// otherwise block.
16 WouldBlock,
17}
18
19impl fmt::Debug for TryLockError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match *self {
22 TryLockError::WouldBlock => "WouldBlock".fmt(f),
23 }
24 }
25}
26
27impl fmt::Display for TryLockError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match *self {
30 TryLockError::WouldBlock => "try_lock failed because the operation would block",
31 }.fmt(f)
32 }
33}
34
35impl Error for TryLockError {
36 #[allow(deprecated, deprecated_in_future)]
37 fn description(&self) -> &str {
38 match *self {
39 TryLockError::WouldBlock => "try_lock failed because the operation would block",
40 }
41 }
42
43 #[allow(deprecated)]
44 fn cause(&self) -> Option<&dyn Error> {
45 None
46 }
47}
48
49/// A type alias for the result of a nonblocking locking method.
50pub type TryLockResult<Guard> = Result<Guard, TryLockError>;
51
52/// A mutual exclusion primitive useful for protecting shared data
53///
54/// This mutex will block threads waiting for the lock to become available. The
55/// mutex can be created via a [`new`] constructor. Each mutex has a type parameter
56/// which represents the data that it is protecting. The data can only be accessed
57/// through the RAII guards returned from [`lock`] and [`try_lock`], which
58/// guarantees that the data is only ever accessed when the mutex is locked.
59///
60/// # Poisoning
61///
62/// This implementation of the mutex does not implement poisoning, as it might not
63/// be possible to do in a no_std environment. This puts the responsibility of never
64/// tainting the held data on the user of the mutex.
65///
66/// [`new`]: Self::new
67/// [`lock`]: Self::lock
68/// [`try_lock`]: Self::try_lock
69/// # Examples
70///
71/// ```
72/// use sync_linux_no_libc::sync::Mutex;
73/// use std::sync::{Arc};
74/// use std::thread;
75/// use std::sync::mpsc::channel;
76///
77/// const N: usize = 10;
78///
79/// // Spawn a few threads to increment a shared variable (non-atomically), and
80/// // let the main thread know once all increments are done.
81/// //
82/// // Here we're using an Arc to share memory among threads, and the data inside
83/// // the Arc is protected with a mutex.
84/// let data = Arc::new(Mutex::new(0));
85///
86/// let (tx, rx) = channel();
87/// for _ in 0..N {
88/// let (data, tx) = (Arc::clone(&data), tx.clone());
89/// thread::spawn(move || {
90/// // The shared state can only be accessed once the lock is held.
91/// // Our non-atomic increment is safe because we're the only thread
92/// // which can access the shared state when the lock is held.
93/// //
94/// // We unwrap() the return value to assert that we are not expecting
95/// // threads to ever fail while holding the lock.
96/// let mut data = data.lock();
97/// *data += 1;
98/// if *data == N {
99/// tx.send(()).unwrap();
100/// }
101/// // the lock is unlocked here when `data` goes out of scope.
102/// });
103/// }
104///
105/// rx.recv().unwrap();
106/// ```
107///
108/// To unlock a mutex guard sooner than the end of the enclosing scope,
109/// either create an inner scope or drop the guard manually.
110///
111/// ```
112/// use sync_linux_no_libc::sync::Mutex;
113/// use std::sync::{Arc};
114/// use std::thread;
115///
116/// const N: usize = 3;
117///
118/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
119/// let res_mutex = Arc::new(Mutex::new(0));
120///
121/// let mut threads = Vec::with_capacity(N);
122/// (0..N).for_each(|_| {
123/// let data_mutex_clone = Arc::clone(&data_mutex);
124/// let res_mutex_clone = Arc::clone(&res_mutex);
125///
126/// threads.push(thread::spawn(move || {
127/// // Here we use a block to limit the lifetime of the lock guard.
128/// let result = {
129/// let mut data = data_mutex_clone.lock();
130/// // This is the result of some important and long-ish work.
131/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
132/// data.push(result);
133/// result
134/// // The mutex guard gets dropped here, together with any other values
135/// // created in the critical section.
136/// };
137/// // The guard created here is a temporary dropped at the end of the statement, i.e.
138/// // the lock would not remain being held even if the thread did some additional work.
139/// *res_mutex_clone.lock() += result;
140/// }));
141/// });
142///
143/// let mut data = data_mutex.lock();
144/// // This is the result of some important and long-ish work.
145/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
146/// data.push(result);
147/// // We drop the `data` explicitly because it's not necessary anymore and the
148/// // thread still has work to do. This allows other threads to start working on
149/// // the data immediately, without waiting for the rest of the unrelated work
150/// // to be done here.
151/// //
152/// // It's even more important here than in the threads because we `.join` the
153/// // threads after that. If we had not dropped the mutex guard, a thread could
154/// // be waiting forever for it, causing a deadlock.
155/// // As in the threads, a block could have been used instead of calling the
156/// // `drop` function.
157/// drop(data);
158/// // Here the mutex guard is not assigned to a variable and so, even if the
159/// // scope does not end after this line, the mutex is still released: there is
160/// // no deadlock.
161/// *res_mutex.lock() += result;
162///
163/// threads.into_iter().for_each(|thread| {
164/// thread
165/// .join()
166/// .expect("The thread creating or execution failed !")
167/// });
168///
169/// assert_eq!(*res_mutex.lock(), 800);
170/// ```
171///
172pub struct Mutex<T: ?Sized> {
173 inner: sys::Mutex,
174 data: UnsafeCell<T>,
175}
176
177/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
178/// the owned `T` from the `Mutex` via [`into_inner`].
179///
180/// [`into_inner`]: Mutex::into_inner
181unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
182
183/// `T` must be `Send` for [`Mutex`] to be `Sync`.
184/// This ensures that the protected data can be accessed safely from multiple threads
185/// without causing data races or other unsafe behavior.
186///
187/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
188/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
189/// this manner. For instance, consider [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html),
190/// a non-atomic reference counted smart pointer,
191/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
192/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
193/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
194/// to potential data races.
195///
196/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
197/// to one thread at a time if `T` is not `Sync`.
198unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
199
200/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
201/// dropped (falls out of scope), the lock will be unlocked.
202///
203/// The data protected by the mutex can be accessed through this guard via its
204/// [`Deref`] and [`DerefMut`] implementations.
205///
206/// This structure is created by the [`lock`] and [`try_lock`] methods on
207/// [`Mutex`].
208///
209/// [`lock`]: Mutex::lock
210/// [`try_lock`]: Mutex::try_lock
211#[must_use = "if unused the Mutex will immediately unlock"]
212#[must_not_suspend = "holding a MutexGuard across suspend \
213 points can cause deadlocks, delays, \
214 and cause Futures to not implement `Send`"]
215#[clippy::has_significant_drop]
216pub struct MutexGuard<'a, T: ?Sized + 'a> {
217 lock: &'a Mutex<T>,
218}
219
220/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
221/// release mutex locks on the same thread they were acquired.
222/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
223/// another thread.
224impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
225
226/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
227/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
228unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
229
230impl<T> Mutex<T> {
231 /// Creates a new mutex in an unlocked state ready for use.
232 ///
233 /// # Examples
234 ///
235 /// ```
236 /// use sync_linux_no_libc::sync::Mutex;
237 ///
238 /// let mutex = Mutex::new(0);
239 /// ```
240 #[inline]
241 pub const fn new(t: T) -> Mutex<T> {
242 Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
243 }
244}
245
246impl<T: ?Sized> Mutex<T> {
247 /// Acquires a mutex, blocking the current thread until it is able to do so.
248 ///
249 /// This function will block the local thread until it is available to acquire
250 /// the mutex. Upon returning, the thread is the only thread with the lock
251 /// held. An RAII guard is returned to allow scoped unlock of the lock. When
252 /// the guard goes out of scope, the mutex will be unlocked.
253 ///
254 /// The exact behavior on locking a mutex in the thread which already holds
255 /// the lock is left unspecified. However, this function will not return on
256 /// the second call (it might panic or deadlock, for example).
257 ///
258 /// # Panics
259 ///
260 /// This function might panic when called if the lock is already held by
261 /// the current thread.
262 ///
263 /// # Examples
264 ///
265 /// ```
266 /// use sync_linux_no_libc::sync::Mutex;
267 /// use std::sync::{Arc};
268 /// use std::thread;
269 ///
270 /// let mutex = Arc::new(Mutex::new(0));
271 /// let c_mutex = Arc::clone(&mutex);
272 ///
273 /// thread::spawn(move || {
274 /// *c_mutex.lock() = 10;
275 /// }).join().expect("thread::spawn failed");
276 /// assert_eq!(*mutex.lock(), 10);
277 /// ```
278 pub fn lock(&self) -> MutexGuard<'_, T> {
279 unsafe {
280 self.inner.lock();
281 MutexGuard::new(self)
282 }
283 }
284
285 /// Attempts to acquire this lock.
286 ///
287 /// If the lock could not be acquired at this time, then [`Err`] is returned.
288 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
289 /// guard is dropped.
290 ///
291 /// This function does not block.
292 ///
293 /// # Errors
294 ///
295 /// If the mutex could not be acquired because it is already locked, then
296 /// this call will return the [`WouldBlock`] error.
297 ///
298 /// [`WouldBlock`]: TryLockError::WouldBlock
299 ///
300 /// # Examples
301 ///
302 /// ```
303 /// use sync_linux_no_libc::sync::Mutex;
304 /// use std::sync::{Arc};
305 /// use std::thread;
306 ///
307 /// let mutex = Arc::new(Mutex::new(0));
308 /// let c_mutex = Arc::clone(&mutex);
309 ///
310 /// thread::spawn(move || {
311 /// let mut lock = c_mutex.try_lock();
312 /// if let Ok(ref mut mutex) = lock {
313 /// **mutex = 10;
314 /// } else {
315 /// println!("try_lock failed");
316 /// }
317 /// }).join().expect("thread::spawn failed");
318 /// assert_eq!(*mutex.lock(), 10);
319 /// ```
320 pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
321 unsafe {
322 if self.inner.try_lock() {
323 Ok(MutexGuard::new(self))
324 } else {
325 Err(TryLockError::WouldBlock)
326 }
327 }
328 }
329
330 /// Consumes this mutex, returning the underlying data.
331 ///
332 /// # Examples
333 ///
334 /// ```
335 /// use sync_linux_no_libc::sync::Mutex;
336 ///
337 /// let mutex = Mutex::new(0);
338 /// assert_eq!(mutex.into_inner(), 0);
339 /// ```
340 pub fn into_inner(self) -> T
341 where
342 T: Sized,
343 {
344 self.data.into_inner()
345 }
346
347 /// Returns a mutable reference to the underlying data.
348 ///
349 /// Since this call borrows the `Mutex` mutably, no actual locking needs to
350 /// take place -- the mutable borrow statically guarantees no new locks can be acquired
351 /// while this reference exists. Note that this method does not clear any previous abandoned locks
352 /// (e.g., via [`forget()`] on a [`MutexGuard`]).
353 ///
354 /// # Examples
355 ///
356 /// ```
357 /// use sync_linux_no_libc::sync::Mutex;
358 ///
359 /// let mut mutex = Mutex::new(0);
360 /// *mutex.get_mut() = 10;
361 /// assert_eq!(*mutex.lock(), 10);
362 /// ```
363 ///
364 /// [`forget()`]: core::mem::forget
365 pub fn get_mut(&mut self) -> &mut T {
366 self.data.get_mut()
367 }
368}
369
370impl<T> From<T> for Mutex<T> {
371 /// Creates a new mutex in an unlocked state ready for use.
372 /// This is equivalent to [`Mutex::new`].
373 fn from(t: T) -> Self {
374 Mutex::new(t)
375 }
376}
377
378impl<T: ?Sized + Default> Default for Mutex<T> {
379 /// Creates a `Mutex<T>`, with the `Default` value for T.
380 fn default() -> Mutex<T> {
381 Mutex::new(Default::default())
382 }
383}
384
385impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 let mut d = f.debug_struct("Mutex");
388 match self.try_lock() {
389 Ok(guard) => {
390 d.field("data", &&*guard);
391 }
392 Err(TryLockError::WouldBlock) => {
393 d.field("data", &format_args!("<locked>"));
394 }
395 }
396 d.finish_non_exhaustive()
397 }
398}
399
400impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
401 unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
402 MutexGuard { lock }
403 }
404}
405
406impl<T: ?Sized> Deref for MutexGuard<'_, T> {
407 type Target = T;
408
409 fn deref(&self) -> &T {
410 unsafe { &*self.lock.data.get() }
411 }
412}
413
414impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
415 fn deref_mut(&mut self) -> &mut T {
416 unsafe { &mut *self.lock.data.get() }
417 }
418}
419
420impl<T: ?Sized> Drop for MutexGuard<'_, T> {
421 #[inline]
422 fn drop(&mut self) {
423 unsafe {
424 self.lock.inner.unlock();
425 }
426 }
427}
428
429impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 fmt::Debug::fmt(&**self, f)
432 }
433}
434
435impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 (**self).fmt(f)
438 }
439}
440
441pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
442 &guard.lock.inner
443}