std/sys/sync/mutex/pthread.rs
1#![forbid(unsafe_op_in_unsafe_fn)]
2
3use crate::mem::forget;
4use crate::pin::Pin;
5use crate::sys::pal::sync as pal;
6use crate::sys::sync::OnceBox;
7
8pub struct Mutex {
9 pub(in crate::sys::sync) pal: OnceBox<pal::Mutex>,
10}
11
12impl Mutex {
13 #[inline]
14 pub const fn new() -> Mutex {
15 Mutex { pal: OnceBox::new() }
16 }
17
18 #[inline]
19 fn get(&self) -> Pin<&pal::Mutex> {
20 // If the initialization race is lost, the new mutex is destroyed.
21 // This is sound however, as it cannot have been locked.
22 self.pal.get_or_init(|| {
23 let mut pal = Box::pin(pal::Mutex::new());
24 // SAFETY: we only call `init` once per `pal::Mutex`, namely here.
25 unsafe { pal.as_mut().init() };
26 pal
27 })
28 }
29
30 #[inline]
31 // Make this a diagnostic item for Miri's concurrency model checker.
32 #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")]
33 pub fn lock(&self) {
34 // SAFETY: we call `init` above, therefore reentrant locking is safe.
35 // In `drop` we ensure that the mutex is not destroyed while locked.
36 unsafe { self.get().lock() }
37 }
38
39 #[inline]
40 // Make this a diagnostic item for Miri's concurrency model checker.
41 #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")]
42 pub unsafe fn unlock(&self) {
43 // SAFETY: the mutex can only be locked if it is already initialized
44 // and we observed this initialization since we observed the locking.
45 unsafe { self.pal.get_unchecked().unlock() }
46 }
47
48 #[inline]
49 // Make this a diagnostic item for Miri's concurrency model checker.
50 #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")]
51 pub fn try_lock(&self) -> bool {
52 // SAFETY: we call `init` above, therefore reentrant locking is safe.
53 // In `drop` we ensure that the mutex is not destroyed while locked.
54 unsafe { self.get().try_lock() }
55 }
56}
57
58impl Drop for Mutex {
59 fn drop(&mut self) {
60 let Some(pal) = self.pal.take() else { return };
61 // We're not allowed to pthread_mutex_destroy a locked mutex,
62 // so check first if it's unlocked.
63 if unsafe { pal.as_ref().try_lock() } {
64 unsafe { pal.as_ref().unlock() };
65 drop(pal)
66 } else {
67 // The mutex is locked. This happens if a MutexGuard is leaked.
68 // In this case, we just leak the Mutex too.
69 forget(pal)
70 }
71 }
72}