Relax memory ordering in AtomicCell::replace (#83)

This commit is contained in:
Taiki Endo 2023-09-10 23:49:32 +09:00 committed by GitHub
parent 450942e773
commit 7bbabd02f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 10 additions and 2 deletions

View File

@ -218,12 +218,20 @@ impl<T> AtomicCell<T> {
/// Swap the value out.
fn replace(&self, value: Option<Box<T>>) -> Option<Box<T>> {
let value = value.map_or(ptr::null_mut(), |value| Box::into_raw(value));
let old_value = self.0.swap(value, Ordering::SeqCst);
let old_value = match value {
Some(value) => self.0.swap(Box::into_raw(value), Ordering::AcqRel),
// Acquire is needed to synchronize with the store of a non-null ptr, but since a null ptr
// will never be dereferenced, there is no need to synchronize the store of a null ptr.
None => self.0.swap(ptr::null_mut(), Ordering::Acquire),
};
if old_value.is_null() {
None
} else {
// SAFETY:
// - AcqRel/Acquire ensures that it does not read a pointer to potentially invalid memory.
// - We've checked that old_value is not null.
// - We do not store invalid pointers other than null in self.0.
Some(unsafe { Box::from_raw(old_value) })
}
}