diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index f6083530005..46f45b19771 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -70,9 +70,13 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { mutex.lock(); res == 0 } +} - pub unsafe fn destroy(&self) { - let _ = abi::sem_destroy(self.sem1); - let _ = abi::sem_destroy(self.sem2); +impl Drop for Condvar { + fn drop(&mut self) { + unsafe { + let _ = abi::sem_destroy(self.sem1); + let _ = abi::sem_destroy(self.sem2); + } } } diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 97b4c49896f..ef44bf411fb 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -215,7 +215,4 @@ pub unsafe fn try_lock(&self) -> bool { } guard.locked } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 690bb155e1a..d43fa08a171 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -84,12 +84,6 @@ pub unsafe fn write_unlock(&self) { // FIXME: should only wake up one of these some of the time self.cond.notify_all(); } - - #[inline] - pub unsafe fn destroy(&self) { - self.lock.destroy(); - self.cond.destroy(); - } } impl State { diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs index ed26c528027..008cd8fb1e3 100644 --- a/library/std/src/sys/itron/condvar.rs +++ b/library/std/src/sys/itron/condvar.rs @@ -117,8 +117,6 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { unsafe { mutex.lock() }; success } - - pub unsafe fn destroy(&self) {} } mod waiter_queue { diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 5ee231882bb..2ba8454ff92 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -64,8 +64,10 @@ pub unsafe fn try_lock(&self) -> bool { } } } +} - pub unsafe fn destroy(&self) { +impl Drop for Mutex { + fn drop(&mut self) { if let Some(mtx) = self.mtx.get().map(|x| x.0) { expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); } diff --git a/library/std/src/sys/sgx/condvar.rs b/library/std/src/sys/sgx/condvar.rs index c9736880b08..36534e0eff3 100644 --- a/library/std/src/sys/sgx/condvar.rs +++ b/library/std/src/sys/sgx/condvar.rs @@ -1,4 +1,5 @@ use crate::sys::locks::Mutex; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; use super::waitqueue::{SpinMutex, WaitQueue, WaitVariable}; @@ -7,16 +8,19 @@ pub struct Condvar { inner: SpinMutex>, } -pub type MovableCondvar = Box; +pub(crate) type MovableCondvar = LazyBox; + +impl LazyInit for Condvar { + fn init() -> Box { + Box::new(Self::new()) + } +} impl Condvar { pub const fn new() -> Condvar { Condvar { inner: SpinMutex::new(WaitVariable::new(())) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn notify_one(&self) { let _ = WaitQueue::notify_one(self.inner.lock()); @@ -38,7 +42,4 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { unsafe { mutex.lock() }; success } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 98a390c4c2b..513cd77fd2a 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -1,11 +1,18 @@ use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct Mutex { inner: SpinMutex>, } // not movable: see UnsafeList implementation -pub type MovableMutex = Box; +pub(crate) type MovableMutex = LazyBox; + +impl LazyInit for Mutex { + fn init() -> Box { + Box::new(Self::new()) + } +} // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { @@ -52,7 +59,4 @@ pub unsafe fn try_lock(&self) -> bool { true } } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 47be4c006ec..a97fb9ab026 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -2,6 +2,7 @@ mod tests; use crate::num::NonZeroUsize; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -13,7 +14,13 @@ pub struct RwLock { writer: SpinMutex>, } -pub type MovableRwLock = Box; +pub(crate) type MovableRwLock = LazyBox; + +impl LazyInit for RwLock { + fn init() -> Box { + Box::new(Self::new()) + } +} // Check at compile time that RwLock size matches C definition (see test_c_rwlock_initializer below) // @@ -168,9 +175,6 @@ unsafe fn unlock(&self) { unsafe { self.__read_unlock(rguard, wguard) }; } } - - #[inline] - pub unsafe fn destroy(&self) {} } // The following functions are needed by libunwind. These symbols are named diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs index df16cc680ad..433abc895f5 100644 --- a/library/std/src/sys/solid/rwlock.rs +++ b/library/std/src/sys/solid/rwlock.rs @@ -82,9 +82,11 @@ pub unsafe fn write_unlock(&self) { let rwl = self.raw(); expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); } +} +impl Drop for RwLock { #[inline] - pub unsafe fn destroy(&self) { + fn drop(&mut self) { if let Some(rwl) = self.rwl.get().map(|x| x.0) { expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl"); } diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 7a63af1ad7c..a9a1a32c5af 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -24,9 +24,6 @@ pub const fn new() -> Self { #[inline] pub unsafe fn init(&mut self) {} - #[inline] - pub unsafe fn destroy(&self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() @@ -118,12 +115,6 @@ pub const fn new() -> Self { Self { futex: AtomicU32::new(0) } } - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn destroy(&self) {} - // All the memory orderings here are `Relaxed`, // because synchronization is done by unlocking and locking the mutex. diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 5ff1aba7974..1f902f50587 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -63,9 +63,6 @@ pub const fn new() -> Self { Self { state: AtomicU32::new(0), writer_notify: AtomicU32::new(0) } } - #[inline] - pub unsafe fn destroy(&self) {} - #[inline] pub unsafe fn try_read(&self) -> bool { self.state diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index 04c5c489fc9..03400efa3c9 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -9,14 +9,14 @@ ))] { mod futex; mod futex_rwlock; - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar}; + pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; } else { mod pthread_mutex; mod pthread_rwlock; mod pthread_condvar; - pub use pthread_mutex::{Mutex, MovableMutex}; - pub use pthread_rwlock::{RwLock, MovableRwLock}; - pub use pthread_condvar::{Condvar, MovableCondvar}; + pub(crate) use pthread_mutex::{Mutex, MovableMutex}; + pub(crate) use pthread_rwlock::{RwLock, MovableRwLock}; + pub(crate) use pthread_condvar::MovableCondvar; } } diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 099aa68706f..61c28d696bc 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -1,12 +1,13 @@ use crate::cell::UnsafeCell; use crate::sys::locks::{pthread_mutex, Mutex}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; pub struct Condvar { inner: UnsafeCell, } -pub type MovableCondvar = Box; +pub(crate) type MovableCondvar = LazyBox; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} @@ -18,6 +19,14 @@ fn saturating_cast_to_time_t(value: u64) -> libc::time_t { if value > ::MAX as u64 { ::MAX } else { value as libc::time_t } } +impl LazyInit for Condvar { + fn init() -> Box { + let mut condvar = Box::new(Self::new()); + unsafe { condvar.init() }; + condvar + } +} + impl Condvar { pub const fn new() -> Condvar { // Might be moved and address is changing it is better to avoid @@ -32,14 +41,14 @@ pub const fn new() -> Condvar { target_os = "android", target_os = "redox" ))] - pub unsafe fn init(&mut self) {} + unsafe fn init(&mut self) {} // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet // So on that platform, init() should always be called // Moreover, that platform does not have pthread_condattr_setclock support, // hence that initialization should be skipped as well #[cfg(target_os = "espidf")] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null()); assert_eq!(r, 0); } @@ -52,7 +61,7 @@ pub unsafe fn init(&mut self) { target_os = "redox", target_os = "espidf" )))] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { use crate::mem::MaybeUninit; let mut attr = MaybeUninit::::uninit(); let r = libc::pthread_condattr_init(attr.as_mut_ptr()); @@ -179,14 +188,14 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { #[inline] #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_cond_destroy(self.inner.get()); debug_assert_eq!(r, 0); } #[inline] #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_cond_destroy(self.inner.get()); // On DragonFly pthread_cond_destroy() returns EINVAL if called on // a condvar that was just initialized with @@ -195,3 +204,10 @@ pub unsafe fn destroy(&self) { debug_assert!(r == 0 || r == libc::EINVAL); } } + +impl Drop for Condvar { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 76840ce74dd..916e898d890 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -1,12 +1,13 @@ use crate::cell::UnsafeCell; use crate::mem::MaybeUninit; use crate::sys::cvt_nz; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct Mutex { inner: UnsafeCell, } -pub type MovableMutex = Box; +pub(crate) type MovableMutex = LazyBox; #[inline] pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { @@ -16,6 +17,14 @@ pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +impl LazyInit for Mutex { + fn init() -> Box { + let mut mutex = Box::new(Self::new()); + unsafe { mutex.init() }; + mutex + } +} + impl Mutex { pub const fn new() -> Mutex { // Might be moved to a different address, so it is better to avoid @@ -73,13 +82,13 @@ pub unsafe fn try_lock(&self) -> bool { } #[inline] #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_mutex_destroy(self.inner.get()); debug_assert_eq!(r, 0); } #[inline] #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_mutex_destroy(self.inner.get()); // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. @@ -89,6 +98,13 @@ pub unsafe fn destroy(&self) { } } +impl Drop for Mutex { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} + pub(super) struct PthreadMutexAttr<'a>(pub &'a mut MaybeUninit); impl Drop for PthreadMutexAttr<'_> { diff --git a/library/std/src/sys/unix/locks/pthread_rwlock.rs b/library/std/src/sys/unix/locks/pthread_rwlock.rs index 11a0c0457cd..75e5759c787 100644 --- a/library/std/src/sys/unix/locks/pthread_rwlock.rs +++ b/library/std/src/sys/unix/locks/pthread_rwlock.rs @@ -1,5 +1,6 @@ use crate::cell::UnsafeCell; use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct RwLock { inner: UnsafeCell, @@ -7,11 +8,17 @@ pub struct RwLock { num_readers: AtomicUsize, } -pub type MovableRwLock = Box; +pub(crate) type MovableRwLock = LazyBox; unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} +impl LazyInit for RwLock { + fn init() -> Box { + Box::new(Self::new()) + } +} + impl RwLock { pub const fn new() -> RwLock { RwLock { @@ -128,7 +135,7 @@ pub unsafe fn write_unlock(&self) { self.raw_unlock(); } #[inline] - pub unsafe fn destroy(&self) { + unsafe fn destroy(&mut self) { let r = libc::pthread_rwlock_destroy(self.inner.get()); // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a // rwlock that was just initialized with @@ -141,3 +148,10 @@ pub unsafe fn destroy(&self) { } } } + +impl Drop for RwLock { + #[inline] + fn drop(&mut self) { + unsafe { self.destroy() }; + } +} diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs index 8dbe03bad9b..f27bf2b26bd 100644 --- a/library/std/src/sys/unsupported/locks/condvar.rs +++ b/library/std/src/sys/unsupported/locks/condvar.rs @@ -10,9 +10,6 @@ pub const fn new() -> Condvar { Condvar {} } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn notify_one(&self) {} @@ -26,7 +23,4 @@ pub unsafe fn wait(&self, _mutex: &Mutex) { pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { panic!("condvar wait not supported"); } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index cad991aae5e..56bad71b189 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -32,7 +32,4 @@ pub unsafe fn unlock(&self) { pub unsafe fn try_lock(&self) -> bool { self.locked.replace(true) == false } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs index 14fd351314c..bf6e2d3d080 100644 --- a/library/std/src/sys/unsupported/locks/rwlock.rs +++ b/library/std/src/sys/unsupported/locks/rwlock.rs @@ -62,7 +62,4 @@ pub unsafe fn read_unlock(&self) { pub unsafe fn write_unlock(&self) { assert_eq!(self.mode.replace(0), -1); } - - #[inline] - pub unsafe fn destroy(&self) {} } diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 9992e44b0e7..55b5ad314da 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -54,8 +54,8 @@ pub mod locks { #![allow(unsafe_op_in_unsafe_fn)] mod futex; mod futex_rwlock; - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; + pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; } #[path = "atomics/futex.rs"] pub mod futex; diff --git a/library/std/src/sys/windows/locks/condvar.rs b/library/std/src/sys/windows/locks/condvar.rs index dfd8cfdceee..59e2c1be0f0 100644 --- a/library/std/src/sys/windows/locks/condvar.rs +++ b/library/std/src/sys/windows/locks/condvar.rs @@ -18,9 +18,6 @@ pub const fn new() -> Condvar { Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0); @@ -51,8 +48,4 @@ pub unsafe fn notify_one(&self) { pub unsafe fn notify_all(&self) { c::WakeAllConditionVariable(self.inner.get()) } - - pub unsafe fn destroy(&self) { - // ... - } } diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index 9fa280b8b76..08f55844a0e 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -53,9 +53,4 @@ pub unsafe fn try_lock(&self) -> bool { pub unsafe fn unlock(&self) { c::ReleaseSRWLockExclusive(raw(self)); } - - #[inline] - pub unsafe fn destroy(&self) { - // SRWLock does not need to be destroyed. - } } diff --git a/library/std/src/sys/windows/locks/rwlock.rs b/library/std/src/sys/windows/locks/rwlock.rs index 12906652e0b..a32df85e2f6 100644 --- a/library/std/src/sys/windows/locks/rwlock.rs +++ b/library/std/src/sys/windows/locks/rwlock.rs @@ -38,9 +38,4 @@ pub unsafe fn read_unlock(&self) { pub unsafe fn write_unlock(&self) { c::ReleaseSRWLockExclusive(self.inner.get()) } - - #[inline] - pub unsafe fn destroy(&self) { - // ... - } } diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index 67d4b126209..1def0518e0a 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -15,9 +15,7 @@ pub struct Condvar { impl Condvar { /// Creates a new condition variable for use. pub fn new() -> Self { - let mut c = imp::MovableCondvar::from(imp::Condvar::new()); - unsafe { c.init() }; - Self { inner: c, check: CondvarCheck::new() } + Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() } } /// Signals one waiter on this condition variable to wake up. @@ -55,9 +53,3 @@ pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool { self.inner.wait_timeout(mutex.raw(), dur) } } - -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { self.inner.destroy() }; - } -} diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs index d0d0d596518..ce8f3670487 100644 --- a/library/std/src/sys_common/condvar/check.rs +++ b/library/std/src/sys_common/condvar/check.rs @@ -1,6 +1,7 @@ use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys::locks as imp; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::sys_common::mutex::MovableMutex; pub trait CondvarCheck { @@ -9,7 +10,7 @@ pub trait CondvarCheck { /// For boxed mutexes, a `Condvar` will check it's only ever used with the same /// mutex, based on its (stable) address. -impl CondvarCheck for Box { +impl CondvarCheck for LazyBox { type Check = SameMutexCheck; } diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs new file mode 100644 index 00000000000..647c13d2437 --- /dev/null +++ b/library/std/src/sys_common/lazy_box.rs @@ -0,0 +1,77 @@ +#![allow(dead_code)] // Only used on some platforms. + +// This is used to wrap pthread {Mutex, Condvar, RwLock} in. + +use crate::marker::PhantomData; +use crate::ops::{Deref, DerefMut}; +use crate::ptr::null_mut; +use crate::sync::atomic::{ + AtomicPtr, + Ordering::{AcqRel, Acquire}, +}; + +pub(crate) struct LazyBox { + ptr: AtomicPtr, + _phantom: PhantomData, +} + +pub(crate) trait LazyInit { + /// This is called before the box is allocated, to provide the value to + /// move into the new box. + /// + /// It might be called more than once per LazyBox, as multiple threads + /// might race to initialize it concurrently, each constructing and initializing + /// their own box. (All but one of them will be destroyed right after.) + fn init() -> Box; +} + +impl LazyBox { + #[inline] + pub const fn new() -> Self { + Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData } + } + + #[inline] + fn get_pointer(&self) -> *mut T { + let ptr = self.ptr.load(Acquire); + if ptr.is_null() { self.initialize() } else { ptr } + } + + #[cold] + fn initialize(&self) -> *mut T { + let new_ptr = Box::into_raw(T::init()); + match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { + Ok(_) => new_ptr, + Err(ptr) => { + // Lost the race to another thread. + // Drop the box we created, and use the one from the other thread instead. + drop(unsafe { Box::from_raw(new_ptr) }); + ptr + } + } + } +} + +impl Deref for LazyBox { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.get_pointer() } + } +} + +impl DerefMut for LazyBox { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.get_pointer() } + } +} + +impl Drop for LazyBox { + fn drop(&mut self) { + let ptr = *self.ptr.get_mut(); + if !ptr.is_null() { + drop(unsafe { Box::from_raw(ptr) }); + } + } +} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 804727fbc54..80f56bf7522 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -24,6 +24,7 @@ pub mod condvar; pub mod fs; pub mod io; +pub mod lazy_box; pub mod memchr; pub mod mutex; pub mod process; diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 12a09c98605..36ea888d8de 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -61,9 +61,7 @@ unsafe impl Sync for MovableMutex {} impl MovableMutex { /// Creates a new mutex. pub fn new() -> Self { - let mut mutex = imp::MovableMutex::from(imp::Mutex::new()); - unsafe { mutex.init() }; - Self(mutex) + Self(imp::MovableMutex::new()) } pub(super) fn raw(&self) -> &imp::Mutex { @@ -92,9 +90,3 @@ pub unsafe fn raw_unlock(&self) { self.0.unlock() } } - -impl Drop for MovableMutex { - fn drop(&mut self) { - unsafe { self.0.destroy() }; - } -} diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 8f252308de7..8921af311d4 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -168,13 +168,6 @@ unsafe fn increment_lock_count(&self) { } } -impl Drop for ReentrantMutex { - fn drop(&mut self) { - // Safety: We're the unique owner of this mutex and not going to use it afterwards. - unsafe { self.mutex.destroy() } - } -} - impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 12e7a72a344..abc9fd561f1 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -74,7 +74,7 @@ fn drop(&mut self) { impl MovableRwLock { /// Creates a new reader-writer lock for use. pub fn new() -> Self { - Self(imp::MovableRwLock::from(imp::RwLock::new())) + Self(imp::MovableRwLock::new()) } /// Acquires shared access to the underlying lock, blocking the current @@ -126,9 +126,3 @@ pub unsafe fn write_unlock(&self) { self.0.write_unlock() } } - -impl Drop for MovableRwLock { - fn drop(&mut self) { - unsafe { self.0.destroy() }; - } -}