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