From 8c37fdf2d702ff1fc805f1bbc5de634e1101a4da Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 3 Sep 2022 14:05:28 +0200 Subject: [PATCH] std: make `ReentrantMutex` movable and `const`; simplify `Stdout` initialization --- library/std/src/io/stdio.rs | 41 ++++++-------- library/std/src/sync/once_lock.rs | 55 ------------------- library/std/src/sys/hermit/mutex.rs | 3 - library/std/src/sys/itron/mutex.rs | 6 -- library/std/src/sys/sgx/mutex.rs | 3 - .../std/src/sys/unix/locks/fuchsia_mutex.rs | 3 - library/std/src/sys/unix/locks/futex_mutex.rs | 3 - .../std/src/sys/unix/locks/pthread_mutex.rs | 2 +- .../std/src/sys/unsupported/locks/mutex.rs | 3 - library/std/src/sys/windows/locks/mutex.rs | 2 - library/std/src/sys_common/remutex.rs | 46 ++++------------ library/std/src/sys_common/remutex/tests.rs | 37 ++++--------- 12 files changed, 39 insertions(+), 165 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4d3736f7914..5d0ac690f81 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,6 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock}; use crate::sys::stdio; @@ -526,7 +525,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Pin<&'static ReentrantMutex>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the [`Stdout`] handle. @@ -603,24 +602,20 @@ static STDOUT: OnceLock>>> = OnceLo #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { Stdout { - inner: Pin::static_ref(&STDOUT).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) }, - |mutex| unsafe { mutex.init() }, - ), + inner: STDOUT + .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))), } } pub fn cleanup() { - if let Some(instance) = STDOUT.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = Pin::static_ref(instance).try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = STDOUT.get().and_then(ReentrantMutex::try_lock) { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); } } @@ -761,7 +756,7 @@ impl fmt::Debug for StdoutLock<'_> { /// standard library or via raw Windows API calls, will fail. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: Pin<&'static ReentrantMutex>>, + inner: &'static ReentrantMutex>, } /// A locked reference to the [`Stderr`] handle. @@ -834,16 +829,12 @@ pub struct StderrLock<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { // Note that unlike `stdout()` we don't use `at_exit` here to register a - // destructor. Stderr is not buffered , so there's no need to run a + // destructor. Stderr is not buffered, so there's no need to run a // destructor for flushing the buffer - static INSTANCE: OnceLock>> = OnceLock::new(); + static INSTANCE: ReentrantMutex> = + ReentrantMutex::new(RefCell::new(stderr_raw())); - Stderr { - inner: Pin::static_ref(&INSTANCE).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }, - |mutex| unsafe { mutex.init() }, - ), - } + Stderr { inner: &INSTANCE } } impl Stderr { diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 813516040cd..37413ec62a7 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -3,7 +3,6 @@ use crate::fmt; use crate::marker::PhantomData; use crate::mem::MaybeUninit; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::Once; /// A synchronization primitive which can be written to only once. @@ -223,60 +222,6 @@ impl OnceLock { Ok(unsafe { self.get_unchecked() }) } - /// Internal-only API that gets the contents of the cell, initializing it - /// in two steps with `f` and `g` if the cell was empty. - /// - /// `f` is called to construct the value, which is then moved into the cell - /// and given as a (pinned) mutable reference to `g` to finish - /// initialization. - /// - /// This allows `g` to inspect an manipulate the value after it has been - /// moved into its final place in the cell, but before the cell is - /// considered initialized. - /// - /// # Panics - /// - /// If `f` or `g` panics, the panic is propagated to the caller, and the - /// cell remains uninitialized. - /// - /// With the current implementation, if `g` panics, the value from `f` will - /// not be dropped. This should probably be fixed if this is ever used for - /// a type where this matters. - /// - /// It is an error to reentrantly initialize the cell from `f`. The exact - /// outcome is unspecified. Current implementation deadlocks, but this may - /// be changed to a panic in the future. - pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> - where - F: FnOnce() -> T, - G: FnOnce(Pin<&mut T>), - { - if let Some(value) = self.get_ref().get() { - // SAFETY: The inner value was already initialized, and will not be - // moved anymore. - return unsafe { Pin::new_unchecked(value) }; - } - - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|_| { - let value = f(); - // SAFETY: We use the Once (self.once) to guarantee unique access - // to the UnsafeCell (slot). - let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; - // SAFETY: The value has been written to its final place in - // self.value. We do not to move it anymore, which we promise here - // with a Pin<&mut T>. - g(unsafe { Pin::new_unchecked(value) }); - }); - - // SAFETY: The inner value has been initialized, and will not be moved - // anymore. - unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } - } - /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index eb15a04ffcf..e0184eb5baf 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -174,9 +174,6 @@ impl Mutex { Mutex { inner: Spinlock::new(MutexInner::new()) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { loop { diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 715e94c3b3d..085662e6d44 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -31,12 +31,6 @@ impl Mutex { Mutex { mtx: SpinIdOnceCell::new() } } - pub unsafe fn init(&mut self) { - // Initialize `self.mtx` eagerly - let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); - unsafe { self.mtx.set_unchecked((id, ())) }; - } - /// Get the inner mutex's ID, which is lazily created. fn raw(&self) -> abi::ID { match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 513cd77fd2a..aa747d56b0d 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -20,9 +20,6 @@ impl Mutex { Mutex { inner: SpinMutex::new(WaitVariable::new(false)) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { let mut guard = self.inner.lock(); diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs index ce427599c3b..41379f50c36 100644 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs @@ -85,9 +85,6 @@ impl Mutex { Mutex { futex: AtomicU32::new(UNLOCKED) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { let thread_self = zx_thread_self(); diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs index 99ba86e5f99..198754a28ef 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex_mutex.rs @@ -19,9 +19,6 @@ impl Mutex { Self { futex: AtomicU32::new(0) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 98afee69ba6..5964935ddb5 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -52,7 +52,7 @@ impl Mutex { Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { // Issue #33770 // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index d7cb12e0cf9..2be0b34b985 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -16,9 +16,6 @@ impl Mutex { Mutex { locked: Cell::new(false) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index f91e8f9f59a..91207f5f466 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -37,8 +37,6 @@ impl Mutex { pub const fn new() -> Mutex { Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } } - #[inline] - pub unsafe fn init(&mut self) {} #[inline] pub unsafe fn lock(&self) { diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 8921af311d4..b448ae3a997 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,13 +1,11 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; +use super::mutex as sys; use crate::cell::UnsafeCell; -use crate::marker::PhantomPinned; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -use crate::sys::locks as sys; /// A re-entrant mutual exclusion /// @@ -41,11 +39,10 @@ use crate::sys::locks as sys; /// synchronization is left to the mutex, making relaxed memory ordering for /// the `owner` field fine in all cases. pub struct ReentrantMutex { - mutex: sys::Mutex, + mutex: sys::MovableMutex, owner: AtomicUsize, lock_count: UnsafeCell, data: T, - _pinned: PhantomPinned, } unsafe impl Send for ReentrantMutex {} @@ -68,39 +65,22 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: Pin<&'a ReentrantMutex>, + lock: &'a ReentrantMutex, } impl !Send for ReentrantMutexGuard<'_, T> {} impl ReentrantMutex { /// Creates a new reentrant mutex in an unlocked state. - /// - /// # Unsafety - /// - /// This function is unsafe because it is required that `init` is called - /// 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 { + pub const fn new(t: T) -> ReentrantMutex { ReentrantMutex { - mutex: sys::Mutex::new(), + mutex: sys::MovableMutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0), data: t, - _pinned: PhantomPinned, } } - /// Initializes this mutex so it's ready for use. - /// - /// # Unsafety - /// - /// Unsafe to call more than once, and must be called after this will no - /// longer move in memory. - pub unsafe fn init(self: Pin<&mut Self>) { - self.get_unchecked_mut().mutex.init() - } - /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the caller until it is available to acquire the mutex. @@ -113,15 +93,14 @@ impl ReentrantMutex { /// 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: Pin<&Self>) -> ReentrantMutexGuard<'_, T> { + pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the lock() on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); } else { - self.mutex.lock(); + self.mutex.raw_lock(); self.owner.store(this_thread, Relaxed); debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; @@ -142,10 +121,9 @@ impl ReentrantMutex { /// 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: Pin<&Self>) -> Option> { + pub fn try_lock(&self) -> Option> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the try_lock on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); @@ -179,12 +157,12 @@ impl Deref for ReentrantMutexGuard<'_, T> { impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { - // Safety: We own the lock, and the lock is pinned. + // Safety: We own the lock. unsafe { *self.lock.lock_count.get() -= 1; if *self.lock.lock_count.get() == 0 { self.lock.owner.store(0, Relaxed); - self.lock.mutex.unlock(); + self.lock.mutex.raw_unlock(); } } } diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs index 64873b850d3..8e97ce11c34 100644 --- a/library/std/src/sys_common/remutex/tests.rs +++ b/library/std/src/sys_common/remutex/tests.rs @@ -1,18 +1,11 @@ -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; #[test] fn smoke() { - let m = unsafe { - let mut m = Box::pin(ReentrantMutex::new(())); - m.as_mut().init(); - m - }; - let m = m.as_ref(); + let m = ReentrantMutex::new(()); { let a = m.lock(); { @@ -29,20 +22,15 @@ fn smoke() { #[test] fn is_mutex() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an 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 m = Arc::new(ReentrantMutex::new(RefCell::new(0))); let m2 = m.clone(); - let lock = m.as_ref().lock(); + let lock = m.lock(); let child = thread::spawn(move || { - let lock = m2.as_ref().lock(); + let lock = m2.lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.as_ref().lock(); + let lock = m.lock(); *lock.borrow_mut() += i; } drop(lock); @@ -51,22 +39,17 @@ fn is_mutex() { #[test] fn trylock_works() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an 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 m = Arc::new(ReentrantMutex::new(())); let m2 = m.clone(); - let _lock = m.as_ref().try_lock(); - let _lock2 = m.as_ref().try_lock(); + let _lock = m.try_lock(); + let _lock2 = m.try_lock(); thread::spawn(move || { - let lock = m2.as_ref().try_lock(); + let lock = m2.try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.as_ref().try_lock(); + let _lock3 = m.try_lock(); } pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>);