]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use crate::cell::UnsafeCell; |
dc9dc135 | 2 | use crate::mem::MaybeUninit; |
1a4d82fc | 3 | |
dfeec247 XL |
4 | pub struct Mutex { |
5 | inner: UnsafeCell<libc::pthread_mutex_t>, | |
6 | } | |
1a4d82fc JJ |
7 | |
8 | #[inline] | |
92a42be0 | 9 | pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { |
1a4d82fc JJ |
10 | m.inner.get() |
11 | } | |
12 | ||
c34b1796 | 13 | unsafe impl Send for Mutex {} |
1a4d82fc JJ |
14 | unsafe impl Sync for Mutex {} |
15 | ||
c34b1796 | 16 | #[allow(dead_code)] // sys isn't exported yet |
1a4d82fc | 17 | impl Mutex { |
62682a34 | 18 | pub const fn new() -> Mutex { |
b7449926 XL |
19 | // Might be moved to a different address, so it is better to avoid |
20 | // initialization of potentially opaque OS data before it landed. | |
21 | // Be very careful using this newly constructed `Mutex`, reentrant | |
22 | // locking is undefined behavior until `init` is called! | |
92a42be0 | 23 | Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } |
1a4d82fc JJ |
24 | } |
25 | #[inline] | |
3157f602 XL |
26 | pub unsafe fn init(&mut self) { |
27 | // Issue #33770 | |
28 | // | |
29 | // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have | |
30 | // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you | |
31 | // try to re-lock it from the same thread when you already hold a lock. | |
32 | // | |
33 | // In practice, glibc takes advantage of this undefined behavior to | |
34 | // implement hardware lock elision, which uses hardware transactional | |
35 | // memory to avoid acquiring the lock. While a transaction is in | |
36 | // progress, the lock appears to be unlocked. This isn't a problem for | |
37 | // other threads since the transactional memory will abort if a conflict | |
38 | // is detected, however no abort is generated if re-locking from the | |
39 | // same thread. | |
40 | // | |
41 | // Since locking the same mutex twice will result in two aliasing &mut | |
42 | // references, we instead create the mutex with type | |
43 | // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to | |
44 | // re-lock it from the same thread, thus avoiding undefined behavior. | |
dc9dc135 XL |
45 | let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); |
46 | let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); | |
3157f602 | 47 | debug_assert_eq!(r, 0); |
dc9dc135 | 48 | let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); |
3157f602 | 49 | debug_assert_eq!(r, 0); |
dc9dc135 | 50 | let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); |
3157f602 | 51 | debug_assert_eq!(r, 0); |
dc9dc135 | 52 | let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); |
3157f602 XL |
53 | debug_assert_eq!(r, 0); |
54 | } | |
55 | #[inline] | |
1a4d82fc | 56 | pub unsafe fn lock(&self) { |
92a42be0 | 57 | let r = libc::pthread_mutex_lock(self.inner.get()); |
1a4d82fc JJ |
58 | debug_assert_eq!(r, 0); |
59 | } | |
60 | #[inline] | |
61 | pub unsafe fn unlock(&self) { | |
92a42be0 | 62 | let r = libc::pthread_mutex_unlock(self.inner.get()); |
1a4d82fc JJ |
63 | debug_assert_eq!(r, 0); |
64 | } | |
65 | #[inline] | |
66 | pub unsafe fn try_lock(&self) -> bool { | |
92a42be0 | 67 | libc::pthread_mutex_trylock(self.inner.get()) == 0 |
1a4d82fc JJ |
68 | } |
69 | #[inline] | |
85aaf69f | 70 | #[cfg(not(target_os = "dragonfly"))] |
1a4d82fc | 71 | pub unsafe fn destroy(&self) { |
92a42be0 | 72 | let r = libc::pthread_mutex_destroy(self.inner.get()); |
1a4d82fc JJ |
73 | debug_assert_eq!(r, 0); |
74 | } | |
85aaf69f SL |
75 | #[inline] |
76 | #[cfg(target_os = "dragonfly")] | |
77 | pub unsafe fn destroy(&self) { | |
92a42be0 | 78 | let r = libc::pthread_mutex_destroy(self.inner.get()); |
85aaf69f | 79 | // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a |
92a42be0 | 80 | // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. |
85aaf69f SL |
81 | // Once it is used (locked/unlocked) or pthread_mutex_init() is called, |
82 | // this behaviour no longer occurs. | |
83 | debug_assert!(r == 0 || r == libc::EINVAL); | |
84 | } | |
1a4d82fc | 85 | } |
9346a6ac | 86 | |
dfeec247 XL |
87 | pub struct ReentrantMutex { |
88 | inner: UnsafeCell<libc::pthread_mutex_t>, | |
89 | } | |
9346a6ac AL |
90 | |
91 | unsafe impl Send for ReentrantMutex {} | |
92 | unsafe impl Sync for ReentrantMutex {} | |
93 | ||
94 | impl ReentrantMutex { | |
ba9703b0 | 95 | pub const unsafe fn uninitialized() -> ReentrantMutex { |
dc9dc135 | 96 | ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } |
d9579d0f AL |
97 | } |
98 | ||
ba9703b0 | 99 | pub unsafe fn init(&self) { |
dc9dc135 XL |
100 | let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); |
101 | let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); | |
9346a6ac | 102 | debug_assert_eq!(result, 0); |
dfeec247 XL |
103 | let result = |
104 | libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); | |
9346a6ac | 105 | debug_assert_eq!(result, 0); |
dc9dc135 | 106 | let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); |
9346a6ac | 107 | debug_assert_eq!(result, 0); |
dc9dc135 | 108 | let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); |
9346a6ac | 109 | debug_assert_eq!(result, 0); |
9346a6ac AL |
110 | } |
111 | ||
112 | pub unsafe fn lock(&self) { | |
92a42be0 | 113 | let result = libc::pthread_mutex_lock(self.inner.get()); |
9346a6ac AL |
114 | debug_assert_eq!(result, 0); |
115 | } | |
116 | ||
117 | #[inline] | |
118 | pub unsafe fn try_lock(&self) -> bool { | |
92a42be0 | 119 | libc::pthread_mutex_trylock(self.inner.get()) == 0 |
9346a6ac AL |
120 | } |
121 | ||
122 | pub unsafe fn unlock(&self) { | |
92a42be0 | 123 | let result = libc::pthread_mutex_unlock(self.inner.get()); |
9346a6ac AL |
124 | debug_assert_eq!(result, 0); |
125 | } | |
126 | ||
127 | pub unsafe fn destroy(&self) { | |
92a42be0 | 128 | let result = libc::pthread_mutex_destroy(self.inner.get()); |
9346a6ac AL |
129 | debug_assert_eq!(result, 0); |
130 | } | |
131 | } |