crossbeam_utils/atomic/atomic_cell.rs
1// Necessary for implementing atomic methods for `AtomicUnit`
2#![allow(clippy::unit_arg)]
3
4use crate::primitive::sync::atomic::{self, Ordering};
5use crate::CachePadded;
6use core::cell::UnsafeCell;
7use core::cmp;
8use core::fmt;
9use core::mem::{self, ManuallyDrop, MaybeUninit};
10use core::panic::{RefUnwindSafe, UnwindSafe};
11use core::ptr;
12
13use super::seq_lock::SeqLock;
14
15/// A thread-safe mutable memory location.
16///
17/// This type is equivalent to [`Cell`], except it can also be shared among multiple threads.
18///
19/// Operations on `AtomicCell`s use atomic instructions whenever possible, and synchronize using
20/// global locks otherwise. You can call [`AtomicCell::<T>::is_lock_free()`] to check whether
21/// atomic instructions or locks will be used.
22///
23/// Atomic loads use the [`Acquire`] ordering and atomic stores use the [`Release`] ordering.
24///
25/// [`Cell`]: std::cell::Cell
26/// [`AtomicCell::<T>::is_lock_free()`]: AtomicCell::is_lock_free
27/// [`Acquire`]: std::sync::atomic::Ordering::Acquire
28/// [`Release`]: std::sync::atomic::Ordering::Release
29#[repr(transparent)]
30pub struct AtomicCell<T> {
31 /// The inner value.
32 ///
33 /// If this value can be transmuted into a primitive atomic type, it will be treated as such.
34 /// Otherwise, all potentially concurrent operations on this data will be protected by a global
35 /// lock.
36 ///
37 /// Using MaybeUninit to prevent code outside the cell from observing partially initialized state:
38 /// <https://github.com/crossbeam-rs/crossbeam/issues/833>
39 /// (This rustc bug has been fixed in Rust 1.64.)
40 ///
41 /// Note:
42 /// - we'll never store uninitialized `T` due to our API only using initialized `T`.
43 /// - this `MaybeUninit` does *not* fix <https://github.com/crossbeam-rs/crossbeam/issues/315>.
44 value: UnsafeCell<MaybeUninit<T>>,
45}
46
47unsafe impl<T: Send> Send for AtomicCell<T> {}
48unsafe impl<T: Send> Sync for AtomicCell<T> {}
49
50impl<T> UnwindSafe for AtomicCell<T> {}
51impl<T> RefUnwindSafe for AtomicCell<T> {}
52
53impl<T> AtomicCell<T> {
54 /// Creates a new atomic cell initialized with `val`.
55 ///
56 /// # Examples
57 ///
58 /// ```
59 /// use crossbeam_utils::atomic::AtomicCell;
60 ///
61 /// let a = AtomicCell::new(7);
62 /// ```
63 pub const fn new(val: T) -> AtomicCell<T> {
64 AtomicCell {
65 value: UnsafeCell::new(MaybeUninit::new(val)),
66 }
67 }
68
69 /// Consumes the atomic and returns the contained value.
70 ///
71 /// This is safe because passing `self` by value guarantees that no other threads are
72 /// concurrently accessing the atomic data.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use crossbeam_utils::atomic::AtomicCell;
78 ///
79 /// let a = AtomicCell::new(7);
80 /// let v = a.into_inner();
81 ///
82 /// assert_eq!(v, 7);
83 /// ```
84 pub const fn into_inner(self) -> T {
85 // HACK: This is equivalent to transmute_copy by value, but available in const
86 // context even on older rustc (const transmute_copy requires Rust 1.74), and
87 // can work around "cannot borrow here, since the borrowed element may contain
88 // interior mutability" error occurs (until const_refs_to_cell stabilized, i.e.,
89 // Rust 1.83) when using transmute_copy with generic type in const context
90 // (because this is a by-value transmutation that doesn't create a reference to
91 // the source value).
92 /// # Safety
93 ///
94 /// This function has the same safety requirements as [`core::mem::transmute_copy`].
95 ///
96 /// Since this is a by-value transmutation, it copies the bits from the source value
97 /// into the destination value, then forgets the original, as with the [`core::mem::transmute`].
98 #[inline]
99 #[must_use]
100 const unsafe fn transmute_copy_by_val<Src, Dst>(src: Src) -> Dst {
101 #[repr(C)]
102 union ConstHack<Src, Dst> {
103 src: ManuallyDrop<Src>,
104 dst: ManuallyDrop<Dst>,
105 }
106 assert!(mem::size_of::<Src>() >= mem::size_of::<Dst>()); // assertion copied from transmute_copy
107 // SAFETY: ConstHack is #[repr(C)] union, and the caller must guarantee that
108 // transmuting Src to Dst is safe.
109 ManuallyDrop::into_inner(
110 ConstHack::<Src, Dst> {
111 src: ManuallyDrop::new(src),
112 }
113 .dst,
114 )
115 }
116
117 // SAFETY:
118 // - Self is repr(transparent) over `UnsafeCell<MaybeUninit<T>>` and
119 // `UnsafeCell<MaybeUninit<T>>` and `T` has the same layout.
120 // - passing `self` by value guarantees that no other threads are concurrently
121 // accessing the atomic data
122 // (Equivalent to UnsafeCell::into_inner which is unstable in const context.)
123 unsafe { transmute_copy_by_val(self) }
124 }
125
126 /// Returns `true` if operations on values of this type are lock-free.
127 ///
128 /// If the compiler or the platform doesn't support the necessary atomic instructions,
129 /// `AtomicCell<T>` will use global locks for every potentially concurrent atomic operation.
130 ///
131 /// # Examples
132 ///
133 /// ```
134 /// use crossbeam_utils::atomic::AtomicCell;
135 ///
136 /// // This type is internally represented as `AtomicUsize` so we can just use atomic
137 /// // operations provided by it.
138 /// assert_eq!(AtomicCell::<usize>::is_lock_free(), true);
139 ///
140 /// // A wrapper struct around `isize`.
141 /// struct Foo {
142 /// bar: isize,
143 /// }
144 /// // `AtomicCell<Foo>` will be internally represented as `AtomicIsize`.
145 /// assert_eq!(AtomicCell::<Foo>::is_lock_free(), true);
146 ///
147 /// // Operations on zero-sized types are always lock-free.
148 /// assert_eq!(AtomicCell::<()>::is_lock_free(), true);
149 ///
150 /// // Very large types cannot be represented as any of the standard atomic types, so atomic
151 /// // operations on them will have to use global locks for synchronization.
152 /// assert_eq!(AtomicCell::<[u8; 1000]>::is_lock_free(), false);
153 /// ```
154 pub const fn is_lock_free() -> bool {
155 atomic_is_lock_free::<T>()
156 }
157
158 /// Stores `val` into the atomic cell.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use crossbeam_utils::atomic::AtomicCell;
164 ///
165 /// let a = AtomicCell::new(7);
166 ///
167 /// assert_eq!(a.load(), 7);
168 /// a.store(8);
169 /// assert_eq!(a.load(), 8);
170 /// ```
171 pub fn store(&self, val: T) {
172 if mem::needs_drop::<T>() {
173 drop(self.swap(val));
174 } else {
175 unsafe {
176 atomic_store(self.as_ptr(), val);
177 }
178 }
179 }
180
181 /// Stores `val` into the atomic cell and returns the previous value.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// use crossbeam_utils::atomic::AtomicCell;
187 ///
188 /// let a = AtomicCell::new(7);
189 ///
190 /// assert_eq!(a.load(), 7);
191 /// assert_eq!(a.swap(8), 7);
192 /// assert_eq!(a.load(), 8);
193 /// ```
194 pub fn swap(&self, val: T) -> T {
195 unsafe { atomic_swap(self.as_ptr(), val) }
196 }
197
198 /// Returns a raw pointer to the underlying data in this atomic cell.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// use crossbeam_utils::atomic::AtomicCell;
204 ///
205 /// let a = AtomicCell::new(5);
206 ///
207 /// let ptr = a.as_ptr();
208 /// ```
209 #[inline]
210 pub const fn as_ptr(&self) -> *mut T {
211 self.value.get().cast::<T>()
212 }
213}
214
215impl<T: Default> AtomicCell<T> {
216 /// Takes the value of the atomic cell, leaving `Default::default()` in its place.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// use crossbeam_utils::atomic::AtomicCell;
222 ///
223 /// let a = AtomicCell::new(5);
224 /// let five = a.take();
225 ///
226 /// assert_eq!(five, 5);
227 /// assert_eq!(a.into_inner(), 0);
228 /// ```
229 pub fn take(&self) -> T {
230 self.swap(Default::default())
231 }
232}
233
234impl<T: Copy> AtomicCell<T> {
235 /// Loads a value from the atomic cell.
236 ///
237 /// # Examples
238 ///
239 /// ```
240 /// use crossbeam_utils::atomic::AtomicCell;
241 ///
242 /// let a = AtomicCell::new(7);
243 ///
244 /// assert_eq!(a.load(), 7);
245 /// ```
246 pub fn load(&self) -> T {
247 unsafe { atomic_load(self.as_ptr()) }
248 }
249}
250
251impl<T: Copy + Eq> AtomicCell<T> {
252 /// If the current value equals `current`, stores `new` into the atomic cell.
253 ///
254 /// The return value is always the previous value. If it is equal to `current`, then the value
255 /// was updated.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// # #![allow(deprecated)]
261 /// use crossbeam_utils::atomic::AtomicCell;
262 ///
263 /// let a = AtomicCell::new(1);
264 ///
265 /// assert_eq!(a.compare_and_swap(2, 3), 1);
266 /// assert_eq!(a.load(), 1);
267 ///
268 /// assert_eq!(a.compare_and_swap(1, 2), 1);
269 /// assert_eq!(a.load(), 2);
270 /// ```
271 // TODO: remove in the next major version.
272 #[deprecated(note = "Use `compare_exchange` instead")]
273 pub fn compare_and_swap(&self, current: T, new: T) -> T {
274 match self.compare_exchange(current, new) {
275 Ok(v) => v,
276 Err(v) => v,
277 }
278 }
279
280 /// If the current value equals `current`, stores `new` into the atomic cell.
281 ///
282 /// The return value is a result indicating whether the new value was written and containing
283 /// the previous value. On success this value is guaranteed to be equal to `current`.
284 ///
285 /// # Examples
286 ///
287 /// ```
288 /// use crossbeam_utils::atomic::AtomicCell;
289 ///
290 /// let a = AtomicCell::new(1);
291 ///
292 /// assert_eq!(a.compare_exchange(2, 3), Err(1));
293 /// assert_eq!(a.load(), 1);
294 ///
295 /// assert_eq!(a.compare_exchange(1, 2), Ok(1));
296 /// assert_eq!(a.load(), 2);
297 /// ```
298 pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> {
299 unsafe { atomic_compare_exchange_weak(self.as_ptr(), current, new) }
300 }
301
302 /// Fetches the value, and applies a function to it that returns an optional
303 /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
304 /// `Err(previous_value)`.
305 ///
306 /// Note: This may call the function multiple times if the value has been changed from other threads in
307 /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
308 /// only once to the stored value.
309 ///
310 /// # Examples
311 ///
312 /// ```rust
313 /// use crossbeam_utils::atomic::AtomicCell;
314 ///
315 /// let a = AtomicCell::new(7);
316 /// assert_eq!(a.fetch_update(|_| None), Err(7));
317 /// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(7));
318 /// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(8));
319 /// assert_eq!(a.load(), 9);
320 /// ```
321 #[inline]
322 pub fn fetch_update<F>(&self, mut f: F) -> Result<T, T>
323 where
324 F: FnMut(T) -> Option<T>,
325 {
326 let mut prev = self.load();
327 while let Some(next) = f(prev) {
328 match self.compare_exchange(prev, next) {
329 x @ Ok(_) => return x,
330 Err(next_prev) => prev = next_prev,
331 }
332 }
333 Err(prev)
334 }
335}
336
337// `MaybeUninit` prevents `T` from being dropped, so we need to implement `Drop`
338// for `AtomicCell` to avoid leaks of non-`Copy` types.
339impl<T> Drop for AtomicCell<T> {
340 fn drop(&mut self) {
341 if mem::needs_drop::<T>() {
342 // SAFETY:
343 // - the mutable reference guarantees that no other threads are concurrently accessing the atomic data
344 // - the raw pointer passed in is valid because we got it from a reference
345 // - `MaybeUninit` prevents double dropping `T`
346 unsafe {
347 self.as_ptr().drop_in_place();
348 }
349 }
350 }
351}
352
353macro_rules! atomic {
354 // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`,
355 // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop.
356 (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => {
357 if can_transmute::<$t, $atomic>() {
358 let $a: &$atomic;
359 break $atomic_op;
360 }
361 };
362
363 // If values of type `$t` can be transmuted into values of a primitive atomic type, declares
364 // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes
365 // `$fallback_op`.
366 ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => {
367 loop {
368 atomic!(@check, $t, AtomicUnit, $a, $atomic_op);
369
370 atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op);
371 atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op);
372 atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op);
373 #[cfg(target_has_atomic = "64")]
374 atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op);
375 // TODO: AtomicU128 is unstable
376 // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op);
377
378 break $fallback_op;
379 }
380 };
381}
382
383macro_rules! impl_arithmetic {
384 ($t:ty, fallback, $example:tt) => {
385 impl AtomicCell<$t> {
386 /// Increments the current value by `val` and returns the previous value.
387 ///
388 /// The addition wraps on overflow.
389 ///
390 /// # Examples
391 ///
392 /// ```
393 /// use crossbeam_utils::atomic::AtomicCell;
394 ///
395 #[doc = $example]
396 ///
397 /// assert_eq!(a.fetch_add(3), 7);
398 /// assert_eq!(a.load(), 10);
399 /// ```
400 #[inline]
401 pub fn fetch_add(&self, val: $t) -> $t {
402 let _guard = lock(self.as_ptr() as usize).write();
403 let value = unsafe { &mut *(self.as_ptr()) };
404 let old = *value;
405 *value = value.wrapping_add(val);
406 old
407 }
408
409 /// Decrements the current value by `val` and returns the previous value.
410 ///
411 /// The subtraction wraps on overflow.
412 ///
413 /// # Examples
414 ///
415 /// ```
416 /// use crossbeam_utils::atomic::AtomicCell;
417 ///
418 #[doc = $example]
419 ///
420 /// assert_eq!(a.fetch_sub(3), 7);
421 /// assert_eq!(a.load(), 4);
422 /// ```
423 #[inline]
424 pub fn fetch_sub(&self, val: $t) -> $t {
425 let _guard = lock(self.as_ptr() as usize).write();
426 let value = unsafe { &mut *(self.as_ptr()) };
427 let old = *value;
428 *value = value.wrapping_sub(val);
429 old
430 }
431
432 /// Applies bitwise "and" to the current value and returns the previous value.
433 ///
434 /// # Examples
435 ///
436 /// ```
437 /// use crossbeam_utils::atomic::AtomicCell;
438 ///
439 #[doc = $example]
440 ///
441 /// assert_eq!(a.fetch_and(3), 7);
442 /// assert_eq!(a.load(), 3);
443 /// ```
444 #[inline]
445 pub fn fetch_and(&self, val: $t) -> $t {
446 let _guard = lock(self.as_ptr() as usize).write();
447 let value = unsafe { &mut *(self.as_ptr()) };
448 let old = *value;
449 *value &= val;
450 old
451 }
452
453 /// Applies bitwise "nand" to the current value and returns the previous value.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// use crossbeam_utils::atomic::AtomicCell;
459 ///
460 #[doc = $example]
461 ///
462 /// assert_eq!(a.fetch_nand(3), 7);
463 /// assert_eq!(a.load(), !(7 & 3));
464 /// ```
465 #[inline]
466 pub fn fetch_nand(&self, val: $t) -> $t {
467 let _guard = lock(self.as_ptr() as usize).write();
468 let value = unsafe { &mut *(self.as_ptr()) };
469 let old = *value;
470 *value = !(old & val);
471 old
472 }
473
474 /// Applies bitwise "or" to the current value and returns the previous value.
475 ///
476 /// # Examples
477 ///
478 /// ```
479 /// use crossbeam_utils::atomic::AtomicCell;
480 ///
481 #[doc = $example]
482 ///
483 /// assert_eq!(a.fetch_or(16), 7);
484 /// assert_eq!(a.load(), 23);
485 /// ```
486 #[inline]
487 pub fn fetch_or(&self, val: $t) -> $t {
488 let _guard = lock(self.as_ptr() as usize).write();
489 let value = unsafe { &mut *(self.as_ptr()) };
490 let old = *value;
491 *value |= val;
492 old
493 }
494
495 /// Applies bitwise "xor" to the current value and returns the previous value.
496 ///
497 /// # Examples
498 ///
499 /// ```
500 /// use crossbeam_utils::atomic::AtomicCell;
501 ///
502 #[doc = $example]
503 ///
504 /// assert_eq!(a.fetch_xor(2), 7);
505 /// assert_eq!(a.load(), 5);
506 /// ```
507 #[inline]
508 pub fn fetch_xor(&self, val: $t) -> $t {
509 let _guard = lock(self.as_ptr() as usize).write();
510 let value = unsafe { &mut *(self.as_ptr()) };
511 let old = *value;
512 *value ^= val;
513 old
514 }
515
516 /// Compares and sets the maximum of the current value and `val`,
517 /// and returns the previous value.
518 ///
519 /// # Examples
520 ///
521 /// ```
522 /// use crossbeam_utils::atomic::AtomicCell;
523 ///
524 #[doc = $example]
525 ///
526 /// assert_eq!(a.fetch_max(2), 7);
527 /// assert_eq!(a.load(), 7);
528 /// ```
529 #[inline]
530 pub fn fetch_max(&self, val: $t) -> $t {
531 let _guard = lock(self.as_ptr() as usize).write();
532 let value = unsafe { &mut *(self.as_ptr()) };
533 let old = *value;
534 *value = cmp::max(old, val);
535 old
536 }
537
538 /// Compares and sets the minimum of the current value and `val`,
539 /// and returns the previous value.
540 ///
541 /// # Examples
542 ///
543 /// ```
544 /// use crossbeam_utils::atomic::AtomicCell;
545 ///
546 #[doc = $example]
547 ///
548 /// assert_eq!(a.fetch_min(2), 7);
549 /// assert_eq!(a.load(), 2);
550 /// ```
551 #[inline]
552 pub fn fetch_min(&self, val: $t) -> $t {
553 let _guard = lock(self.as_ptr() as usize).write();
554 let value = unsafe { &mut *(self.as_ptr()) };
555 let old = *value;
556 *value = cmp::min(old, val);
557 old
558 }
559 }
560 };
561 ($t:ty, $atomic:ident, $example:tt) => {
562 impl AtomicCell<$t> {
563 /// Increments the current value by `val` and returns the previous value.
564 ///
565 /// The addition wraps on overflow.
566 ///
567 /// # Examples
568 ///
569 /// ```
570 /// use crossbeam_utils::atomic::AtomicCell;
571 ///
572 #[doc = $example]
573 ///
574 /// assert_eq!(a.fetch_add(3), 7);
575 /// assert_eq!(a.load(), 10);
576 /// ```
577 #[inline]
578 pub fn fetch_add(&self, val: $t) -> $t {
579 atomic! {
580 $t, _a,
581 {
582 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
583 a.fetch_add(val, Ordering::AcqRel)
584 },
585 {
586 let _guard = lock(self.as_ptr() as usize).write();
587 let value = unsafe { &mut *(self.as_ptr()) };
588 let old = *value;
589 *value = value.wrapping_add(val);
590 old
591 }
592 }
593 }
594
595 /// Decrements the current value by `val` and returns the previous value.
596 ///
597 /// The subtraction wraps on overflow.
598 ///
599 /// # Examples
600 ///
601 /// ```
602 /// use crossbeam_utils::atomic::AtomicCell;
603 ///
604 #[doc = $example]
605 ///
606 /// assert_eq!(a.fetch_sub(3), 7);
607 /// assert_eq!(a.load(), 4);
608 /// ```
609 #[inline]
610 pub fn fetch_sub(&self, val: $t) -> $t {
611 atomic! {
612 $t, _a,
613 {
614 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
615 a.fetch_sub(val, Ordering::AcqRel)
616 },
617 {
618 let _guard = lock(self.as_ptr() as usize).write();
619 let value = unsafe { &mut *(self.as_ptr()) };
620 let old = *value;
621 *value = value.wrapping_sub(val);
622 old
623 }
624 }
625 }
626
627 /// Applies bitwise "and" to the current value and returns the previous value.
628 ///
629 /// # Examples
630 ///
631 /// ```
632 /// use crossbeam_utils::atomic::AtomicCell;
633 ///
634 #[doc = $example]
635 ///
636 /// assert_eq!(a.fetch_and(3), 7);
637 /// assert_eq!(a.load(), 3);
638 /// ```
639 #[inline]
640 pub fn fetch_and(&self, val: $t) -> $t {
641 atomic! {
642 $t, _a,
643 {
644 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
645 a.fetch_and(val, Ordering::AcqRel)
646 },
647 {
648 let _guard = lock(self.as_ptr() as usize).write();
649 let value = unsafe { &mut *(self.as_ptr()) };
650 let old = *value;
651 *value &= val;
652 old
653 }
654 }
655 }
656
657 /// Applies bitwise "nand" to the current value and returns the previous value.
658 ///
659 /// # Examples
660 ///
661 /// ```
662 /// use crossbeam_utils::atomic::AtomicCell;
663 ///
664 #[doc = $example]
665 ///
666 /// assert_eq!(a.fetch_nand(3), 7);
667 /// assert_eq!(a.load(), !(7 & 3));
668 /// ```
669 #[inline]
670 pub fn fetch_nand(&self, val: $t) -> $t {
671 atomic! {
672 $t, _a,
673 {
674 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
675 a.fetch_nand(val, Ordering::AcqRel)
676 },
677 {
678 let _guard = lock(self.as_ptr() as usize).write();
679 let value = unsafe { &mut *(self.as_ptr()) };
680 let old = *value;
681 *value = !(old & val);
682 old
683 }
684 }
685 }
686
687 /// Applies bitwise "or" to the current value and returns the previous value.
688 ///
689 /// # Examples
690 ///
691 /// ```
692 /// use crossbeam_utils::atomic::AtomicCell;
693 ///
694 #[doc = $example]
695 ///
696 /// assert_eq!(a.fetch_or(16), 7);
697 /// assert_eq!(a.load(), 23);
698 /// ```
699 #[inline]
700 pub fn fetch_or(&self, val: $t) -> $t {
701 atomic! {
702 $t, _a,
703 {
704 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
705 a.fetch_or(val, Ordering::AcqRel)
706 },
707 {
708 let _guard = lock(self.as_ptr() as usize).write();
709 let value = unsafe { &mut *(self.as_ptr()) };
710 let old = *value;
711 *value |= val;
712 old
713 }
714 }
715 }
716
717 /// Applies bitwise "xor" to the current value and returns the previous value.
718 ///
719 /// # Examples
720 ///
721 /// ```
722 /// use crossbeam_utils::atomic::AtomicCell;
723 ///
724 #[doc = $example]
725 ///
726 /// assert_eq!(a.fetch_xor(2), 7);
727 /// assert_eq!(a.load(), 5);
728 /// ```
729 #[inline]
730 pub fn fetch_xor(&self, val: $t) -> $t {
731 atomic! {
732 $t, _a,
733 {
734 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
735 a.fetch_xor(val, Ordering::AcqRel)
736 },
737 {
738 let _guard = lock(self.as_ptr() as usize).write();
739 let value = unsafe { &mut *(self.as_ptr()) };
740 let old = *value;
741 *value ^= val;
742 old
743 }
744 }
745 }
746
747 /// Compares and sets the maximum of the current value and `val`,
748 /// and returns the previous value.
749 ///
750 /// # Examples
751 ///
752 /// ```
753 /// use crossbeam_utils::atomic::AtomicCell;
754 ///
755 #[doc = $example]
756 ///
757 /// assert_eq!(a.fetch_max(9), 7);
758 /// assert_eq!(a.load(), 9);
759 /// ```
760 #[inline]
761 pub fn fetch_max(&self, val: $t) -> $t {
762 atomic! {
763 $t, _a,
764 {
765 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
766 a.fetch_max(val, Ordering::AcqRel)
767 },
768 {
769 let _guard = lock(self.as_ptr() as usize).write();
770 let value = unsafe { &mut *(self.as_ptr()) };
771 let old = *value;
772 *value = cmp::max(old, val);
773 old
774 }
775 }
776 }
777
778 /// Compares and sets the minimum of the current value and `val`,
779 /// and returns the previous value.
780 ///
781 /// # Examples
782 ///
783 /// ```
784 /// use crossbeam_utils::atomic::AtomicCell;
785 ///
786 #[doc = $example]
787 ///
788 /// assert_eq!(a.fetch_min(2), 7);
789 /// assert_eq!(a.load(), 2);
790 /// ```
791 #[inline]
792 pub fn fetch_min(&self, val: $t) -> $t {
793 atomic! {
794 $t, _a,
795 {
796 let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) };
797 a.fetch_min(val, Ordering::AcqRel)
798 },
799 {
800 let _guard = lock(self.as_ptr() as usize).write();
801 let value = unsafe { &mut *(self.as_ptr()) };
802 let old = *value;
803 *value = cmp::min(old, val);
804 old
805 }
806 }
807 }
808 }
809 };
810}
811
812impl_arithmetic!(u8, AtomicU8, "let a = AtomicCell::new(7u8);");
813impl_arithmetic!(i8, AtomicI8, "let a = AtomicCell::new(7i8);");
814impl_arithmetic!(u16, AtomicU16, "let a = AtomicCell::new(7u16);");
815impl_arithmetic!(i16, AtomicI16, "let a = AtomicCell::new(7i16);");
816
817impl_arithmetic!(u32, AtomicU32, "let a = AtomicCell::new(7u32);");
818impl_arithmetic!(i32, AtomicI32, "let a = AtomicCell::new(7i32);");
819
820#[cfg(target_has_atomic = "64")]
821impl_arithmetic!(u64, AtomicU64, "let a = AtomicCell::new(7u64);");
822#[cfg(target_has_atomic = "64")]
823impl_arithmetic!(i64, AtomicI64, "let a = AtomicCell::new(7i64);");
824#[cfg(not(target_has_atomic = "64"))]
825impl_arithmetic!(u64, fallback, "let a = AtomicCell::new(7u64);");
826#[cfg(not(target_has_atomic = "64"))]
827impl_arithmetic!(i64, fallback, "let a = AtomicCell::new(7i64);");
828
829// TODO: AtomicU128 is unstable
830// impl_arithmetic!(u128, AtomicU128, "let a = AtomicCell::new(7u128);");
831// impl_arithmetic!(i128, AtomicI128, "let a = AtomicCell::new(7i128);");
832impl_arithmetic!(u128, fallback, "let a = AtomicCell::new(7u128);");
833impl_arithmetic!(i128, fallback, "let a = AtomicCell::new(7i128);");
834
835impl_arithmetic!(usize, AtomicUsize, "let a = AtomicCell::new(7usize);");
836impl_arithmetic!(isize, AtomicIsize, "let a = AtomicCell::new(7isize);");
837
838impl AtomicCell<bool> {
839 /// Applies logical "and" to the current value and returns the previous value.
840 ///
841 /// # Examples
842 ///
843 /// ```
844 /// use crossbeam_utils::atomic::AtomicCell;
845 ///
846 /// let a = AtomicCell::new(true);
847 ///
848 /// assert_eq!(a.fetch_and(true), true);
849 /// assert_eq!(a.load(), true);
850 ///
851 /// assert_eq!(a.fetch_and(false), true);
852 /// assert_eq!(a.load(), false);
853 /// ```
854 #[inline]
855 pub fn fetch_and(&self, val: bool) -> bool {
856 atomic! {
857 bool, _a,
858 {
859 let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) };
860 a.fetch_and(val, Ordering::AcqRel)
861 },
862 {
863 let _guard = lock(self.as_ptr() as usize).write();
864 let value = unsafe { &mut *(self.as_ptr()) };
865 let old = *value;
866 *value &= val;
867 old
868 }
869 }
870 }
871
872 /// Applies logical "nand" to the current value and returns the previous value.
873 ///
874 /// # Examples
875 ///
876 /// ```
877 /// use crossbeam_utils::atomic::AtomicCell;
878 ///
879 /// let a = AtomicCell::new(true);
880 ///
881 /// assert_eq!(a.fetch_nand(false), true);
882 /// assert_eq!(a.load(), true);
883 ///
884 /// assert_eq!(a.fetch_nand(true), true);
885 /// assert_eq!(a.load(), false);
886 ///
887 /// assert_eq!(a.fetch_nand(false), false);
888 /// assert_eq!(a.load(), true);
889 /// ```
890 #[inline]
891 pub fn fetch_nand(&self, val: bool) -> bool {
892 atomic! {
893 bool, _a,
894 {
895 let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) };
896 a.fetch_nand(val, Ordering::AcqRel)
897 },
898 {
899 let _guard = lock(self.as_ptr() as usize).write();
900 let value = unsafe { &mut *(self.as_ptr()) };
901 let old = *value;
902 *value = !(old & val);
903 old
904 }
905 }
906 }
907
908 /// Applies logical "or" to the current value and returns the previous value.
909 ///
910 /// # Examples
911 ///
912 /// ```
913 /// use crossbeam_utils::atomic::AtomicCell;
914 ///
915 /// let a = AtomicCell::new(false);
916 ///
917 /// assert_eq!(a.fetch_or(false), false);
918 /// assert_eq!(a.load(), false);
919 ///
920 /// assert_eq!(a.fetch_or(true), false);
921 /// assert_eq!(a.load(), true);
922 /// ```
923 #[inline]
924 pub fn fetch_or(&self, val: bool) -> bool {
925 atomic! {
926 bool, _a,
927 {
928 let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) };
929 a.fetch_or(val, Ordering::AcqRel)
930 },
931 {
932 let _guard = lock(self.as_ptr() as usize).write();
933 let value = unsafe { &mut *(self.as_ptr()) };
934 let old = *value;
935 *value |= val;
936 old
937 }
938 }
939 }
940
941 /// Applies logical "xor" to the current value and returns the previous value.
942 ///
943 /// # Examples
944 ///
945 /// ```
946 /// use crossbeam_utils::atomic::AtomicCell;
947 ///
948 /// let a = AtomicCell::new(true);
949 ///
950 /// assert_eq!(a.fetch_xor(false), true);
951 /// assert_eq!(a.load(), true);
952 ///
953 /// assert_eq!(a.fetch_xor(true), true);
954 /// assert_eq!(a.load(), false);
955 /// ```
956 #[inline]
957 pub fn fetch_xor(&self, val: bool) -> bool {
958 atomic! {
959 bool, _a,
960 {
961 let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) };
962 a.fetch_xor(val, Ordering::AcqRel)
963 },
964 {
965 let _guard = lock(self.as_ptr() as usize).write();
966 let value = unsafe { &mut *(self.as_ptr()) };
967 let old = *value;
968 *value ^= val;
969 old
970 }
971 }
972 }
973}
974
975impl<T: Default> Default for AtomicCell<T> {
976 fn default() -> AtomicCell<T> {
977 AtomicCell::new(T::default())
978 }
979}
980
981impl<T> From<T> for AtomicCell<T> {
982 #[inline]
983 fn from(val: T) -> AtomicCell<T> {
984 AtomicCell::new(val)
985 }
986}
987
988impl<T: Copy + fmt::Debug> fmt::Debug for AtomicCell<T> {
989 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
990 f.debug_struct("AtomicCell")
991 .field("value", &self.load())
992 .finish()
993 }
994}
995
996/// Returns `true` if values of type `A` can be transmuted into values of type `B`.
997const fn can_transmute<A, B>() -> bool {
998 // Sizes must be equal, but alignment of `A` must be greater or equal than that of `B`.
999 (mem::size_of::<A>() == mem::size_of::<B>()) & (mem::align_of::<A>() >= mem::align_of::<B>())
1000}
1001
1002/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`.
1003///
1004/// This function is used to protect atomic data which doesn't fit into any of the primitive atomic
1005/// types in `std::sync::atomic`. Operations on such atomics must therefore use a global lock.
1006///
1007/// However, there is not only one global lock but an array of many locks, and one of them is
1008/// picked based on the given address. Having many locks reduces contention and improves
1009/// scalability.
1010#[inline]
1011#[must_use]
1012fn lock(addr: usize) -> &'static SeqLock {
1013 // The number of locks is a prime number because we want to make sure `addr % LEN` gets
1014 // dispersed across all locks.
1015 //
1016 // Note that addresses are always aligned to some power of 2, depending on type `T` in
1017 // `AtomicCell<T>`. If `LEN` was an even number, then `addr % LEN` would be an even number,
1018 // too, which means only half of the locks would get utilized!
1019 //
1020 // It is also possible for addresses to accidentally get aligned to a number that is not a
1021 // power of 2. Consider this example:
1022 //
1023 // ```
1024 // #[repr(C)]
1025 // struct Foo {
1026 // a: AtomicCell<u8>,
1027 // b: u8,
1028 // c: u8,
1029 // }
1030 // ```
1031 //
1032 // Now, if we have a slice of type `&[Foo]`, it is possible that field `a` in all items gets
1033 // stored at addresses that are multiples of 3. It'd be too bad if `LEN` was divisible by 3.
1034 // In order to protect from such cases, we simply choose a large prime number for `LEN`.
1035 const LEN: usize = 67;
1036 const L: CachePadded<SeqLock> = CachePadded::new(SeqLock::new());
1037 static LOCKS: [CachePadded<SeqLock>; LEN] = [L; LEN];
1038
1039 // If the modulus is a constant number, the compiler will use crazy math to transform this into
1040 // a sequence of cheap arithmetic operations rather than using the slow modulo instruction.
1041 &LOCKS[addr % LEN]
1042}
1043
1044/// An atomic `()`.
1045///
1046/// All operations are noops.
1047struct AtomicUnit;
1048
1049impl AtomicUnit {
1050 #[inline]
1051 fn load(&self, _order: Ordering) {}
1052
1053 #[inline]
1054 fn store(&self, _val: (), _order: Ordering) {}
1055
1056 #[inline]
1057 fn swap(&self, _val: (), _order: Ordering) {}
1058
1059 #[inline]
1060 fn compare_exchange_weak(
1061 &self,
1062 _current: (),
1063 _new: (),
1064 _success: Ordering,
1065 _failure: Ordering,
1066 ) -> Result<(), ()> {
1067 Ok(())
1068 }
1069}
1070
1071/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
1072const fn atomic_is_lock_free<T>() -> bool {
1073 atomic! { T, _a, true, false }
1074}
1075
1076/// Atomically reads data from `src`.
1077///
1078/// This operation uses the `Acquire` ordering. If possible, an atomic instructions is used, and a
1079/// global lock otherwise.
1080unsafe fn atomic_load<T>(src: *mut T) -> T
1081where
1082 T: Copy,
1083{
1084 atomic! {
1085 T, a,
1086 {
1087 a = &*(src as *const _ as *const _);
1088 mem::transmute_copy(&a.load(Ordering::Acquire))
1089 },
1090 {
1091 let lock = lock(src as usize);
1092
1093 // Try doing an optimistic read first.
1094 if let Some(stamp) = lock.optimistic_read() {
1095 // We need a volatile read here because other threads might concurrently modify the
1096 // value. In theory, data races are *always* UB, even if we use volatile reads and
1097 // discard the data when a data race is detected. The proper solution would be to
1098 // do atomic reads and atomic writes, but we can't atomically read and write all
1099 // kinds of data since `AtomicU8` is not available on stable Rust yet.
1100 // Load as `MaybeUninit` because we may load a value that is not valid as `T`.
1101 let val = ptr::read_volatile(src.cast::<MaybeUninit<T>>());
1102
1103 if lock.validate_read(stamp) {
1104 return val.assume_init();
1105 }
1106 }
1107
1108 // Grab a regular write lock so that writers don't starve this load.
1109 let guard = lock.write();
1110 let val = ptr::read(src);
1111 // The value hasn't been changed. Drop the guard without incrementing the stamp.
1112 guard.abort();
1113 val
1114 }
1115 }
1116}
1117
1118/// Atomically writes `val` to `dst`.
1119///
1120/// This operation uses the `Release` ordering. If possible, an atomic instructions is used, and a
1121/// global lock otherwise.
1122unsafe fn atomic_store<T>(dst: *mut T, val: T) {
1123 atomic! {
1124 T, a,
1125 {
1126 a = &*(dst as *const _ as *const _);
1127 a.store(mem::transmute_copy(&val), Ordering::Release);
1128 mem::forget(val);
1129 },
1130 {
1131 let _guard = lock(dst as usize).write();
1132 ptr::write(dst, val);
1133 }
1134 }
1135}
1136
1137/// Atomically swaps data at `dst` with `val`.
1138///
1139/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a
1140/// global lock otherwise.
1141unsafe fn atomic_swap<T>(dst: *mut T, val: T) -> T {
1142 atomic! {
1143 T, a,
1144 {
1145 a = &*(dst as *const _ as *const _);
1146 let res = mem::transmute_copy(&a.swap(mem::transmute_copy(&val), Ordering::AcqRel));
1147 mem::forget(val);
1148 res
1149 },
1150 {
1151 let _guard = lock(dst as usize).write();
1152 ptr::replace(dst, val)
1153 }
1154 }
1155}
1156
1157/// Atomically compares data at `dst` to `current` and, if equal byte-for-byte, exchanges data at
1158/// `dst` with `new`.
1159///
1160/// Returns the old value on success, or the current value at `dst` on failure.
1161///
1162/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a
1163/// global lock otherwise.
1164#[allow(clippy::let_unit_value)]
1165unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T, mut current: T, new: T) -> Result<T, T>
1166where
1167 T: Copy + Eq,
1168{
1169 atomic! {
1170 T, a,
1171 {
1172 a = &*(dst as *const _ as *const _);
1173 let mut current_raw = mem::transmute_copy(¤t);
1174 let new_raw = mem::transmute_copy(&new);
1175
1176 loop {
1177 match a.compare_exchange_weak(
1178 current_raw,
1179 new_raw,
1180 Ordering::AcqRel,
1181 Ordering::Acquire,
1182 ) {
1183 Ok(_) => break Ok(current),
1184 Err(previous_raw) => {
1185 let previous = mem::transmute_copy(&previous_raw);
1186
1187 if !T::eq(&previous, ¤t) {
1188 break Err(previous);
1189 }
1190
1191 // The compare-exchange operation has failed and didn't store `new`. The
1192 // failure is either spurious, or `previous` was semantically equal to
1193 // `current` but not byte-equal. Let's retry with `previous` as the new
1194 // `current`.
1195 current = previous;
1196 current_raw = previous_raw;
1197 }
1198 }
1199 }
1200 },
1201 {
1202 let guard = lock(dst as usize).write();
1203
1204 if T::eq(&*dst, ¤t) {
1205 Ok(ptr::replace(dst, new))
1206 } else {
1207 let val = ptr::read(dst);
1208 // The value hasn't been changed. Drop the guard without incrementing the stamp.
1209 guard.abort();
1210 Err(val)
1211 }
1212 }
1213 }
1214}