diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2020-10-10 20:20:14 +0200 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2020-12-08 22:57:57 +0100 |
| commit | 67c18fdec59cf313818b8606c3847a8af6bcf684 (patch) | |
| tree | 283449abe305d1eb37410871e507cd1c0fcdcf04 /library/std/src/sys_common | |
| parent | 8fe90966e19a4c3b6d05484d5368e5f9b444eb8b (diff) | |
| download | rust-67c18fdec59cf313818b8606c3847a8af6bcf684.tar.gz rust-67c18fdec59cf313818b8606c3847a8af6bcf684.zip | |
Use Pin for the 'don't move' requirement of ReentrantMutex.
The code in io::stdio before this change misused the ReentrantMutexes, by calling init() on them and moving them afterwards. Now that ReentrantMutex requires Pin for init(), this mistake is no longer easy to make.
Diffstat (limited to 'library/std/src/sys_common')
| -rw-r--r-- | library/std/src/sys_common/remutex.rs | 52 | ||||
| -rw-r--r-- | library/std/src/sys_common/remutex/tests.rs | 35 |
2 files changed, 39 insertions, 48 deletions
diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 35d6701efd0..475bfca9b6d 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,9 +1,10 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; -use crate::fmt; +use crate::marker::PhantomPinned; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::pin::Pin; use crate::sys::mutex as sys; /// A re-entrant mutual exclusion @@ -14,6 +15,7 @@ use crate::sys::mutex as sys; pub struct ReentrantMutex<T> { inner: sys::ReentrantMutex, data: T, + _pinned: PhantomPinned, } unsafe impl<T: Send> Send for ReentrantMutex<T> {} @@ -36,7 +38,7 @@ impl<T> RefUnwindSafe for ReentrantMutex<T> {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: &'a ReentrantMutex<T>, + lock: Pin<&'a ReentrantMutex<T>>, } impl<T> !Send for ReentrantMutexGuard<'_, T> {} @@ -50,7 +52,11 @@ impl<T> ReentrantMutex<T> { /// once this mutex is in its final resting place, and only then are the /// lock/unlock methods safe. pub const unsafe fn new(t: T) -> ReentrantMutex<T> { - ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t } + ReentrantMutex { + inner: sys::ReentrantMutex::uninitialized(), + data: t, + _pinned: PhantomPinned, + } } /// Initializes this mutex so it's ready for use. @@ -59,8 +65,8 @@ impl<T> ReentrantMutex<T> { /// /// Unsafe to call more than once, and must be called after this will no /// longer move in memory. - pub unsafe fn init(&self) { - self.inner.init(); + pub unsafe fn init(self: Pin<&mut Self>) { + self.get_unchecked_mut().inner.init() } /// Acquires a mutex, blocking the current thread until it is able to do so. @@ -75,9 +81,9 @@ impl<T> ReentrantMutex<T> { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { + pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> { unsafe { self.inner.lock() } - ReentrantMutexGuard::new(&self) + ReentrantMutexGuard { lock: self } } /// Attempts to acquire this lock. @@ -92,8 +98,12 @@ impl<T> ReentrantMutex<T> { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> { - if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None } + pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> { + if unsafe { self.inner.try_lock() } { + Some(ReentrantMutexGuard { lock: self }) + } else { + None + } } } @@ -106,30 +116,6 @@ impl<T> Drop for ReentrantMutex<T> { } } -impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.try_lock() { - Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), - None => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("<locked>") - } - } - - f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() - } - } - } -} - -impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { - fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> { - ReentrantMutexGuard { lock } - } -} - impl<T> Deref for ReentrantMutexGuard<'_, T> { type Target = T; diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs index 9c686e579d7..88453ded2f9 100644 --- a/library/std/src/sys_common/remutex/tests.rs +++ b/library/std/src/sys_common/remutex/tests.rs @@ -1,4 +1,6 @@ +use crate::boxed::Box; use crate::cell::RefCell; +use crate::pin::Pin; use crate::sync::Arc; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread; @@ -6,10 +8,11 @@ use crate::thread; #[test] fn smoke() { let m = unsafe { - let m = ReentrantMutex::new(()); - m.init(); + let mut m = Box::pin(ReentrantMutex::new(())); + m.as_mut().init(); m }; + let m = m.as_ref(); { let a = m.lock(); { @@ -27,18 +30,19 @@ fn smoke() { #[test] fn is_mutex() { let m = unsafe { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - m.init(); - m + // FIXME: Simplify this if Arc gets a Arc::get_pin_mut. + let mut m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); + Pin::new_unchecked(m) }; let m2 = m.clone(); - let lock = m.lock(); + let lock = m.as_ref().lock(); let child = thread::spawn(move || { - let lock = m2.lock(); + let lock = m2.as_ref().lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.lock(); + let lock = m.as_ref().lock(); *lock.borrow_mut() += i; } drop(lock); @@ -48,20 +52,21 @@ fn is_mutex() { #[test] fn trylock_works() { let m = unsafe { - let m = Arc::new(ReentrantMutex::new(())); - m.init(); - m + // FIXME: Simplify this if Arc gets a Arc::get_pin_mut. + let mut m = Arc::new(ReentrantMutex::new(())); + Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); + Pin::new_unchecked(m) }; let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); + let _lock = m.as_ref().try_lock(); + let _lock2 = m.as_ref().try_lock(); thread::spawn(move || { - let lock = m2.try_lock(); + let lock = m2.as_ref().try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.try_lock(); + let _lock3 = m.as_ref().try_lock(); } pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>); |
