1 use crate::loom::sync::atomic::AtomicUsize;
2 use crate::util::slab::Address;
3 
4 use std::fmt;
5 use std::sync::atomic::Ordering;
6 use std::usize;
7 
8 pub(super) struct TransferStack {
9     head: AtomicUsize,
10 }
11 
12 impl TransferStack {
new() -> Self13     pub(super) fn new() -> Self {
14         Self {
15             head: AtomicUsize::new(Address::NULL),
16         }
17     }
18 
pop_all(&self) -> Option<usize>19     pub(super) fn pop_all(&self) -> Option<usize> {
20         let val = self.head.swap(Address::NULL, Ordering::Acquire);
21 
22         if val == Address::NULL {
23             None
24         } else {
25             Some(val)
26         }
27     }
28 
push(&self, value: usize, before: impl Fn(usize))29     pub(super) fn push(&self, value: usize, before: impl Fn(usize)) {
30         let mut next = self.head.load(Ordering::Relaxed);
31 
32         loop {
33             before(next);
34 
35             match self
36                 .head
37                 .compare_exchange(next, value, Ordering::AcqRel, Ordering::Acquire)
38             {
39                 // lost the race!
40                 Err(actual) => next = actual,
41                 Ok(_) => return,
42             }
43         }
44     }
45 }
46 
47 impl fmt::Debug for TransferStack {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result48     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49         // Loom likes to dump all its internal state in `fmt::Debug` impls, so
50         // we override this to just print the current value in tests.
51         f.debug_struct("TransferStack")
52             .field(
53                 "head",
54                 &format_args!("{:#x}", self.head.load(Ordering::Relaxed)),
55             )
56             .finish()
57     }
58 }
59