Skip to content

Commit 488d048

Browse files
committed
Merge from rustc
2 parents d6c2912 + f94c244 commit 488d048

File tree

17 files changed

+332
-76
lines changed

17 files changed

+332
-76
lines changed

alloc/src/sync.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,20 @@ impl<T> Arc<T> {
654654
///
655655
/// This will succeed even if there are outstanding weak references.
656656
///
657+
// FIXME: when `Arc::into_inner` is stabilized, add this paragraph:
658+
/*
659+
/// It is strongly recommended to use [`Arc::into_inner`] instead if you don't
660+
/// want to keep the `Arc` in the [`Err`] case.
661+
/// Immediately dropping the [`Err`] payload, like in the expression
662+
/// `Arc::try_unwrap(this).ok()`, can still cause the strong count to
663+
/// drop to zero and the inner value of the `Arc` to be dropped:
664+
/// For instance if two threads execute this expression in parallel, then
665+
/// there is a race condition. The threads could first both check whether they
666+
/// have the last clone of their `Arc` via `Arc::try_unwrap`, and then
667+
/// both drop their `Arc` in the call to [`ok`][`Result::ok`],
668+
/// taking the strong count from two down to zero.
669+
///
670+
*/
657671
/// # Examples
658672
///
659673
/// ```
@@ -685,6 +699,137 @@ impl<T> Arc<T> {
685699
Ok(elem)
686700
}
687701
}
702+
703+
/// Returns the inner value, if the `Arc` has exactly one strong reference.
704+
///
705+
/// Otherwise, [`None`] is returned and the `Arc` is dropped.
706+
///
707+
/// This will succeed even if there are outstanding weak references.
708+
///
709+
/// If `Arc::into_inner` is called on every clone of this `Arc`,
710+
/// it is guaranteed that exactly one of the calls returns the inner value.
711+
/// This means in particular that the inner value is not dropped.
712+
///
713+
/// The similar expression `Arc::try_unwrap(this).ok()` does not
714+
/// offer such a guarantee. See the last example below.
715+
//
716+
// FIXME: when `Arc::into_inner` is stabilized, add this to end
717+
// of the previous sentence:
718+
/*
719+
/// and the documentation of [`Arc::try_unwrap`].
720+
*/
721+
///
722+
/// # Examples
723+
///
724+
/// Minimal example demonstrating the guarantee that `Arc::into_inner` gives.
725+
/// ```
726+
/// #![feature(arc_into_inner)]
727+
///
728+
/// use std::sync::Arc;
729+
///
730+
/// let x = Arc::new(3);
731+
/// let y = Arc::clone(&x);
732+
///
733+
/// // Two threads calling `Arc::into_inner` on both clones of an `Arc`:
734+
/// let x_thread = std::thread::spawn(|| Arc::into_inner(x));
735+
/// let y_thread = std::thread::spawn(|| Arc::into_inner(y));
736+
///
737+
/// let x_inner_value = x_thread.join().unwrap();
738+
/// let y_inner_value = y_thread.join().unwrap();
739+
///
740+
/// // One of the threads is guaranteed to receive the inner value:
741+
/// assert!(matches!(
742+
/// (x_inner_value, y_inner_value),
743+
/// (None, Some(3)) | (Some(3), None)
744+
/// ));
745+
/// // The result could also be `(None, None)` if the threads called
746+
/// // `Arc::try_unwrap(x).ok()` and `Arc::try_unwrap(y).ok()` instead.
747+
/// ```
748+
///
749+
/// A more practical example demonstrating the need for `Arc::into_inner`:
750+
/// ```
751+
/// #![feature(arc_into_inner)]
752+
///
753+
/// use std::sync::Arc;
754+
///
755+
/// // Definition of a simple singly linked list using `Arc`:
756+
/// #[derive(Clone)]
757+
/// struct LinkedList<T>(Option<Arc<Node<T>>>);
758+
/// struct Node<T>(T, Option<Arc<Node<T>>>);
759+
///
760+
/// // Dropping a long `LinkedList<T>` relying on the destructor of `Arc`
761+
/// // can cause a stack overflow. To prevent this, we can provide a
762+
/// // manual `Drop` implementation that does the destruction in a loop:
763+
/// impl<T> Drop for LinkedList<T> {
764+
/// fn drop(&mut self) {
765+
/// let mut link = self.0.take();
766+
/// while let Some(arc_node) = link.take() {
767+
/// if let Some(Node(_value, next)) = Arc::into_inner(arc_node) {
768+
/// link = next;
769+
/// }
770+
/// }
771+
/// }
772+
/// }
773+
///
774+
/// // Implementation of `new` and `push` omitted
775+
/// impl<T> LinkedList<T> {
776+
/// /* ... */
777+
/// # fn new() -> Self {
778+
/// # LinkedList(None)
779+
/// # }
780+
/// # fn push(&mut self, x: T) {
781+
/// # self.0 = Some(Arc::new(Node(x, self.0.take())));
782+
/// # }
783+
/// }
784+
///
785+
/// // The following code could have still caused a stack overflow
786+
/// // despite the manual `Drop` impl if that `Drop` impl had used
787+
/// // `Arc::try_unwrap(arc).ok()` instead of `Arc::into_inner(arc)`.
788+
///
789+
/// // Create a long list and clone it
790+
/// let mut x = LinkedList::new();
791+
/// for i in 0..100000 {
792+
/// x.push(i); // Adds i to the front of x
793+
/// }
794+
/// let y = x.clone();
795+
///
796+
/// // Drop the clones in parallel
797+
/// let x_thread = std::thread::spawn(|| drop(x));
798+
/// let y_thread = std::thread::spawn(|| drop(y));
799+
/// x_thread.join().unwrap();
800+
/// y_thread.join().unwrap();
801+
/// ```
802+
803+
// FIXME: when `Arc::into_inner` is stabilized, adjust above documentation
804+
// and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also
805+
// open an issue on rust-lang/rust-clippy, asking for a lint against
806+
// `Arc::try_unwrap(...).ok()`.
807+
#[inline]
808+
#[unstable(feature = "arc_into_inner", issue = "106894")]
809+
pub fn into_inner(this: Self) -> Option<T> {
810+
// Make sure that the ordinary `Drop` implementation isn’t called as well
811+
let mut this = mem::ManuallyDrop::new(this);
812+
813+
// Following the implementation of `drop` and `drop_slow`
814+
if this.inner().strong.fetch_sub(1, Release) != 1 {
815+
return None;
816+
}
817+
818+
acquire!(this.inner().strong);
819+
820+
// SAFETY: This mirrors the line
821+
//
822+
// unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
823+
//
824+
// in `drop_slow`. Instead of dropping the value behind the pointer,
825+
// it is read and eventually returned; `ptr::read` has the same
826+
// safety conditions as `ptr::drop_in_place`.
827+
let inner = unsafe { ptr::read(Self::get_mut_unchecked(&mut this)) };
828+
829+
drop(Weak { ptr: this.ptr });
830+
831+
Some(inner)
832+
}
688833
}
689834

690835
impl<T> Arc<[T]> {

alloc/src/sync/tests.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,38 @@ fn try_unwrap() {
101101
assert_eq!(Arc::try_unwrap(x), Ok(5));
102102
}
103103

104+
#[test]
105+
fn into_inner() {
106+
for _ in 0..100
107+
// ^ Increase chances of hitting potential race conditions
108+
{
109+
let x = Arc::new(3);
110+
let y = Arc::clone(&x);
111+
let r_thread = std::thread::spawn(|| Arc::into_inner(x));
112+
let s_thread = std::thread::spawn(|| Arc::into_inner(y));
113+
let r = r_thread.join().expect("r_thread panicked");
114+
let s = s_thread.join().expect("s_thread panicked");
115+
assert!(
116+
matches!((r, s), (None, Some(3)) | (Some(3), None)),
117+
"assertion failed: unexpected result `{:?}`\
118+
\n expected `(None, Some(3))` or `(Some(3), None)`",
119+
(r, s),
120+
);
121+
}
122+
123+
let x = Arc::new(3);
124+
assert_eq!(Arc::into_inner(x), Some(3));
125+
126+
let x = Arc::new(4);
127+
let y = Arc::clone(&x);
128+
assert_eq!(Arc::into_inner(x), None);
129+
assert_eq!(Arc::into_inner(y), Some(4));
130+
131+
let x = Arc::new(5);
132+
let _w = Arc::downgrade(&x);
133+
assert_eq!(Arc::into_inner(x), Some(5));
134+
}
135+
104136
#[test]
105137
fn into_from_raw() {
106138
let x = Arc::new(Box::new("hello"));

std/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@
238238
#![feature(allocator_internals)]
239239
#![feature(allow_internal_unsafe)]
240240
#![feature(allow_internal_unstable)]
241-
#![feature(box_syntax)]
242241
#![feature(c_unwind)]
243242
#![feature(cfg_target_thread_local)]
244243
#![feature(concat_idents)]

std/src/sync/lazy_lock.rs

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
use crate::cell::Cell;
1+
use crate::cell::UnsafeCell;
22
use crate::fmt;
3+
use crate::mem::ManuallyDrop;
34
use crate::ops::Deref;
45
use crate::panic::{RefUnwindSafe, UnwindSafe};
5-
use crate::sync::OnceLock;
6+
use crate::sync::Once;
7+
8+
use super::once::ExclusiveState;
9+
10+
// We use the state of a Once as discriminant value. Upon creation, the state is
11+
// "incomplete" and `f` contains the initialization closure. In the first call to
12+
// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
13+
// is changed to "complete". If it panics, the Once is poisoned, so none of the
14+
// two fields is initialized.
15+
union Data<T, F> {
16+
value: ManuallyDrop<T>,
17+
f: ManuallyDrop<F>,
18+
}
619

720
/// A value which is initialized on the first access.
821
///
@@ -43,16 +56,17 @@ use crate::sync::OnceLock;
4356
/// ```
4457
#[unstable(feature = "once_cell", issue = "74465")]
4558
pub struct LazyLock<T, F = fn() -> T> {
46-
cell: OnceLock<T>,
47-
init: Cell<Option<F>>,
59+
once: Once,
60+
data: UnsafeCell<Data<T, F>>,
4861
}
62+
4963
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
5064
/// Creates a new lazy value with the given initializing
5165
/// function.
5266
#[inline]
5367
#[unstable(feature = "once_cell", issue = "74465")]
5468
pub const fn new(f: F) -> LazyLock<T, F> {
55-
LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
69+
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
5670
}
5771

5872
/// Forces the evaluation of this lazy value and
@@ -74,10 +88,50 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
7488
#[inline]
7589
#[unstable(feature = "once_cell", issue = "74465")]
7690
pub fn force(this: &LazyLock<T, F>) -> &T {
77-
this.cell.get_or_init(|| match this.init.take() {
78-
Some(f) => f(),
79-
None => panic!("Lazy instance has previously been poisoned"),
80-
})
91+
this.once.call_once(|| {
92+
// SAFETY: `call_once` only runs this closure once, ever.
93+
let data = unsafe { &mut *this.data.get() };
94+
let f = unsafe { ManuallyDrop::take(&mut data.f) };
95+
let value = f();
96+
data.value = ManuallyDrop::new(value);
97+
});
98+
99+
// SAFETY:
100+
// There are four possible scenarios:
101+
// * the closure was called and initialized `value`.
102+
// * the closure was called and panicked, so this point is never reached.
103+
// * the closure was not called, but a previous call initialized `value`.
104+
// * the closure was not called because the Once is poisoned, so this point
105+
// is never reached.
106+
// So `value` has definitely been initialized and will not be modified again.
107+
unsafe { &*(*this.data.get()).value }
108+
}
109+
}
110+
111+
impl<T, F> LazyLock<T, F> {
112+
/// Get the inner value if it has already been initialized.
113+
fn get(&self) -> Option<&T> {
114+
if self.once.is_completed() {
115+
// SAFETY:
116+
// The closure has been run successfully, so `value` has been initialized
117+
// and will not be modified again.
118+
Some(unsafe { &*(*self.data.get()).value })
119+
} else {
120+
None
121+
}
122+
}
123+
}
124+
125+
#[unstable(feature = "once_cell", issue = "74465")]
126+
impl<T, F> Drop for LazyLock<T, F> {
127+
fn drop(&mut self) {
128+
match self.once.state() {
129+
ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) },
130+
ExclusiveState::Complete => unsafe {
131+
ManuallyDrop::drop(&mut self.data.get_mut().value)
132+
},
133+
ExclusiveState::Poisoned => {}
134+
}
81135
}
82136
}
83137

@@ -103,23 +157,23 @@ impl<T: Default> Default for LazyLock<T> {
103157
#[unstable(feature = "once_cell", issue = "74465")]
104158
impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
105159
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106-
f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
160+
match self.get() {
161+
Some(v) => f.debug_tuple("LazyLock").field(v).finish(),
162+
None => f.write_str("LazyLock(Uninit)"),
163+
}
107164
}
108165
}
109166

110167
// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
111168
// to not impl `Sync` for `F`
112-
// we do create a `&mut Option<F>` in `force`, but this is
113-
// properly synchronized, so it only happens once
114-
// so it also does not contribute to this impl.
115169
#[unstable(feature = "once_cell", issue = "74465")]
116-
unsafe impl<T, F: Send> Sync for LazyLock<T, F> where OnceLock<T>: Sync {}
170+
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
117171
// auto-derived `Send` impl is OK.
118172

119173
#[unstable(feature = "once_cell", issue = "74465")]
120-
impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {}
174+
impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
121175
#[unstable(feature = "once_cell", issue = "74465")]
122-
impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: UnwindSafe {}
176+
impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}
123177

124178
#[cfg(test)]
125179
mod tests;

std/src/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ mod condvar;
186186
mod lazy_lock;
187187
mod mpmc;
188188
mod mutex;
189-
mod once;
189+
pub(crate) mod once;
190190
mod once_lock;
191191
mod poison;
192192
mod remutex;

std/src/sync/once.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ pub struct OnceState {
4343
pub(crate) inner: sys::OnceState,
4444
}
4545

46+
pub(crate) enum ExclusiveState {
47+
Incomplete,
48+
Poisoned,
49+
Complete,
50+
}
51+
4652
/// Initialization value for static [`Once`] values.
4753
///
4854
/// # Examples
@@ -248,6 +254,16 @@ impl Once {
248254
pub fn is_completed(&self) -> bool {
249255
self.inner.is_completed()
250256
}
257+
258+
/// Returns the current state of the `Once` instance.
259+
///
260+
/// Since this takes a mutable reference, no initialization can currently
261+
/// be running, so the state must be either "incomplete", "poisoned" or
262+
/// "complete".
263+
#[inline]
264+
pub(crate) fn state(&mut self) -> ExclusiveState {
265+
self.inner.state()
266+
}
251267
}
252268

253269
#[stable(feature = "std_debug", since = "1.16.0")]

std/src/sys/hermit/thread.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ impl Thread {
2727
p: Box<dyn FnOnce()>,
2828
core_id: isize,
2929
) -> io::Result<Thread> {
30-
let p = Box::into_raw(box p);
30+
let p = Box::into_raw(Box::new(p));
3131
let tid = abi::spawn2(
3232
thread_start,
33-
p as usize,
33+
p.expose_addr(),
3434
abi::Priority::into(abi::NORMAL_PRIO),
3535
stack,
3636
core_id,

0 commit comments

Comments
 (0)