From c2b430f6c5b5d27d860cd2f50ea9305d48607fba Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:58:53 -0400 Subject: [PATCH 1/7] Revert "link once_cell feature to #74465" This reverts commit fe639057086fa7bef1e964bf3a211517b04bc328. --- src/libcore/lazy.rs | 42 +++++++++++++++++----------------- src/libcore/lib.rs | 2 +- src/libstd/lazy.rs | 56 ++++++++++++++++++++++----------------------- src/libstd/lib.rs | 2 +- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs index 5cf7217ef11e8..e9af66ff64264 100644 --- a/src/libcore/lazy.rs +++ b/src/libcore/lazy.rs @@ -26,20 +26,20 @@ use crate::ops::Deref; /// assert_eq!(value, "Hello, World!"); /// assert!(cell.get().is_some()); /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub struct OnceCell { // Invariant: written to at most once. inner: UnsafeCell>, } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Default for OnceCell { fn default() -> Self { Self::new() } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl fmt::Debug for OnceCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { @@ -49,7 +49,7 @@ impl fmt::Debug for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Clone for OnceCell { fn clone(&self) -> OnceCell { let res = OnceCell::new(); @@ -63,17 +63,17 @@ impl Clone for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl PartialEq for OnceCell { fn eq(&self, other: &Self) -> bool { self.get() == other.get() } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Eq for OnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl From for OnceCell { fn from(value: T) -> Self { OnceCell { inner: UnsafeCell::new(Some(value)) } @@ -82,7 +82,7 @@ impl From for OnceCell { impl OnceCell { /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub const fn new() -> OnceCell { OnceCell { inner: UnsafeCell::new(None) } } @@ -90,7 +90,7 @@ impl OnceCell { /// Gets the reference to the underlying value. /// /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get(&self) -> Option<&T> { // Safety: Safe due to `inner`'s invariant unsafe { &*self.inner.get() }.as_ref() @@ -99,7 +99,7 @@ impl OnceCell { /// Gets the mutable reference to the underlying value. /// /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_mut(&mut self) -> Option<&mut T> { // Safety: Safe because we have unique access unsafe { &mut *self.inner.get() }.as_mut() @@ -127,7 +127,7 @@ impl OnceCell { /// /// assert!(cell.get().is_some()); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn set(&self, value: T) -> Result<(), T> { // Safety: Safe because we cannot have overlapping mutable borrows let slot = unsafe { &*self.inner.get() }; @@ -168,7 +168,7 @@ impl OnceCell { /// let value = cell.get_or_init(|| unreachable!()); /// assert_eq!(value, &92); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -206,7 +206,7 @@ impl OnceCell { /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, @@ -241,7 +241,7 @@ impl OnceCell { /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option`. @@ -269,7 +269,7 @@ impl OnceCell { /// assert_eq!(cell.take(), Some("hello".to_string())); /// assert_eq!(cell.get(), None); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn take(&mut self) -> Option { mem::take(self).into_inner() } @@ -298,13 +298,13 @@ impl OnceCell { /// // 92 /// // 92 /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub struct Lazy T> { cell: OnceCell, init: Cell>, } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl fmt::Debug for Lazy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() @@ -329,7 +329,7 @@ impl Lazy { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// # } /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub const fn new(init: F) -> Lazy { Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } } @@ -353,7 +353,7 @@ impl T> Lazy { /// assert_eq!(Lazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn force(this: &Lazy) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), @@ -362,7 +362,7 @@ impl T> Lazy { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl T> Deref for Lazy { type Target = T; fn deref(&self) -> &T { @@ -370,7 +370,7 @@ impl T> Deref for Lazy { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Default for Lazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> Lazy { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2e443064706d2..4701503d4103e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -240,7 +240,7 @@ pub mod char; pub mod ffi; #[cfg(not(test))] // See #65860 pub mod iter; -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub mod lazy; pub mod option; pub mod panic; diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index 86e1cfae582e8..094eff17f8916 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -10,7 +10,7 @@ use crate::{ }; #[doc(inline)] -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub use core::lazy::*; /// A synchronization primitive which can be written to only once. @@ -38,7 +38,7 @@ pub use core::lazy::*; /// assert!(value.is_some()); /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub struct SyncOnceCell { once: Once, // Whether or not the value is initialized is tracked by `state_and_queue`. @@ -50,24 +50,24 @@ pub struct SyncOnceCell { // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Sync for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Send for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl RefUnwindSafe for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl UnwindSafe for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Default for SyncOnceCell { fn default() -> SyncOnceCell { SyncOnceCell::new() } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl fmt::Debug for SyncOnceCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { @@ -77,7 +77,7 @@ impl fmt::Debug for SyncOnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Clone for SyncOnceCell { fn clone(&self) -> SyncOnceCell { let cell = Self::new(); @@ -91,7 +91,7 @@ impl Clone for SyncOnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl From for SyncOnceCell { fn from(value: T) -> Self { let cell = Self::new(); @@ -102,19 +102,19 @@ impl From for SyncOnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl PartialEq for SyncOnceCell { fn eq(&self, other: &SyncOnceCell) -> bool { self.get() == other.get() } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Eq for SyncOnceCell {} impl SyncOnceCell { /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub const fn new() -> SyncOnceCell { SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) } } @@ -123,7 +123,7 @@ impl SyncOnceCell { /// /// Returns `None` if the cell is empty, or being initialized. This /// method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get(&self) -> Option<&T> { if self.is_initialized() { // Safe b/c checked is_initialized @@ -136,7 +136,7 @@ impl SyncOnceCell { /// Gets the mutable reference to the underlying value. /// /// Returns `None` if the cell is empty. This method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_mut(&mut self) -> Option<&mut T> { if self.is_initialized() { // Safe b/c checked is_initialized and we have a unique access @@ -170,7 +170,7 @@ impl SyncOnceCell { /// assert_eq!(CELL.get(), Some(&92)); /// } /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn set(&self, value: T) -> Result<(), T> { let mut value = Some(value); self.get_or_init(|| value.take().unwrap()); @@ -209,7 +209,7 @@ impl SyncOnceCell { /// let value = cell.get_or_init(|| unreachable!()); /// assert_eq!(value, &92); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -248,7 +248,7 @@ impl SyncOnceCell { /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, @@ -286,7 +286,7 @@ impl SyncOnceCell { /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn into_inner(mut self) -> Option { // Safety: Safe because we immediately free `self` without dropping let inner = unsafe { self.take_inner() }; @@ -318,7 +318,7 @@ impl SyncOnceCell { /// assert_eq!(cell.take(), Some("hello".to_string())); /// assert_eq!(cell.get(), None); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn take(&mut self) -> Option { mem::take(self).into_inner() } @@ -428,13 +428,13 @@ impl Drop for SyncOnceCell { /// // Some("Hoyten") /// } /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub struct SyncLazy T> { cell: SyncOnceCell, init: Cell>, } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl fmt::Debug for SyncLazy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() @@ -446,17 +446,17 @@ impl fmt::Debug for SyncLazy { // we do create a `&mut Option` in `force`, but this is // properly synchronized, so it only happens once // so it also does not contribute to this impl. -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Sync for SyncLazy where SyncOnceCell: Sync {} // auto-derived `Send` impl is OK. -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl RefUnwindSafe for SyncLazy where SyncOnceCell: RefUnwindSafe {} impl SyncLazy { /// Creates a new lazy value with the given initializing /// function. - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub const fn new(f: F) -> SyncLazy { SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } } @@ -479,7 +479,7 @@ impl T> SyncLazy { /// assert_eq!(SyncLazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell", issue = "68198")] pub fn force(this: &SyncLazy) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), @@ -488,7 +488,7 @@ impl T> SyncLazy { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl T> Deref for SyncLazy { type Target = T; fn deref(&self) -> &T { @@ -496,7 +496,7 @@ impl T> Deref for SyncLazy { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] impl Default for SyncLazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> SyncLazy { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 00f2fff94c9a1..21978f0d936f4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -477,7 +477,7 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "once_cell", issue = "68198")] pub mod lazy; #[stable(feature = "futures_api", since = "1.36.0")] From 2d907bb619f6d3a667434cf0e2eaa0283af0458b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:10 -0400 Subject: [PATCH 2/7] Revert "include changes to Cargo.lock" This reverts commit 48844fed2bdc7c40d213131d5e13ab28e47df083. --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8f110403eb842..9b5b6620f79a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1372,8 +1372,8 @@ checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" name = "installer" version = "0.0.0" dependencies = [ - "anyhow", "clap", + "failure", "flate2", "lazy_static", "num_cpus", From fd694bb77b563a1a777897ec46229b018e21aa37 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:11 -0400 Subject: [PATCH 3/7] Revert "appease tidy" This reverts commit 1f1cda65d9a5c88855d3fbcb3912095474e557de. --- src/libstd/lazy.rs | 5 ++++- src/libstd/sync/once.rs | 5 +---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index 094eff17f8916..761cc2b439f67 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -116,7 +116,10 @@ impl SyncOnceCell { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "68198")] pub const fn new() -> SyncOnceCell { - SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) } + SyncOnceCell { + once: Once::new(), + value: UnsafeCell::new(MaybeUninit::uninit()), + } } /// Gets the reference to the underlying value. diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 64260990824b8..1fce5dc035224 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -414,10 +414,7 @@ impl Once { }; // Run the initialization function, letting it know if we're // poisoned or not. - let init_state = OnceState { - poisoned: state_and_queue == POISONED, - set_state_on_drop_to: Cell::new(COMPLETE), - }; + let init_state = OnceState { poisoned: state_and_queue == POISONED, set_state_on_drop_to: Cell::new(COMPLETE) }; init(&init_state); waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get(); break; From f9febd507819be60c365d7f3ccd55809309387b3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:13 -0400 Subject: [PATCH 4/7] Revert "remove inlined lazy::Waiter in favor of sync::Once" This reverts commit d1017940d77f35f841008c3e108e3da5e48a592f. --- src/libstd/lazy.rs | 140 +++++++++++++++++++++++++++++++++++----- src/libstd/sync/once.rs | 18 ++---- 2 files changed, 129 insertions(+), 29 deletions(-) diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index 761cc2b439f67..aed91df47449f 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -3,10 +3,12 @@ use crate::{ cell::{Cell, UnsafeCell}, fmt, + marker::PhantomData, mem::{self, MaybeUninit}, ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, - sync::Once, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, + thread::{self, Thread}, }; #[doc(inline)] @@ -40,7 +42,10 @@ pub use core::lazy::*; /// ``` #[unstable(feature = "once_cell", issue = "68198")] pub struct SyncOnceCell { - once: Once, + // This `state` word is actually an encoded version of just a pointer to a + // `Waiter`, so we add the `PhantomData` appropriately. + state_and_queue: AtomicUsize, + _marker: PhantomData<*mut Waiter>, // Whether or not the value is initialized is tracked by `state_and_queue`. value: UnsafeCell>, } @@ -117,7 +122,8 @@ impl SyncOnceCell { #[unstable(feature = "once_cell", issue = "68198")] pub const fn new() -> SyncOnceCell { SyncOnceCell { - once: Once::new(), + state_and_queue: AtomicUsize::new(INCOMPLETE), + _marker: PhantomData, value: UnsafeCell::new(MaybeUninit::uninit()), } } @@ -129,7 +135,7 @@ impl SyncOnceCell { #[unstable(feature = "once_cell", issue = "68198")] pub fn get(&self) -> Option<&T> { if self.is_initialized() { - // Safe b/c checked is_initialized + // Safe b/c checked is_initialize Some(unsafe { self.get_unchecked() }) } else { None @@ -142,7 +148,7 @@ impl SyncOnceCell { #[unstable(feature = "once_cell", issue = "68198")] pub fn get_mut(&mut self) -> Option<&mut T> { if self.is_initialized() { - // Safe b/c checked is_initialized and we have a unique access + // Safe b/c checked is_initialize and we have a unique access Some(unsafe { self.get_unchecked_mut() }) } else { None @@ -344,32 +350,37 @@ impl SyncOnceCell { } } + /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). #[inline] fn is_initialized(&self) -> bool { - self.once.is_completed() + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us, and, this being a fast path, weaker + // ordering helps with performance. This `Acquire` synchronizes with + // `SeqCst` operations on the slow path. + self.state_and_queue.load(Ordering::Acquire) == COMPLETE } + /// Safety: synchronizes with store to value via SeqCst read from state, + /// writes value only once because we never get to INCOMPLETE state after a + /// successful write. #[cold] fn initialize(&self, f: F) -> Result<(), E> where F: FnOnce() -> Result, { + let mut f = Some(f); let mut res: Result<(), E> = Ok(()); 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(|p| { + initialize_inner(&self.state_and_queue, &mut || { + let f = f.take().unwrap(); match f() { Ok(value) => { unsafe { (&mut *slot.get()).write(value) }; + true } Err(e) => { res = Err(e); - - // Treat the underlying `Once` as poisoned since we - // failed to initialize our value. Calls - p.poison(); + false } } }); @@ -396,6 +407,106 @@ impl Drop for SyncOnceCell { } } +const INCOMPLETE: usize = 0x0; +const RUNNING: usize = 0x1; +const COMPLETE: usize = 0x2; + +const STATE_MASK: usize = 0x3; + +// The alignment here is so that we can stash the state in the lower +// bits of the `next` pointer +#[repr(align(4))] +struct Waiter { + thread: Cell>, + signaled: AtomicBool, + next: *const Waiter, +} + +struct WaiterQueue<'a> { + state_and_queue: &'a AtomicUsize, + set_state_on_drop_to: usize, +} + +impl Drop for WaiterQueue<'_> { + fn drop(&mut self) { + let state_and_queue = + self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel); + + assert_eq!(state_and_queue & STATE_MASK, RUNNING); + + unsafe { + let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter; + while !queue.is_null() { + let next = (*queue).next; + let thread = (*queue).thread.replace(None).unwrap(); + (*queue).signaled.store(true, Ordering::Release); + queue = next; + thread.unpark(); + } + } + } +} + +fn initialize_inner(my_state_and_queue: &AtomicUsize, init: &mut dyn FnMut() -> bool) -> bool { + let mut state_and_queue = my_state_and_queue.load(Ordering::Acquire); + + loop { + match state_and_queue { + COMPLETE => return true, + INCOMPLETE => { + let old = my_state_and_queue.compare_and_swap( + state_and_queue, + RUNNING, + Ordering::Acquire, + ); + if old != state_and_queue { + state_and_queue = old; + continue; + } + let mut waiter_queue = WaiterQueue { + state_and_queue: my_state_and_queue, + set_state_on_drop_to: INCOMPLETE, + }; + let success = init(); + + waiter_queue.set_state_on_drop_to = if success { COMPLETE } else { INCOMPLETE }; + return success; + } + _ => { + assert!(state_and_queue & STATE_MASK == RUNNING); + wait(&my_state_and_queue, state_and_queue); + state_and_queue = my_state_and_queue.load(Ordering::Acquire); + } + } + } +} + +fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { + loop { + if current_state & STATE_MASK != RUNNING { + return; + } + + let node = Waiter { + thread: Cell::new(Some(thread::current())), + signaled: AtomicBool::new(false), + next: (current_state & !STATE_MASK) as *const Waiter, + }; + let me = &node as *const Waiter as usize; + + let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release); + if old != current_state { + current_state = old; + continue; + } + + while !node.signaled.load(Ordering::Acquire) { + thread::park(); + } + break; + } +} + /// A value which is initialized on the first access. /// /// This type is a thread-safe `Lazy`, and can be used in statics. @@ -652,7 +763,6 @@ mod tests { let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); assert!(res.is_err()); - assert!(!cell.is_initialized()); assert!(cell.get().is_none()); assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 1fce5dc035224..7dc822db3d027 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -132,7 +132,6 @@ unsafe impl Send for Once {} #[derive(Debug)] pub struct OnceState { poisoned: bool, - set_state_on_drop_to: Cell, } /// Initialization value for static [`Once`] values. @@ -322,7 +321,7 @@ impl Once { } let mut f = Some(f); - self.call_inner(true, &mut |p| f.take().unwrap()(p)); + self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p })); } /// Returns `true` if some `call_once` call has completed @@ -386,7 +385,7 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] - fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) { + fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) { let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire); loop { match state_and_queue { @@ -414,9 +413,8 @@ impl Once { }; // Run the initialization function, letting it know if we're // poisoned or not. - let init_state = OnceState { poisoned: state_and_queue == POISONED, set_state_on_drop_to: Cell::new(COMPLETE) }; - init(&init_state); - waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get(); + init(state_and_queue == POISONED); + waiter_queue.set_state_on_drop_to = COMPLETE; break; } _ => { @@ -556,14 +554,6 @@ impl OnceState { pub fn poisoned(&self) -> bool { self.poisoned } - - /// Poison the associated [`Once`] without explicitly panicking. - /// - /// [`Once`]: struct.Once.html - // NOTE: This is currently only exposed for the `lazy` module - pub(crate) fn poison(&self) { - self.set_state_on_drop_to.set(POISONED); - } } #[cfg(all(test, not(target_os = "emscripten")))] From fffb1bdc6b4b1d6ab181dce5024a29e261f61299 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:14 -0400 Subject: [PATCH 5/7] Revert "use set() in SyncOnceCell::from" This reverts commit d1263f5e66d31ad170c524a70aa5f21e08474326. --- src/libstd/lazy.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index aed91df47449f..c7553caa4c056 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -85,14 +85,14 @@ impl fmt::Debug for SyncOnceCell { #[unstable(feature = "once_cell", issue = "68198")] impl Clone for SyncOnceCell { fn clone(&self) -> SyncOnceCell { - let cell = Self::new(); + let res = SyncOnceCell::new(); if let Some(value) = self.get() { - match cell.set(value.clone()) { + match res.set(value.clone()) { Ok(()) => (), Err(_) => unreachable!(), } } - cell + res } } @@ -100,10 +100,8 @@ impl Clone for SyncOnceCell { impl From for SyncOnceCell { fn from(value: T) -> Self { let cell = Self::new(); - match cell.set(value) { - Ok(()) => cell, - Err(_) => unreachable!(), - } + cell.get_or_init(|| value); + cell } } @@ -157,7 +155,8 @@ impl SyncOnceCell { /// Sets the contents of this cell to `value`. /// - /// Returns `Ok(())` if the cell's value was updated. + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. /// /// # Examples /// @@ -263,10 +262,8 @@ impl SyncOnceCell { F: FnOnce() -> Result, { // Fast path check - // NOTE: We need to perform an acquire on the state in this method - // in order to correctly synchronize `SyncLazy::force`. This is - // currently done by calling `self.get()`, which in turn calls - // `self.is_initialized()`, which in turn performs the acquire. + // NOTE: This acquire here is important to ensure + // `SyncLazy::force` is correctly synchronized if let Some(value) = self.get() { return Ok(value); } @@ -413,8 +410,6 @@ const COMPLETE: usize = 0x2; const STATE_MASK: usize = 0x3; -// The alignment here is so that we can stash the state in the lower -// bits of the `next` pointer #[repr(align(4))] struct Waiter { thread: Cell>, From 57ebee9b7f0205b2639eb5b1c04b2be0a5d244ac Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:15 -0400 Subject: [PATCH 6/7] Revert "integrate Lazy into std layout" This reverts commit 237a97760ad79a21ce0655b9f5adc0cc5b5cbc79. --- Cargo.lock | 2 +- src/libcore/lazy.rs | 379 -------------- src/libcore/lib.rs | 2 - src/libcore/tests/lazy.rs | 124 ----- src/libcore/tests/lib.rs | 2 - src/libstd/lazy.rs | 1032 +++++++++++++++++++------------------ src/libstd/lib.rs | 7 +- 7 files changed, 546 insertions(+), 1002 deletions(-) delete mode 100644 src/libcore/lazy.rs delete mode 100644 src/libcore/tests/lazy.rs diff --git a/Cargo.lock b/Cargo.lock index 9b5b6620f79a7..8f110403eb842 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1372,8 +1372,8 @@ checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" name = "installer" version = "0.0.0" dependencies = [ + "anyhow", "clap", - "failure", "flate2", "lazy_static", "num_cpus", diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs deleted file mode 100644 index e9af66ff64264..0000000000000 --- a/src/libcore/lazy.rs +++ /dev/null @@ -1,379 +0,0 @@ -//! Lazy values and one-time initialization of static data. - -use crate::cell::{Cell, UnsafeCell}; -use crate::fmt; -use crate::mem; -use crate::ops::Deref; - -/// A cell which can be written to only once. -/// -/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. -/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::OnceCell; -/// -/// let cell = OnceCell::new(); -/// assert!(cell.get().is_none()); -/// -/// let value: &String = cell.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// assert!(cell.get().is_some()); -/// ``` -#[unstable(feature = "once_cell", issue = "68198")] -pub struct OnceCell { - // Invariant: written to at most once. - inner: UnsafeCell>, -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl Default for OnceCell { - fn default() -> Self { - Self::new() - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl fmt::Debug for OnceCell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("OnceCell").field(v).finish(), - None => f.write_str("OnceCell(Uninit)"), - } - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl Clone for OnceCell { - fn clone(&self) -> OnceCell { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl PartialEq for OnceCell { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl Eq for OnceCell {} - -#[unstable(feature = "once_cell", issue = "68198")] -impl From for OnceCell { - fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } - } -} - -impl OnceCell { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new() -> OnceCell { - OnceCell { inner: UnsafeCell::new(None) } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get(&self) -> Option<&T> { - // Safety: Safe due to `inner`'s invariant - unsafe { &*self.inner.get() }.as_ref() - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get_mut(&mut self) -> Option<&mut T> { - // Safety: Safe because we have unique access - unsafe { &mut *self.inner.get() }.as_mut() - } - - /// Sets the contents of the cell to `value`. - /// - /// # Errors - /// - /// This method returns `Ok(())` if the cell was empty and `Err(value)` if - /// it was full. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert!(cell.get().is_none()); - /// - /// assert_eq!(cell.set(92), Ok(())); - /// assert_eq!(cell.set(62), Err(62)); - /// - /// assert!(cell.get().is_some()); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn set(&self, value: T) -> Result<(), T> { - // Safety: Safe because we cannot have overlapping mutable borrows - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - - // Safety: This is the only place where we set the slot, no races - // due to reentrancy/concurrency are possible, and we've - // checked that slot is currently `None`, so this write - // maintains the `inner`'s invariant. - let slot = unsafe { &mut *self.inner.get() }; - *slot = Some(value); - Ok(()) - } - - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get_or_init(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::(f())) { - Ok(val) => val, - } - } - - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result { - /// Ok(92) - /// }); - /// assert_eq!(value, Ok(&92)); - /// assert_eq!(cell.get(), Some(&92)) - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn get_or_try_init(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result, - { - if let Some(val) = self.get() { - return Ok(val); - } - let val = f()?; - // Note that *some* forms of reentrant initialization might lead to - // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems - // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) - } - - /// Consumes the cell, returning the wrapped value. - /// - /// Returns `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell: OnceCell = OnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn into_inner(self) -> Option { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option`. - self.inner.into_inner() - } - - /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. - /// - /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. - /// - /// Safety is guaranteed by requiring a mutable reference. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let mut cell: OnceCell = OnceCell::new(); - /// assert_eq!(cell.take(), None); - /// - /// let mut cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.take(), Some("hello".to_string())); - /// assert_eq!(cell.get(), None); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn take(&mut self) -> Option { - mem::take(self).into_inner() - } -} - -/// A value which is initialized on the first access. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::Lazy; -/// -/// let lazy: Lazy = Lazy::new(|| { -/// println!("initializing"); -/// 92 -/// }); -/// println!("ready"); -/// println!("{}", *lazy); -/// println!("{}", *lazy); -/// -/// // Prints: -/// // ready -/// // initializing -/// // 92 -/// // 92 -/// ``` -#[unstable(feature = "once_cell", issue = "68198")] -pub struct Lazy T> { - cell: OnceCell, - init: Cell>, -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl fmt::Debug for Lazy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() - } -} - -impl Lazy { - /// Creates a new lazy value with the given initializing function. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// # fn main() { - /// use std::lazy::Lazy; - /// - /// let hello = "Hello, World!".to_string(); - /// - /// let lazy = Lazy::new(|| hello.to_uppercase()); - /// - /// assert_eq!(&*lazy, "HELLO, WORLD!"); - /// # } - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub const fn new(init: F) -> Lazy { - Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } - } -} - -impl T> Lazy { - /// Forces the evaluation of this lazy value and returns a reference to - /// the result. - /// - /// This is equivalent to the `Deref` impl, but is explicit. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::Lazy; - /// - /// let lazy = Lazy::new(|| 92); - /// - /// assert_eq!(Lazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn force(this: &Lazy) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("`Lazy` instance has previously been poisoned"), - }) - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl T> Deref for Lazy { - type Target = T; - fn deref(&self) -> &T { - Lazy::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "68198")] -impl Default for Lazy { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> Lazy { - Lazy::new(T::default) - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4701503d4103e..8bf98b50acfed 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -240,8 +240,6 @@ pub mod char; pub mod ffi; #[cfg(not(test))] // See #65860 pub mod iter; -#[unstable(feature = "once_cell", issue = "68198")] -pub mod lazy; pub mod option; pub mod panic; pub mod panicking; diff --git a/src/libcore/tests/lazy.rs b/src/libcore/tests/lazy.rs deleted file mode 100644 index 1c0bddb9aef62..0000000000000 --- a/src/libcore/tests/lazy.rs +++ /dev/null @@ -1,124 +0,0 @@ -use core::{ - cell::Cell, - lazy::{Lazy, OnceCell}, - sync::atomic::{AtomicUsize, Ordering::SeqCst}, -}; - -#[test] -fn once_cell() { - let c = OnceCell::new(); - assert!(c.get().is_none()); - c.get_or_init(|| 92); - assert_eq!(c.get(), Some(&92)); - - c.get_or_init(|| panic!("Kabom!")); - assert_eq!(c.get(), Some(&92)); -} - -#[test] -fn once_cell_get_mut() { - let mut c = OnceCell::new(); - assert!(c.get_mut().is_none()); - c.set(90).unwrap(); - *c.get_mut().unwrap() += 2; - assert_eq!(c.get_mut(), Some(&mut 92)); -} - -#[test] -fn once_cell_drop() { - static DROP_CNT: AtomicUsize = AtomicUsize::new(0); - struct Dropper; - impl Drop for Dropper { - fn drop(&mut self) { - DROP_CNT.fetch_add(1, SeqCst); - } - } - - let x = OnceCell::new(); - x.get_or_init(|| Dropper); - assert_eq!(DROP_CNT.load(SeqCst), 0); - drop(x); - assert_eq!(DROP_CNT.load(SeqCst), 1); -} - -#[test] -fn unsync_once_cell_drop_empty() { - let x = OnceCell::<&'static str>::new(); - drop(x); -} - -#[test] -fn clone() { - let s = OnceCell::new(); - let c = s.clone(); - assert!(c.get().is_none()); - - s.set("hello").unwrap(); - let c = s.clone(); - assert_eq!(c.get().map(|c| *c), Some("hello")); -} - -#[test] -fn from_impl() { - assert_eq!(OnceCell::from("value").get(), Some(&"value")); - assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); -} - -#[test] -fn partialeq_impl() { - assert!(OnceCell::from("value") == OnceCell::from("value")); - assert!(OnceCell::from("foo") != OnceCell::from("bar")); - - assert!(OnceCell::<&'static str>::new() == OnceCell::new()); - assert!(OnceCell::<&'static str>::new() != OnceCell::from("value")); -} - -#[test] -fn into_inner() { - let cell: OnceCell<&'static str> = OnceCell::new(); - assert_eq!(cell.into_inner(), None); - let cell = OnceCell::new(); - cell.set("hello").unwrap(); - assert_eq!(cell.into_inner(), Some("hello")); -} - -#[test] -fn lazy_new() { - let called = Cell::new(0); - let x = Lazy::new(|| { - called.set(called.get() + 1); - 92 - }); - - assert_eq!(called.get(), 0); - - let y = *x - 30; - assert_eq!(y, 62); - assert_eq!(called.get(), 1); - - let y = *x - 30; - assert_eq!(y, 62); - assert_eq!(called.get(), 1); -} - -#[test] -fn aliasing_in_get() { - let x = OnceCell::new(); - x.set(42).unwrap(); - let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ - let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | - println!("{}", at_x); // <------- up until here ---------------------------+ -} - -#[test] -#[should_panic(expected = "reentrant init")] -fn reentrant_init() { - let x: OnceCell> = OnceCell::new(); - let dangling_ref: Cell> = Cell::new(None); - x.get_or_init(|| { - let r = x.get_or_init(|| Box::new(92)); - dangling_ref.set(Some(r)); - Box::new(62) - }); - eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); -} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 47ed6db6c677b..090ce47174566 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -43,7 +43,6 @@ #![feature(option_unwrap_none)] #![feature(peekable_next_if)] #![feature(partition_point)] -#![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)] @@ -63,7 +62,6 @@ mod fmt; mod hash; mod intrinsics; mod iter; -mod lazy; mod manually_drop; mod mem; mod nonzero; diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs index c7553caa4c056..bcac2dc311aff 100644 --- a/src/libstd/lazy.rs +++ b/src/libstd/lazy.rs @@ -1,32 +1,508 @@ -//! Lazy values and one-time initialization of static data. +//! `lazy` modules provides lazy values and one-time initialization of static data. +//! +//! `lazy` provides two new cell-like types, `OnceCell` and `SyncOnceCell`. `OnceCell` +//! might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access +//! to the stored contents. In a nutshell, API looks *roughly* like this: +//! +//! ```rust,ignore +//! impl OnceCell { +//! fn new() -> OnceCell { ... } +//! fn set(&self, value: T) -> Result<(), T> { ... } +//! fn get(&self) -> Option<&T> { ... } +//! } +//! ``` +//! +//! Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. +//! Because of the single assignment restriction `get` can return an `&T` instead of `Ref` +//! or `MutexGuard`. +//! +//! The `SyncOnceCell` flavor is thread-safe (that is, implements [`Sync`]) trait, while `OnceCell` one is not. +//! +//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! +//! # Patterns +//! +//! `OnceCell` might be useful for a variety of patterns. +//! +//! ## Safe Initialization of global data +//! +//! ```rust +//! use std::{env, io}; +//! use std::lazy::SyncOnceCell; +//! +//! #[derive(Debug)] +//! pub struct Logger { +//! // ... +//! } +//! static INSTANCE: OnceCell = OnceCell::new(); +//! +//! impl Logger { +//! pub fn global() -> &'static Logger { +//! INSTANCE.get().expect("logger is not initialized") +//! } +//! +//! fn from_cli(args: env::Args) -> Result { +//! // ... +//! # Ok(Logger {}) +//! } +//! } +//! +//! fn main() { +//! let logger = Logger::from_cli(env::args()).unwrap(); +//! INSTANCE.set(logger).unwrap(); +//! // use `Logger::global()` from now on +//! } +//! ``` +//! +//! ## Lazy initialized global data +//! +//! This is essentially `lazy_static!` macro, but without a macro. +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! use lazy::SyncOnceCell; +//! +//! fn global_data() -> &'static Mutex> { +//! static INSTANCE: OnceCell>> = OnceCell::new(); +//! INSTANCE.get_or_init(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }) +//! } +//! ``` +//! +//! There are also `sync::Lazy` and `unsync::Lazy` convenience types to streamline this pattern: +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! use lazy::SyncLazy; +//! +//! static GLOBAL_DATA: Lazy>> = Lazy::new(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }); +//! +//! fn main() { +//! println!("{:?}", GLOBAL_DATA.lock().unwrap()); +//! } +//! ``` +//! +//! ## General purpose lazy evaluation +//! +//! `Lazy` also works with local variables. +//! +//! ```rust +//! use std::lazy::Lazy; +//! +//! fn main() { +//! let ctx = vec![1, 2, 3]; +//! let thunk = Lazy::new(|| { +//! ctx.iter().sum::() +//! }); +//! assert_eq!(*thunk, 6); +//! } +//! ``` +//! +//! If you need a lazy field in a struct, you probably should use `OnceCell` +//! directly, because that will allow you to access `self` during initialization. +//! +//! ```rust +//! use std::{fs, path::PathBuf}; +//! +//! use std::lazy::OnceCell; +//! +//! struct Ctx { +//! config_path: PathBuf, +//! config: OnceCell, +//! } +//! +//! impl Ctx { +//! pub fn get_config(&self) -> Result<&str, std::io::Error> { +//! let cfg = self.config.get_or_try_init(|| { +//! fs::read_to_string(&self.config_path) +//! })?; +//! Ok(cfg.as_str()) +//! } +//! } +//! ``` +//! +//! ## Building block +//! +//! Naturally, it is possible to build other abstractions on top of `OnceCell`. +//! For example, this is a `regex!` macro which takes a string literal and returns an +//! *expression* that evaluates to a `&'static Regex`: +//! +//! ``` +//! macro_rules! regex { +//! ($re:literal $(,)?) => {{ +//! static RE: std::lazy::SyncOnceCell = std::lazy::SyncOnceCell::new(); +//! RE.get_or_init(|| regex::Regex::new($re).unwrap()) +//! }}; +//! } +//! ``` +//! +//! This macro can be useful to avoid "compile regex on every loop iteration" problem. +//! +//! # Comparison with other interior mutatbility types +//! +//! |`!Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`Cell` | `T` | requires `T: Copy` for `get` | +//! |`RefCell` | `RefMut` / `Ref` | may panic at runtime | +//! |`OnceCell` | `&T` | assignable only once | +//! +//! |`Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`AtomicT` | `T` | works only with certain `Copy` types | +//! |`Mutex` | `MutexGuard` | may deadlock at runtime, may block the thread | +//! |`SyncOnceCell` | `&T` | assignable only once, may block the thread | +//! +//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls +//! itself. However, because the assignment can happen only once, such cases should be more rare than +//! equivalents with `RefCell` and `Mutex`. use crate::{ cell::{Cell, UnsafeCell}, fmt, + hint::unreachable_unchecked, marker::PhantomData, - mem::{self, MaybeUninit}, - ops::{Deref, Drop}, + ops::Deref, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicBool, AtomicUsize, Ordering}, thread::{self, Thread}, }; -#[doc(inline)] -#[unstable(feature = "once_cell", issue = "68198")] -pub use core::lazy::*; +/// A cell which can be written to only once. Not thread safe. +/// +/// Unlike `:td::cell::RefCell`, a `OnceCell` provides simple `&` +/// references to the contents. +/// +/// # Example +/// ``` +/// use std::lazy::OnceCell; +/// +/// let cell = OnceCell::new(); +/// assert!(cell.get().is_none()); +/// +/// let value: &String = cell.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// assert!(cell.get().is_some()); +/// ``` +pub struct OnceCell { + // Invariant: written to at most once. + inner: UnsafeCell>, +} + +// Similarly to a `Sync` bound on `SyncOnceCell`, we can use +// `&OnceCell` to sneak a `T` through `catch_unwind`, +// by initializing the cell in closure and extracting the value in the +// `Drop`. +#[cfg(feature = "std")] +impl RefUnwindSafe for OnceCell {} +#[cfg(feature = "std")] +impl UnwindSafe for OnceCell {} + +impl Default for OnceCell { + fn default() -> Self { + Self::new() + } +} + +impl fmt::Debug for OnceCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } +} + +impl Clone for OnceCell { + fn clone(&self) -> OnceCell { + let res = OnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +impl PartialEq for OnceCell { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +impl Eq for OnceCell {} + +impl From for OnceCell { + fn from(value: T) -> Self { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } +} + +impl OnceCell { + /// Creates a new empty cell. + pub const fn new() -> OnceCell { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + pub fn get(&self) -> Option<&T> { + // Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safe because we have unique access + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + pub fn set(&self, value: T) -> Result<(), T> { + let slot = unsafe { &*self.inner.get() }; + if slot.is_some() { + return Err(value); + } + let slot = unsafe { &mut *self.inner.get() }; + // This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + *slot = Some(value); + Ok(()) + } -/// A synchronization primitive which can be written to only once. + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + match self.get_or_try_init(|| Ok::(f())) { + Ok(val) => val, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result { + /// Ok(92) + /// }); + /// assert_eq!(value, Ok(&92)); + /// assert_eq!(cell.get(), Some(&92)) + /// ``` + pub fn get_or_try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, + { + if let Some(val) = self.get() { + return Ok(val); + } + let val = f()?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(self.get().unwrap()) + } + + /// Consumes the `OnceCell`, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// use std::lazy::OnceCell; + /// + /// let cell: OnceCell = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + pub fn into_inner(self) -> Option { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option`. + self.inner.into_inner() + } +} + +/// A value which is initialized on the first access. /// -/// This type is a thread-safe `OnceCell`. +/// # Example +/// ``` +/// use std::lazy::Lazy; /// -/// # Examples +/// let lazy: Lazy = Lazy::new(|| { +/// println!("initializing"); +/// 92 +/// }); +/// println!("ready"); +/// println!("{}", *lazy); +/// println!("{}", *lazy); /// +/// // Prints: +/// // ready +/// // initializing +/// // 92 +/// // 92 /// ``` -/// #![feature(once_cell)] +pub struct Lazy T> { + cell: OnceCell, + init: Cell>, +} + +#[cfg(feature = "std")] +impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} + +impl fmt::Debug for Lazy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } +} + +impl Lazy { + /// Creates a new lazy value with the given initializing function. + /// + /// # Example + /// ``` + /// # fn main() { + /// use std::lazy::Lazy; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = Lazy::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// # } + /// ``` + pub const fn new(init: F) -> Lazy { + Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } +} + +impl T> Lazy { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Example + /// ``` + /// use std::lazy::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + pub fn force(this: &Lazy) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } +} + +impl T> Deref for Lazy { + type Target = T; + fn deref(&self) -> &T { + Lazy::force(self) + } +} + +impl Default for Lazy { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> Lazy { + Lazy::new(T::default) + } +} + +/// A thread-safe cell which can be written to only once. /// +/// `OnceCell` provides `&` references to the contents without RAII guards. +/// +/// Reading a non-`None` value out of `OnceCell` establishes a +/// happens-before relationship with a corresponding write. For example, if +/// thread A initializes the cell with `get_or_init(f)`, and thread B +/// subsequently reads the result of this call, B also observes all the side +/// effects of `f`. +/// +/// # Example +/// ``` /// use std::lazy::SyncOnceCell; /// -/// static CELL: SyncOnceCell = SyncOnceCell::new(); +/// static CELL: OnceCell = OnceCell::new(); /// assert!(CELL.get().is_none()); /// /// std::thread::spawn(|| { @@ -40,49 +516,44 @@ pub use core::lazy::*; /// assert!(value.is_some()); /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); /// ``` -#[unstable(feature = "once_cell", issue = "68198")] pub struct SyncOnceCell { // This `state` word is actually an encoded version of just a pointer to a // `Waiter`, so we add the `PhantomData` appropriately. state_and_queue: AtomicUsize, _marker: PhantomData<*mut Waiter>, - // Whether or not the value is initialized is tracked by `state_and_queue`. - value: UnsafeCell>, + // FIXME: switch to `std::mem::MaybeUninit` once we are ready to bump MSRV + // that far. It was stabilized in 1.36.0, so, if you are reading this and + // it's higher than 1.46.0 outside, please send a PR! ;) (and do the same + // for `Lazy`, while we are at it). + pub(crate) value: UnsafeCell>, } // Why do we need `T: Send`? -// Thread A creates a `SyncOnceCell` and shares it with +// Thread A creates a `OnceCell` and shares it with // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. -#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Sync for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Send for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "68198")] impl RefUnwindSafe for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "68198")] impl UnwindSafe for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "68198")] impl Default for SyncOnceCell { fn default() -> SyncOnceCell { SyncOnceCell::new() } } -#[unstable(feature = "once_cell", issue = "68198")] impl fmt::Debug for SyncOnceCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { - Some(v) => f.debug_tuple("Once").field(v).finish(), - None => f.write_str("Once(Uninit)"), + Some(v) => f.debug_tuple("SyncOnceCell").field(v).finish(), + None => f.write_str("SyncOnceCell(Uninit)"), } } } -#[unstable(feature = "once_cell", issue = "68198")] impl Clone for SyncOnceCell { fn clone(&self) -> SyncOnceCell { let res = SyncOnceCell::new(); @@ -96,7 +567,6 @@ impl Clone for SyncOnceCell { } } -#[unstable(feature = "once_cell", issue = "68198")] impl From for SyncOnceCell { fn from(value: T) -> Self { let cell = Self::new(); @@ -105,24 +575,21 @@ impl From for SyncOnceCell { } } -#[unstable(feature = "once_cell", issue = "68198")] impl PartialEq for SyncOnceCell { fn eq(&self, other: &SyncOnceCell) -> bool { self.get() == other.get() } } -#[unstable(feature = "once_cell", issue = "68198")] impl Eq for SyncOnceCell {} impl SyncOnceCell { /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "68198")] pub const fn new() -> SyncOnceCell { SyncOnceCell { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: PhantomData, - value: UnsafeCell::new(MaybeUninit::uninit()), + value: UnsafeCell::new(None), } } @@ -130,7 +597,6 @@ impl SyncOnceCell { /// /// Returns `None` if the cell is empty, or being initialized. This /// method never blocks. - #[unstable(feature = "once_cell", issue = "68198")] pub fn get(&self) -> Option<&T> { if self.is_initialized() { // Safe b/c checked is_initialize @@ -142,14 +608,29 @@ impl SyncOnceCell { /// Gets the mutable reference to the underlying value. /// - /// Returns `None` if the cell is empty. This method never blocks. - #[unstable(feature = "once_cell", issue = "68198")] + /// Returns `None` if the cell is empty. pub fn get_mut(&mut self) -> Option<&mut T> { - if self.is_initialized() { - // Safe b/c checked is_initialize and we have a unique access - Some(unsafe { self.get_unchecked_mut() }) - } else { - None + // Safe b/c we have a unique access. + unsafe { &mut *self.value.get() }.as_mut() + } + + /// Get the reference to the underlying value, without checking if the + /// cell is initialized. + /// + /// Safety: + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + pub unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + let slot: &Option = &*self.value.get(); + match slot { + Some(value) => value, + // This unsafe does improve performance, see `examples/bench`. + None => { + debug_assert!(false); + unreachable_unchecked() + } } } @@ -158,11 +639,8 @@ impl SyncOnceCell { /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. /// - /// # Examples - /// + /// # Example /// ``` - /// #![feature(once_cell)] - /// /// use std::lazy::SyncOnceCell; /// /// static CELL: SyncOnceCell = SyncOnceCell::new(); @@ -178,7 +656,6 @@ impl SyncOnceCell { /// assert_eq!(CELL.get(), Some(&92)); /// } /// ``` - #[unstable(feature = "once_cell", issue = "68198")] pub fn set(&self, value: T) -> Result<(), T> { let mut value = Some(value); self.get_or_init(|| value.take().unwrap()); @@ -204,11 +681,8 @@ impl SyncOnceCell { /// exact outcome is unspecified. Current implementation deadlocks, but /// this may be changed to a panic in the future. /// - /// # Examples - /// + /// # Example /// ``` - /// #![feature(once_cell)] - /// /// use std::lazy::SyncOnceCell; /// /// let cell = SyncOnceCell::new(); @@ -217,7 +691,6 @@ impl SyncOnceCell { /// let value = cell.get_or_init(|| unreachable!()); /// assert_eq!(value, &92); /// ``` - #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -240,11 +713,8 @@ impl SyncOnceCell { /// The exact outcome is unspecified. Current implementation /// deadlocks, but this may be changed to a panic in the future. /// - /// # Examples - /// + /// # Example /// ``` - /// #![feature(once_cell)] - /// /// use std::lazy::SyncOnceCell; /// /// let cell = SyncOnceCell::new(); @@ -256,22 +726,18 @@ impl SyncOnceCell { /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` - #[unstable(feature = "once_cell", issue = "68198")] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, { // Fast path check - // NOTE: This acquire here is important to ensure - // `SyncLazy::force` is correctly synchronized if let Some(value) = self.get() { return Ok(value); } self.initialize(f)?; + // Safe b/c called initialize debug_assert!(self.is_initialized()); - - // Safety: The inner value has been initialized Ok(unsafe { self.get_unchecked() }) } @@ -281,8 +747,6 @@ impl SyncOnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] - /// /// use std::lazy::SyncOnceCell; /// /// let cell: SyncOnceCell = SyncOnceCell::new(); @@ -292,59 +756,10 @@ impl SyncOnceCell { /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn into_inner(mut self) -> Option { - // Safety: Safe because we immediately free `self` without dropping - let inner = unsafe { self.take_inner() }; - - // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set - // the state to uninitialized. - mem::ManuallyDrop::new(self); - inner - } - - /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. - /// - /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized. - /// - /// Safety is guaranteed by requiring a mutable reference. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let mut cell: SyncOnceCell = SyncOnceCell::new(); - /// assert_eq!(cell.take(), None); - /// - /// let mut cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.take(), Some("hello".to_string())); - /// assert_eq!(cell.get(), None); - /// ``` - #[unstable(feature = "once_cell", issue = "68198")] - pub fn take(&mut self) -> Option { - mem::take(self).into_inner() - } - - /// Takes the wrapped value out of a `SyncOnceCell`. - /// Afterwards the cell is no longer initialized. - /// - /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell - /// are valid. Only used by `into_inner` and `drop`. - unsafe fn take_inner(&mut self) -> Option { - // The mutable reference guarantees there are no other threads that can observe us - // taking out the wrapped value. - // Right after this function `self` is supposed to be freed, so it makes little sense - // to atomically set the state to uninitialized. - if self.is_initialized() { - let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); - Some(value.into_inner().assume_init()) - } else { - None - } + pub fn into_inner(self) -> Option { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option`. + self.value.into_inner() } /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). @@ -372,7 +787,7 @@ impl SyncOnceCell { let f = f.take().unwrap(); match f() { Ok(value) => { - unsafe { (&mut *slot.get()).write(value) }; + unsafe { *slot.get() = Some(value) }; true } Err(e) => { @@ -383,33 +798,18 @@ impl SyncOnceCell { }); res } - - /// Safety: The value must be initialized - unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - (&*self.value.get()).get_ref() - } - - /// Safety: The value must be initialized - unsafe fn get_unchecked_mut(&mut self) -> &mut T { - debug_assert!(self.is_initialized()); - (&mut *self.value.get()).get_mut() - } -} - -impl Drop for SyncOnceCell { - fn drop(&mut self) { - // Safety: The cell is being dropped, so it can't be accessed again - unsafe { self.take_inner() }; - } } +// region: copy-paste +// The following code is copied from `sync::Once`. +// This should be uncopypasted once we decide the right way to handle panics. const INCOMPLETE: usize = 0x0; const RUNNING: usize = 0x1; const COMPLETE: usize = 0x2; const STATE_MASK: usize = 0x3; + #[repr(align(4))] struct Waiter { thread: Cell>, @@ -501,21 +901,19 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { break; } } +// endregion: copy-paste /// A value which is initialized on the first access. /// -/// This type is a thread-safe `Lazy`, and can be used in statics. -/// -/// # Examples +/// This type is thread-safe and can be used in statics: /// +/// # Example /// ``` -/// #![feature(once_cell)] -/// /// use std::collections::HashMap; /// -/// use std::lazy::SyncLazy; +/// use std::lazy::Lazy; /// -/// static HASHMAP: SyncLazy> = SyncLazy::new(|| { +/// static HASHMAP: Lazy> = Lazy::new(|| { /// println!("initializing"); /// let mut m = HashMap::new(); /// m.insert(13, "Spica".to_string()); @@ -537,16 +935,14 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { /// // Some("Hoyten") /// } /// ``` -#[unstable(feature = "once_cell", issue = "68198")] pub struct SyncLazy T> { cell: SyncOnceCell, init: Cell>, } -#[unstable(feature = "once_cell", issue = "68198")] -impl fmt::Debug for SyncLazy { +impl fmt::Debug for SyncLazy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + f.debug_struct("SyncLazy").field("cell", &self.cell).field("init", &"..").finish() } } @@ -555,17 +951,15 @@ impl fmt::Debug for SyncLazy { // we do create a `&mut Option` in `force`, but this is // properly synchronized, so it only happens once // so it also does not contribute to this impl. -#[unstable(feature = "once_cell", issue = "68198")] unsafe impl Sync for SyncLazy where SyncOnceCell: Sync {} // auto-derived `Send` impl is OK. -#[unstable(feature = "once_cell", issue = "68198")] +#[cfg(feature = "std")] impl RefUnwindSafe for SyncLazy where SyncOnceCell: RefUnwindSafe {} impl SyncLazy { /// Creates a new lazy value with the given initializing /// function. - #[unstable(feature = "once_cell", issue = "68198")] pub const fn new(f: F) -> SyncLazy { SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } } @@ -576,11 +970,8 @@ impl T> SyncLazy { /// returns a reference to result. This is equivalent /// to the `Deref` impl, but is explicit. /// - /// # Examples - /// + /// # Example /// ``` - /// #![feature(once_cell)] - /// /// use std::lazy::SyncLazy; /// /// let lazy = SyncLazy::new(|| 92); @@ -588,16 +979,14 @@ impl T> SyncLazy { /// assert_eq!(SyncLazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` - #[unstable(feature = "once_cell", issue = "68198")] pub fn force(this: &SyncLazy) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), - None => panic!("Lazy instance has previously been poisoned"), + None => panic!("SyncLazy instance has previously been poisoned"), }) } } -#[unstable(feature = "once_cell", issue = "68198")] impl T> Deref for SyncLazy { type Target = T; fn deref(&self) -> &T { @@ -605,348 +994,9 @@ impl T> Deref for SyncLazy { } } -#[unstable(feature = "once_cell", issue = "68198")] impl Default for SyncLazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> SyncLazy { SyncLazy::new(T::default) } } - -#[cfg(test)] -mod tests { - use crate::{ - lazy::{Lazy, SyncLazy, SyncOnceCell}, - panic, - sync::{ - atomic::{AtomicUsize, Ordering::SeqCst}, - mpsc::channel, - Mutex, - }, - }; - - #[test] - fn lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: Lazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn lazy_poisoning() { - let x: Lazy = Lazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } - } - - // miri doesn't support threads - #[cfg(not(miri))] - fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { - crate::thread::spawn(f).join().unwrap() - } - - #[cfg(not(miri))] - fn spawn(f: impl FnOnce() + Send + 'static) { - let _ = crate::thread::spawn(f); - } - - // "stub threads" for Miri - #[cfg(miri)] - fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { - f(()) - } - - #[cfg(miri)] - fn spawn(f: impl FnOnce() + Send + 'static) { - f(()) - } - - #[test] - fn sync_once_cell() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - assert!(ONCE_CELL.get().is_none()); - - spawn_and_wait(|| { - ONCE_CELL.get_or_init(|| 92); - assert_eq!(ONCE_CELL.get(), Some(&92)); - }); - - ONCE_CELL.get_or_init(|| panic!("Kabom!")); - assert_eq!(ONCE_CELL.get(), Some(&92)); - } - - #[test] - fn sync_once_cell_get_mut() { - let mut c = SyncOnceCell::new(); - assert!(c.get_mut().is_none()); - c.set(90).unwrap(); - *c.get_mut().unwrap() += 2; - assert_eq!(c.get_mut(), Some(&mut 92)); - } - - #[test] - fn sync_once_cell_get_unchecked() { - let c = SyncOnceCell::new(); - c.set(92).unwrap(); - unsafe { - assert_eq!(c.get_unchecked(), &92); - } - } - - #[test] - fn sync_once_cell_drop() { - static DROP_CNT: AtomicUsize = AtomicUsize::new(0); - struct Dropper; - impl Drop for Dropper { - fn drop(&mut self) { - DROP_CNT.fetch_add(1, SeqCst); - } - } - - let x = SyncOnceCell::new(); - spawn_and_wait(move || { - x.get_or_init(|| Dropper); - assert_eq!(DROP_CNT.load(SeqCst), 0); - drop(x); - }); - - assert_eq!(DROP_CNT.load(SeqCst), 1); - } - - #[test] - fn sync_once_cell_drop_empty() { - let x = SyncOnceCell::::new(); - drop(x); - } - - #[test] - fn clone() { - let s = SyncOnceCell::new(); - let c = s.clone(); - assert!(c.get().is_none()); - - s.set("hello".to_string()).unwrap(); - let c = s.clone(); - assert_eq!(c.get().map(String::as_str), Some("hello")); - } - - #[test] - fn get_or_try_init() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert!(cell.get().is_none()); - - let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); - assert!(res.is_err()); - assert!(cell.get().is_none()); - - assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - - assert_eq!( - cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), - Ok(&"hello".to_string()) - ); - assert_eq!(cell.get(), Some(&"hello".to_string())); - } - - #[test] - fn from_impl() { - assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); - assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); - } - - #[test] - fn partialeq_impl() { - assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); - assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); - - assert!(SyncOnceCell::::new() == SyncOnceCell::new()); - assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); - } - - #[test] - fn into_inner() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert_eq!(cell.into_inner(), None); - let cell = SyncOnceCell::new(); - cell.set("hello".to_string()).unwrap(); - assert_eq!(cell.into_inner(), Some("hello".to_string())); - } - - #[test] - fn sync_lazy_new() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { - CALLED.fetch_add(1, SeqCst); - 92 - }); - - assert_eq!(CALLED.load(SeqCst), 0); - - spawn_and_wait(|| { - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - }); - - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn sync_lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: SyncLazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - #[cfg_attr(miri, ignore)] // leaks memory - fn static_sync_lazy() { - static XS: SyncLazy> = SyncLazy::new(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }); - - spawn_and_wait(|| { - assert_eq!(&*XS, &vec![1, 2, 3]); - }); - - assert_eq!(&*XS, &vec![1, 2, 3]); - } - - #[test] - #[cfg_attr(miri, ignore)] // leaks memory - fn static_sync_lazy_via_fn() { - fn xs() -> &'static Vec { - static XS: SyncOnceCell> = SyncOnceCell::new(); - XS.get_or_init(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }) - } - assert_eq!(xs(), &vec![1, 2, 3]); - } - - #[test] - fn sync_lazy_poisoning() { - let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } - } - - #[test] - fn is_sync_send() { - fn assert_traits() {} - assert_traits::>(); - assert_traits::>(); - } - - #[test] - fn eval_once_macro() { - macro_rules! eval_once { - (|| -> $ty:ty { - $($body:tt)* - }) => {{ - static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); - fn init() -> $ty { - $($body)* - } - ONCE_CELL.get_or_init(init) - }}; - } - - let fib: &'static Vec = eval_once! { - || -> Vec { - let mut res = vec![1, 1]; - for i in 0..10 { - let next = res[i] + res[i + 1]; - res.push(next); - } - res - } - }; - assert_eq!(fib[5], 8) - } - - #[test] - #[cfg_attr(miri, ignore)] // deadlocks without real threads - fn sync_once_cell_does_not_leak_partially_constructed_boxes() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - let n_readers = 10; - let n_writers = 3; - const MSG: &str = "Hello, World"; - - let (tx, rx) = channel(); - - for _ in 0..n_readers { - let tx = tx.clone(); - spawn(move || { - loop { - if let Some(msg) = ONCE_CELL.get() { - tx.send(msg).unwrap(); - break; - } - } - }); - } - for _ in 0..n_writers { - spawn(move || { - let _ = ONCE_CELL.set(MSG.to_owned()); - }); - } - - for _ in 0..n_readers { - let msg = rx.recv().unwrap(); - assert_eq!(msg, MSG); - } - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 21978f0d936f4..9feefd4e242a1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -284,7 +284,6 @@ #![feature(linkage)] #![feature(llvm_asm)] #![feature(log_syntax)] -#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(min_specialization)] @@ -292,7 +291,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] -#![feature(once_cell)] #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(panic_info_message)] @@ -477,7 +475,10 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "once_cell", issue = "68198")] +#[unstable( + feature = "std_lazy", + issue = "99", +)] pub mod lazy; #[stable(feature = "futures_api", since = "1.36.0")] From 6eaaff4f1f24c8d512ab1d9ecd0295add1683a7e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 24 Jul 2020 09:59:16 -0400 Subject: [PATCH 7/7] Revert "First cut of `std::lazy` module" This reverts commit cac1768b03c8d6673c51605dca03997876979d68. --- src/libstd/lazy.rs | 1002 -------------------------------------------- src/libstd/lib.rs | 6 - 2 files changed, 1008 deletions(-) delete mode 100644 src/libstd/lazy.rs diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs deleted file mode 100644 index bcac2dc311aff..0000000000000 --- a/src/libstd/lazy.rs +++ /dev/null @@ -1,1002 +0,0 @@ -//! `lazy` modules provides lazy values and one-time initialization of static data. -//! -//! `lazy` provides two new cell-like types, `OnceCell` and `SyncOnceCell`. `OnceCell` -//! might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access -//! to the stored contents. In a nutshell, API looks *roughly* like this: -//! -//! ```rust,ignore -//! impl OnceCell { -//! fn new() -> OnceCell { ... } -//! fn set(&self, value: T) -> Result<(), T> { ... } -//! fn get(&self) -> Option<&T> { ... } -//! } -//! ``` -//! -//! Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. -//! Because of the single assignment restriction `get` can return an `&T` instead of `Ref` -//! or `MutexGuard`. -//! -//! The `SyncOnceCell` flavor is thread-safe (that is, implements [`Sync`]) trait, while `OnceCell` one is not. -//! -//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html -//! -//! # Patterns -//! -//! `OnceCell` might be useful for a variety of patterns. -//! -//! ## Safe Initialization of global data -//! -//! ```rust -//! use std::{env, io}; -//! use std::lazy::SyncOnceCell; -//! -//! #[derive(Debug)] -//! pub struct Logger { -//! // ... -//! } -//! static INSTANCE: OnceCell = OnceCell::new(); -//! -//! impl Logger { -//! pub fn global() -> &'static Logger { -//! INSTANCE.get().expect("logger is not initialized") -//! } -//! -//! fn from_cli(args: env::Args) -> Result { -//! // ... -//! # Ok(Logger {}) -//! } -//! } -//! -//! fn main() { -//! let logger = Logger::from_cli(env::args()).unwrap(); -//! INSTANCE.set(logger).unwrap(); -//! // use `Logger::global()` from now on -//! } -//! ``` -//! -//! ## Lazy initialized global data -//! -//! This is essentially `lazy_static!` macro, but without a macro. -//! -//! ```rust -//! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::SyncOnceCell; -//! -//! fn global_data() -> &'static Mutex> { -//! static INSTANCE: OnceCell>> = OnceCell::new(); -//! INSTANCE.get_or_init(|| { -//! let mut m = HashMap::new(); -//! m.insert(13, "Spica".to_string()); -//! m.insert(74, "Hoyten".to_string()); -//! Mutex::new(m) -//! }) -//! } -//! ``` -//! -//! There are also `sync::Lazy` and `unsync::Lazy` convenience types to streamline this pattern: -//! -//! ```rust -//! use std::{sync::Mutex, collections::HashMap}; -//! use lazy::SyncLazy; -//! -//! static GLOBAL_DATA: Lazy>> = Lazy::new(|| { -//! let mut m = HashMap::new(); -//! m.insert(13, "Spica".to_string()); -//! m.insert(74, "Hoyten".to_string()); -//! Mutex::new(m) -//! }); -//! -//! fn main() { -//! println!("{:?}", GLOBAL_DATA.lock().unwrap()); -//! } -//! ``` -//! -//! ## General purpose lazy evaluation -//! -//! `Lazy` also works with local variables. -//! -//! ```rust -//! use std::lazy::Lazy; -//! -//! fn main() { -//! let ctx = vec![1, 2, 3]; -//! let thunk = Lazy::new(|| { -//! ctx.iter().sum::() -//! }); -//! assert_eq!(*thunk, 6); -//! } -//! ``` -//! -//! If you need a lazy field in a struct, you probably should use `OnceCell` -//! directly, because that will allow you to access `self` during initialization. -//! -//! ```rust -//! use std::{fs, path::PathBuf}; -//! -//! use std::lazy::OnceCell; -//! -//! struct Ctx { -//! config_path: PathBuf, -//! config: OnceCell, -//! } -//! -//! impl Ctx { -//! pub fn get_config(&self) -> Result<&str, std::io::Error> { -//! let cfg = self.config.get_or_try_init(|| { -//! fs::read_to_string(&self.config_path) -//! })?; -//! Ok(cfg.as_str()) -//! } -//! } -//! ``` -//! -//! ## Building block -//! -//! Naturally, it is possible to build other abstractions on top of `OnceCell`. -//! For example, this is a `regex!` macro which takes a string literal and returns an -//! *expression* that evaluates to a `&'static Regex`: -//! -//! ``` -//! macro_rules! regex { -//! ($re:literal $(,)?) => {{ -//! static RE: std::lazy::SyncOnceCell = std::lazy::SyncOnceCell::new(); -//! RE.get_or_init(|| regex::Regex::new($re).unwrap()) -//! }}; -//! } -//! ``` -//! -//! This macro can be useful to avoid "compile regex on every loop iteration" problem. -//! -//! # Comparison with other interior mutatbility types -//! -//! |`!Sync` types | Access Mode | Drawbacks | -//! |----------------------|------------------------|-----------------------------------------------| -//! |`Cell` | `T` | requires `T: Copy` for `get` | -//! |`RefCell` | `RefMut` / `Ref` | may panic at runtime | -//! |`OnceCell` | `&T` | assignable only once | -//! -//! |`Sync` types | Access Mode | Drawbacks | -//! |----------------------|------------------------|-----------------------------------------------| -//! |`AtomicT` | `T` | works only with certain `Copy` types | -//! |`Mutex` | `MutexGuard` | may deadlock at runtime, may block the thread | -//! |`SyncOnceCell` | `&T` | assignable only once, may block the thread | -//! -//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls -//! itself. However, because the assignment can happen only once, such cases should be more rare than -//! equivalents with `RefCell` and `Mutex`. - -use crate::{ - cell::{Cell, UnsafeCell}, - fmt, - hint::unreachable_unchecked, - marker::PhantomData, - ops::Deref, - panic::{RefUnwindSafe, UnwindSafe}, - sync::atomic::{AtomicBool, AtomicUsize, Ordering}, - thread::{self, Thread}, -}; - -/// A cell which can be written to only once. Not thread safe. -/// -/// Unlike `:td::cell::RefCell`, a `OnceCell` provides simple `&` -/// references to the contents. -/// -/// # Example -/// ``` -/// use std::lazy::OnceCell; -/// -/// let cell = OnceCell::new(); -/// assert!(cell.get().is_none()); -/// -/// let value: &String = cell.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// assert!(cell.get().is_some()); -/// ``` -pub struct OnceCell { - // Invariant: written to at most once. - inner: UnsafeCell>, -} - -// Similarly to a `Sync` bound on `SyncOnceCell`, we can use -// `&OnceCell` to sneak a `T` through `catch_unwind`, -// by initializing the cell in closure and extracting the value in the -// `Drop`. -#[cfg(feature = "std")] -impl RefUnwindSafe for OnceCell {} -#[cfg(feature = "std")] -impl UnwindSafe for OnceCell {} - -impl Default for OnceCell { - fn default() -> Self { - Self::new() - } -} - -impl fmt::Debug for OnceCell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("OnceCell").field(v).finish(), - None => f.write_str("OnceCell(Uninit)"), - } - } -} - -impl Clone for OnceCell { - fn clone(&self) -> OnceCell { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -impl PartialEq for OnceCell { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -impl Eq for OnceCell {} - -impl From for OnceCell { - fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } - } -} - -impl OnceCell { - /// Creates a new empty cell. - pub const fn new() -> OnceCell { - OnceCell { inner: UnsafeCell::new(None) } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - pub fn get(&self) -> Option<&T> { - // Safe due to `inner`'s invariant - unsafe { &*self.inner.get() }.as_ref() - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - pub fn get_mut(&mut self) -> Option<&mut T> { - // Safe because we have unique access - unsafe { &mut *self.inner.get() }.as_mut() - } - - /// Sets the contents of this cell to `value`. - /// - /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was - /// full. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert!(cell.get().is_none()); - /// - /// assert_eq!(cell.set(92), Ok(())); - /// assert_eq!(cell.set(62), Err(62)); - /// - /// assert!(cell.get().is_some()); - /// ``` - pub fn set(&self, value: T) -> Result<(), T> { - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - let slot = unsafe { &mut *self.inner.get() }; - // This is the only place where we set the slot, no races - // due to reentrancy/concurrency are possible, and we've - // checked that slot is currently `None`, so this write - // maintains the `inner`'s invariant. - *slot = Some(value); - Ok(()) - } - - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. Doing - /// so results in a panic. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - pub fn get_or_init(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::(f())) { - Ok(val) => val, - } - } - - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. Doing - /// so results in a panic. - /// - /// # Example - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result { - /// Ok(92) - /// }); - /// assert_eq!(value, Ok(&92)); - /// assert_eq!(cell.get(), Some(&92)) - /// ``` - pub fn get_or_try_init(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result, - { - if let Some(val) = self.get() { - return Ok(val); - } - let val = f()?; - // Note that *some* forms of reentrant initialization might lead to - // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems - // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) - } - - /// Consumes the `OnceCell`, returning the wrapped value. - /// - /// Returns `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// use std::lazy::OnceCell; - /// - /// let cell: OnceCell = OnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - pub fn into_inner(self) -> Option { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option`. - self.inner.into_inner() - } -} - -/// A value which is initialized on the first access. -/// -/// # Example -/// ``` -/// use std::lazy::Lazy; -/// -/// let lazy: Lazy = Lazy::new(|| { -/// println!("initializing"); -/// 92 -/// }); -/// println!("ready"); -/// println!("{}", *lazy); -/// println!("{}", *lazy); -/// -/// // Prints: -/// // ready -/// // initializing -/// // 92 -/// // 92 -/// ``` -pub struct Lazy T> { - cell: OnceCell, - init: Cell>, -} - -#[cfg(feature = "std")] -impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} - -impl fmt::Debug for Lazy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() - } -} - -impl Lazy { - /// Creates a new lazy value with the given initializing function. - /// - /// # Example - /// ``` - /// # fn main() { - /// use std::lazy::Lazy; - /// - /// let hello = "Hello, World!".to_string(); - /// - /// let lazy = Lazy::new(|| hello.to_uppercase()); - /// - /// assert_eq!(&*lazy, "HELLO, WORLD!"); - /// # } - /// ``` - pub const fn new(init: F) -> Lazy { - Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } - } -} - -impl T> Lazy { - /// Forces the evaluation of this lazy value and returns a reference to - /// the result. - /// - /// This is equivalent to the `Deref` impl, but is explicit. - /// - /// # Example - /// ``` - /// use std::lazy::Lazy; - /// - /// let lazy = Lazy::new(|| 92); - /// - /// assert_eq!(Lazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - pub fn force(this: &Lazy) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("Lazy instance has previously been poisoned"), - }) - } -} - -impl T> Deref for Lazy { - type Target = T; - fn deref(&self) -> &T { - Lazy::force(self) - } -} - -impl Default for Lazy { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> Lazy { - Lazy::new(T::default) - } -} - -/// A thread-safe cell which can be written to only once. -/// -/// `OnceCell` provides `&` references to the contents without RAII guards. -/// -/// Reading a non-`None` value out of `OnceCell` establishes a -/// happens-before relationship with a corresponding write. For example, if -/// thread A initializes the cell with `get_or_init(f)`, and thread B -/// subsequently reads the result of this call, B also observes all the side -/// effects of `f`. -/// -/// # Example -/// ``` -/// use std::lazy::SyncOnceCell; -/// -/// static CELL: OnceCell = OnceCell::new(); -/// assert!(CELL.get().is_none()); -/// -/// std::thread::spawn(|| { -/// let value: &String = CELL.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// }).join().unwrap(); -/// -/// let value: Option<&String> = CELL.get(); -/// assert!(value.is_some()); -/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); -/// ``` -pub struct SyncOnceCell { - // This `state` word is actually an encoded version of just a pointer to a - // `Waiter`, so we add the `PhantomData` appropriately. - state_and_queue: AtomicUsize, - _marker: PhantomData<*mut Waiter>, - // FIXME: switch to `std::mem::MaybeUninit` once we are ready to bump MSRV - // that far. It was stabilized in 1.36.0, so, if you are reading this and - // it's higher than 1.46.0 outside, please send a PR! ;) (and do the same - // for `Lazy`, while we are at it). - pub(crate) value: UnsafeCell>, -} - -// Why do we need `T: Send`? -// Thread A creates a `OnceCell` and shares it with -// scoped thread B, which fills the cell, which is -// then destroyed by A. That is, destructor observes -// a sent value. -unsafe impl Sync for SyncOnceCell {} -unsafe impl Send for SyncOnceCell {} - -impl RefUnwindSafe for SyncOnceCell {} -impl UnwindSafe for SyncOnceCell {} - -impl Default for SyncOnceCell { - fn default() -> SyncOnceCell { - SyncOnceCell::new() - } -} - -impl fmt::Debug for SyncOnceCell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("SyncOnceCell").field(v).finish(), - None => f.write_str("SyncOnceCell(Uninit)"), - } - } -} - -impl Clone for SyncOnceCell { - fn clone(&self) -> SyncOnceCell { - let res = SyncOnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -impl From for SyncOnceCell { - fn from(value: T) -> Self { - let cell = Self::new(); - cell.get_or_init(|| value); - cell - } -} - -impl PartialEq for SyncOnceCell { - fn eq(&self, other: &SyncOnceCell) -> bool { - self.get() == other.get() - } -} - -impl Eq for SyncOnceCell {} - -impl SyncOnceCell { - /// Creates a new empty cell. - pub const fn new() -> SyncOnceCell { - SyncOnceCell { - state_and_queue: AtomicUsize::new(INCOMPLETE), - _marker: PhantomData, - value: UnsafeCell::new(None), - } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty, or being initialized. This - /// method never blocks. - pub fn get(&self) -> Option<&T> { - if self.is_initialized() { - // Safe b/c checked is_initialize - Some(unsafe { self.get_unchecked() }) - } else { - None - } - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - pub fn get_mut(&mut self) -> Option<&mut T> { - // Safe b/c we have a unique access. - unsafe { &mut *self.value.get() }.as_mut() - } - - /// Get the reference to the underlying value, without checking if the - /// cell is initialized. - /// - /// Safety: - /// - /// Caller must ensure that the cell is in initialized state, and that - /// the contents are acquired by (synchronized to) this thread. - pub unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - let slot: &Option = &*self.value.get(); - match slot { - Some(value) => value, - // This unsafe does improve performance, see `examples/bench`. - None => { - debug_assert!(false); - unreachable_unchecked() - } - } - } - - /// Sets the contents of this cell to `value`. - /// - /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was - /// full. - /// - /// # Example - /// ``` - /// use std::lazy::SyncOnceCell; - /// - /// static CELL: SyncOnceCell = SyncOnceCell::new(); - /// - /// fn main() { - /// assert!(CELL.get().is_none()); - /// - /// std::thread::spawn(|| { - /// assert_eq!(CELL.set(92), Ok(())); - /// }).join().unwrap(); - /// - /// assert_eq!(CELL.set(62), Err(62)); - /// assert_eq!(CELL.get(), Some(&92)); - /// } - /// ``` - pub fn set(&self, value: T) -> Result<(), T> { - let mut value = Some(value); - self.get_or_init(|| value.take().unwrap()); - match value { - None => Ok(()), - Some(value) => Err(value), - } - } - - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. - /// - /// Many threads may call `get_or_init` concurrently with different - /// initializing functions, but it is guaranteed that only one function - /// will be executed. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// 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. - /// - /// # Example - /// ``` - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - pub fn get_or_init(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::(f())) { - Ok(val) => val, - } - } - - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and - /// the cell remains uninitialized. - /// - /// 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. - /// - /// # Example - /// ``` - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result { - /// Ok(92) - /// }); - /// assert_eq!(value, Ok(&92)); - /// assert_eq!(cell.get(), Some(&92)) - /// ``` - pub fn get_or_try_init(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result, - { - // Fast path check - if let Some(value) = self.get() { - return Ok(value); - } - self.initialize(f)?; - - // Safe b/c called initialize - debug_assert!(self.is_initialized()); - Ok(unsafe { self.get_unchecked() }) - } - - /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns - /// `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// use std::lazy::SyncOnceCell; - /// - /// let cell: SyncOnceCell = SyncOnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - pub fn into_inner(self) -> Option { - // Because `into_inner` takes `self` by value, the compiler statically verifies - // that it is not currently borrowed. So it is safe to move out `Option`. - self.value.into_inner() - } - - /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). - #[inline] - fn is_initialized(&self) -> bool { - // An `Acquire` load is enough because that makes all the initialization - // operations visible to us, and, this being a fast path, weaker - // ordering helps with performance. This `Acquire` synchronizes with - // `SeqCst` operations on the slow path. - self.state_and_queue.load(Ordering::Acquire) == COMPLETE - } - - /// Safety: synchronizes with store to value via SeqCst read from state, - /// writes value only once because we never get to INCOMPLETE state after a - /// successful write. - #[cold] - fn initialize(&self, f: F) -> Result<(), E> - where - F: FnOnce() -> Result, - { - let mut f = Some(f); - let mut res: Result<(), E> = Ok(()); - let slot = &self.value; - initialize_inner(&self.state_and_queue, &mut || { - let f = f.take().unwrap(); - match f() { - Ok(value) => { - unsafe { *slot.get() = Some(value) }; - true - } - Err(e) => { - res = Err(e); - false - } - } - }); - res - } -} - -// region: copy-paste -// The following code is copied from `sync::Once`. -// This should be uncopypasted once we decide the right way to handle panics. -const INCOMPLETE: usize = 0x0; -const RUNNING: usize = 0x1; -const COMPLETE: usize = 0x2; - -const STATE_MASK: usize = 0x3; - - -#[repr(align(4))] -struct Waiter { - thread: Cell>, - signaled: AtomicBool, - next: *const Waiter, -} - -struct WaiterQueue<'a> { - state_and_queue: &'a AtomicUsize, - set_state_on_drop_to: usize, -} - -impl Drop for WaiterQueue<'_> { - fn drop(&mut self) { - let state_and_queue = - self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel); - - assert_eq!(state_and_queue & STATE_MASK, RUNNING); - - unsafe { - let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter; - while !queue.is_null() { - let next = (*queue).next; - let thread = (*queue).thread.replace(None).unwrap(); - (*queue).signaled.store(true, Ordering::Release); - queue = next; - thread.unpark(); - } - } - } -} - -fn initialize_inner(my_state_and_queue: &AtomicUsize, init: &mut dyn FnMut() -> bool) -> bool { - let mut state_and_queue = my_state_and_queue.load(Ordering::Acquire); - - loop { - match state_and_queue { - COMPLETE => return true, - INCOMPLETE => { - let old = my_state_and_queue.compare_and_swap( - state_and_queue, - RUNNING, - Ordering::Acquire, - ); - if old != state_and_queue { - state_and_queue = old; - continue; - } - let mut waiter_queue = WaiterQueue { - state_and_queue: my_state_and_queue, - set_state_on_drop_to: INCOMPLETE, - }; - let success = init(); - - waiter_queue.set_state_on_drop_to = if success { COMPLETE } else { INCOMPLETE }; - return success; - } - _ => { - assert!(state_and_queue & STATE_MASK == RUNNING); - wait(&my_state_and_queue, state_and_queue); - state_and_queue = my_state_and_queue.load(Ordering::Acquire); - } - } - } -} - -fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { - loop { - if current_state & STATE_MASK != RUNNING { - return; - } - - let node = Waiter { - thread: Cell::new(Some(thread::current())), - signaled: AtomicBool::new(false), - next: (current_state & !STATE_MASK) as *const Waiter, - }; - let me = &node as *const Waiter as usize; - - let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release); - if old != current_state { - current_state = old; - continue; - } - - while !node.signaled.load(Ordering::Acquire) { - thread::park(); - } - break; - } -} -// endregion: copy-paste - -/// A value which is initialized on the first access. -/// -/// This type is thread-safe and can be used in statics: -/// -/// # Example -/// ``` -/// use std::collections::HashMap; -/// -/// use std::lazy::Lazy; -/// -/// static HASHMAP: Lazy> = Lazy::new(|| { -/// println!("initializing"); -/// let mut m = HashMap::new(); -/// m.insert(13, "Spica".to_string()); -/// m.insert(74, "Hoyten".to_string()); -/// m -/// }); -/// -/// fn main() { -/// println!("ready"); -/// std::thread::spawn(|| { -/// println!("{:?}", HASHMAP.get(&13)); -/// }).join().unwrap(); -/// println!("{:?}", HASHMAP.get(&74)); -/// -/// // Prints: -/// // ready -/// // initializing -/// // Some("Spica") -/// // Some("Hoyten") -/// } -/// ``` -pub struct SyncLazy T> { - cell: SyncOnceCell, - init: Cell>, -} - -impl fmt::Debug for SyncLazy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SyncLazy").field("cell", &self.cell).field("init", &"..").finish() - } -} - -// We never create a `&F` from a `&SyncLazy` so it is fine -// to not impl `Sync` for `F` -// we do create a `&mut Option` in `force`, but this is -// properly synchronized, so it only happens once -// so it also does not contribute to this impl. -unsafe impl Sync for SyncLazy where SyncOnceCell: Sync {} -// auto-derived `Send` impl is OK. - -#[cfg(feature = "std")] -impl RefUnwindSafe for SyncLazy where SyncOnceCell: RefUnwindSafe {} - -impl SyncLazy { - /// Creates a new lazy value with the given initializing - /// function. - pub const fn new(f: F) -> SyncLazy { - SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } - } -} - -impl T> SyncLazy { - /// Forces the evaluation of this lazy value and - /// returns a reference to result. This is equivalent - /// to the `Deref` impl, but is explicit. - /// - /// # Example - /// ``` - /// use std::lazy::SyncLazy; - /// - /// let lazy = SyncLazy::new(|| 92); - /// - /// assert_eq!(SyncLazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - pub fn force(this: &SyncLazy) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("SyncLazy instance has previously been poisoned"), - }) - } -} - -impl T> Deref for SyncLazy { - type Target = T; - fn deref(&self) -> &T { - SyncLazy::force(self) - } -} - -impl Default for SyncLazy { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> SyncLazy { - SyncLazy::new(T::default) - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9feefd4e242a1..5acc24c34fee6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -475,12 +475,6 @@ pub mod process; pub mod sync; pub mod time; -#[unstable( - feature = "std_lazy", - issue = "99", -)] -pub mod lazy; - #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks.