Rollup merge of #131746 - slanterns:once_box_order, r=joboet

Relax a memory order in `once_box`

per https://github.com/rust-lang/rust/pull/131094#discussion_r1788536445.

In the successful path we don't need `Acquire` since we don't care if the store in `f()` happened in other threads has become visible to the current thread. We'll use our own results instead and just using `Release` to ensure other threads can see our store to `Box` when they fail the `compare_exchange` will suffice.

Also took https://marabos.nl/atomics/memory-ordering.html#example-lazy-initialization-with-indirection as a reference.

`@rustbot` label: +T-libs

r? `@ibraheemdev`
This commit is contained in:
Urgau 2024-10-16 12:03:42 +02:00 committed by GitHub
commit 66dc09f3da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,7 +8,7 @@
use crate::mem::replace;
use crate::ptr::null_mut;
use crate::sync::atomic::AtomicPtr;
use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
pub(crate) struct OnceBox<T> {
ptr: AtomicPtr<T>,
@ -60,7 +60,7 @@ pub fn take(&mut self) -> Option<Box<T>> {
#[cold]
fn initialize(&self, f: impl FnOnce() -> Box<T>) -> &T {
let new_ptr = Box::into_raw(f());
match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
match self.ptr.compare_exchange(null_mut(), new_ptr, Release, Acquire) {
Ok(_) => unsafe { &*new_ptr },
Err(ptr) => {
// Lost the race to another thread.