os_unfair_lock/
lib.rs

1#![cfg(any(target_os = "macos", target_os = "ios"))]
2#![no_std]
3#![cfg_attr(feature = "nightly", feature(coerce_unsized, unsize))]
4
5use core::cell::UnsafeCell;
6use core::default::Default;
7use core::fmt::{self, Debug, Display, Formatter};
8use core::marker::PhantomData;
9use core::ops::{Deref, DerefMut, Drop};
10
11#[allow(non_camel_case_types)]
12pub mod sys {
13    #[repr(C)]
14    pub struct os_unfair_lock(pub u32);
15
16    pub type os_unfair_lock_t = *mut os_unfair_lock;
17    pub type os_unfair_lock_s = os_unfair_lock;
18
19    pub const OS_UNFAIR_LOCK_INIT: os_unfair_lock = os_unfair_lock(0);
20
21    extern "C" {
22        // part of libSystem, no link needed
23        pub fn os_unfair_lock_lock(lock: os_unfair_lock_t);
24        pub fn os_unfair_lock_unlock(lock: os_unfair_lock_t);
25        pub fn os_unfair_lock_trylock(lock: os_unfair_lock_t) -> bool;
26        pub fn os_unfair_lock_assert_owner(lock: os_unfair_lock_t);
27        pub fn os_unfair_lock_assert_not_owner(lock: os_unfair_lock_t);
28    }
29}
30
31pub struct Mutex<T: ?Sized> {
32    pub lock: UnsafeCell<sys::os_unfair_lock>,
33    pub cell: UnsafeCell<T>,
34}
35
36struct CantSendMutexGuardBetweenThreads;
37
38pub struct MutexGuard<'a, T: ?Sized> {
39    pub mutex: &'a Mutex<T>,
40    // could just be *const (), but this produces a better error message
41    pd: PhantomData<*const CantSendMutexGuardBetweenThreads>,
42}
43
44unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
45unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
46
47impl<T: ?Sized> Mutex<T> {
48    #[inline]
49    pub const fn new(value: T) -> Self
50    where
51        T: Sized,
52    {
53        Mutex {
54            lock: UnsafeCell::new(sys::OS_UNFAIR_LOCK_INIT),
55            cell: UnsafeCell::new(value),
56        }
57    }
58    #[inline]
59    pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
60        unsafe {
61            sys::os_unfair_lock_lock(self.lock.get());
62        }
63        MutexGuard {
64            mutex: self,
65            pd: PhantomData,
66        }
67    }
68    #[inline]
69    pub fn try_lock<'a>(&'a self) -> Option<MutexGuard<'a, T>> {
70        let ok = unsafe { sys::os_unfair_lock_trylock(self.lock.get()) };
71        if ok {
72            Some(MutexGuard {
73                mutex: self,
74                pd: PhantomData,
75            })
76        } else {
77            None
78        }
79    }
80    #[inline]
81    pub fn assert_not_owner(&self) {
82        unsafe {
83            sys::os_unfair_lock_assert_not_owner(self.lock.get());
84        }
85    }
86    #[inline]
87    pub fn into_inner(self) -> T
88    where
89        T: Sized,
90    {
91        self.cell.into_inner()
92    }
93}
94
95// It's (potentially) Sync but not Send, because os_unfair_lock_unlock must be called from the
96// locking thread.
97unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> {}
98
99impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
100    type Target = T;
101    #[inline]
102    fn deref(&self) -> &T {
103        unsafe { &*self.mutex.cell.get() }
104    }
105}
106
107impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
108    #[inline]
109    fn deref_mut(&mut self) -> &mut T {
110        unsafe { &mut *self.mutex.cell.get() }
111    }
112}
113
114impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
115    #[inline]
116    fn drop(&mut self) {
117        unsafe {
118            sys::os_unfair_lock_unlock(self.mutex.lock.get());
119        }
120    }
121}
122
123// extra impls: Mutex
124
125impl<T: ?Sized + Default> Default for Mutex<T> {
126    #[inline]
127    fn default() -> Self {
128        Mutex::new(T::default())
129    }
130}
131
132impl<T: ?Sized + Debug> Debug for Mutex<T> {
133    #[inline]
134    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
135        self.lock().fmt(f)
136    }
137}
138
139impl<T: ?Sized + Display> Display for Mutex<T> {
140    #[inline]
141    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
142        self.lock().fmt(f)
143    }
144}
145
146impl<T> From<T> for Mutex<T> {
147    #[inline]
148    fn from(t: T) -> Mutex<T> {
149        Mutex::new(t)
150    }
151}
152
153#[cfg(feature = "nightly")]
154impl<T, U> core::ops::CoerceUnsized<Mutex<U>> for Mutex<T> where T: core::ops::CoerceUnsized<U> {}
155
156// extra impls: MutexGuard
157
158impl<'a, T: ?Sized + Debug> Debug for MutexGuard<'a, T> {
159    #[inline]
160    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
161        (**self).fmt(f)
162    }
163}
164
165impl<'a, T: ?Sized + Display> Display for MutexGuard<'a, T> {
166    #[inline]
167    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
168        (**self).fmt(f)
169    }
170}
171
172#[cfg(feature = "nightly")]
173impl<'a, T: ?Sized, U: ?Sized> core::ops::CoerceUnsized<MutexGuard<'a, U>> for MutexGuard<'a, T> where
174    T: core::marker::Unsize<U>
175{
176}
177
178#[cfg(test)]
179mod tests {
180    use super::Mutex;
181    const TEST_CONST: Mutex<u32> = Mutex::new(42);
182    #[test]
183    fn basics() {
184        let m = TEST_CONST;
185        *m.lock() += 1;
186        {
187            let mut g = m.try_lock().unwrap();
188            *g += 1;
189            assert!(m.try_lock().is_none());
190        }
191        m.assert_not_owner();
192        assert_eq!(*m.lock(), 44);
193        assert_eq!(m.into_inner(), 44);
194    }
195    #[test]
196    #[cfg(feature = "nightly")]
197    fn unsize() {
198        use super::MutexGuard;
199        let m: Mutex<[u8; 1]> = Mutex::new([100]);
200        (&m as &Mutex<[u8]>).lock()[0] += 1;
201        (m.lock() as MutexGuard<'_, [u8]>)[0] += 1;
202        let n: Mutex<&'static [u8; 1]> = Mutex::new(&[200]);
203        let _: Mutex<&'static [u8]> = n;
204    }
205}