|
19 | 19 | //! `Acquire` and `Release` have very little performance overhead on most |
20 | 20 | //! architectures versus `Relaxed`. |
21 | 21 |
|
| 22 | +// The "atomic orderings" section of the documentation above promises |
| 23 | +// "happens-before" semantics. This drives the choice of orderings in the uses |
| 24 | +// of `compare_exchange` below. On success, the value was zero/null, so there |
| 25 | +// was nothing to acquire (there is never any `Ordering::Release` store of 0). |
| 26 | +// On failure, the value was nonzero, so it was initialized previously (perhaps |
| 27 | +// on another thread) using `Ordering::Release`, so we must use |
| 28 | +// `Ordering::Acquire` to ensure that store "happens-before" this load. |
| 29 | + |
22 | 30 | #[cfg(not(feature = "portable-atomic"))] |
23 | 31 | use core::sync::atomic; |
24 | 32 | #[cfg(feature = "portable-atomic")] |
@@ -98,7 +106,7 @@ impl OnceNonZeroUsize { |
98 | 106 | #[inline] |
99 | 107 | pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { |
100 | 108 | let exchange = |
101 | | - self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire); |
| 109 | + self.inner.compare_exchange(0, value.get(), Ordering::Release, Ordering::Acquire); |
102 | 110 | match exchange { |
103 | 111 | Ok(_) => Ok(()), |
104 | 112 | Err(_) => Err(()), |
@@ -144,7 +152,7 @@ impl OnceNonZeroUsize { |
144 | 152 | #[inline(never)] |
145 | 153 | fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> { |
146 | 154 | let mut val = f()?.get(); |
147 | | - let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire); |
| 155 | + let exchange = self.inner.compare_exchange(0, val, Ordering::Release, Ordering::Acquire); |
148 | 156 | if let Err(old) = exchange { |
149 | 157 | val = old; |
150 | 158 | } |
@@ -258,7 +266,7 @@ impl<'a, T> OnceRef<'a, T> { |
258 | 266 | pub fn set(&self, value: &'a T) -> Result<(), ()> { |
259 | 267 | let ptr = value as *const T as *mut T; |
260 | 268 | let exchange = |
261 | | - self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire); |
| 269 | + self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::Release, Ordering::Acquire); |
262 | 270 | match exchange { |
263 | 271 | Ok(_) => Ok(()), |
264 | 272 | Err(_) => Err(()), |
@@ -301,7 +309,7 @@ impl<'a, T> OnceRef<'a, T> { |
301 | 309 | let exchange = self.inner.compare_exchange( |
302 | 310 | ptr::null_mut(), |
303 | 311 | ptr, |
304 | | - Ordering::AcqRel, |
| 312 | + Ordering::Release, |
305 | 313 | Ordering::Acquire, |
306 | 314 | ); |
307 | 315 | if let Err(old) = exchange { |
@@ -396,7 +404,7 @@ mod once_box { |
396 | 404 | let exchange = self.inner.compare_exchange( |
397 | 405 | ptr::null_mut(), |
398 | 406 | ptr, |
399 | | - Ordering::AcqRel, |
| 407 | + Ordering::Release, |
400 | 408 | Ordering::Acquire, |
401 | 409 | ); |
402 | 410 | if exchange.is_err() { |
@@ -442,7 +450,7 @@ mod once_box { |
442 | 450 | let exchange = self.inner.compare_exchange( |
443 | 451 | ptr::null_mut(), |
444 | 452 | ptr, |
445 | | - Ordering::AcqRel, |
| 453 | + Ordering::Release, |
446 | 454 | Ordering::Acquire, |
447 | 455 | ); |
448 | 456 | if let Err(old) = exchange { |
|
0 commit comments