diff options
Diffstat (limited to 'vendor/crossbeam-epoch/tests/loom.rs')
-rw-r--r-- | vendor/crossbeam-epoch/tests/loom.rs | 157 |
1 files changed, 0 insertions, 157 deletions
diff --git a/vendor/crossbeam-epoch/tests/loom.rs b/vendor/crossbeam-epoch/tests/loom.rs deleted file mode 100644 index 4e56acd..0000000 --- a/vendor/crossbeam-epoch/tests/loom.rs +++ /dev/null @@ -1,157 +0,0 @@ -#![cfg(crossbeam_loom)] - -use crossbeam_epoch as epoch; -use loom_crate as loom; - -use epoch::*; -use epoch::{Atomic, Owned}; -use loom::sync::atomic::Ordering::{self, Acquire, Relaxed, Release}; -use loom::sync::Arc; -use loom::thread::spawn; -use std::mem::ManuallyDrop; -use std::ptr; - -#[test] -fn it_works() { - loom::model(|| { - let collector = Collector::new(); - let item: Atomic<String> = Atomic::from(Owned::new(String::from("boom"))); - let item2 = item.clone(); - let collector2 = collector.clone(); - let guard = collector.register().pin(); - - let jh = loom::thread::spawn(move || { - let guard = collector2.register().pin(); - guard.defer(move || { - // this isn't really safe, since other threads may still have pointers to the - // value, but in this limited test scenario it's okay, since we know the test won't - // access item after all the pins are released. - let mut item = unsafe { item2.into_owned() }; - // mutate it as a second measure to make sure the assert_eq below would fail - item.retain(|c| c == 'o'); - drop(item); - }); - }); - - let item = item.load(Ordering::SeqCst, &guard); - // we pinned strictly before the call to defer_destroy, - // so item cannot have been dropped yet - assert_eq!(*unsafe { item.deref() }, "boom"); - drop(guard); - - jh.join().unwrap(); - - drop(collector); - }) -} - -#[test] -fn treiber_stack() { - /// Treiber's lock-free stack. - /// - /// Usable with any number of producers and consumers. - #[derive(Debug)] - pub struct TreiberStack<T> { - head: Atomic<Node<T>>, - } - - #[derive(Debug)] - struct Node<T> { - data: ManuallyDrop<T>, - next: Atomic<Node<T>>, - } - - impl<T> TreiberStack<T> { - /// Creates a new, empty stack. - pub fn new() -> TreiberStack<T> { - TreiberStack { - head: Atomic::null(), - } - } - - /// Pushes a value on top of the stack. - pub fn push(&self, t: T) { - let mut n = Owned::new(Node { - data: ManuallyDrop::new(t), - next: Atomic::null(), - }); - - let guard = epoch::pin(); - - loop { - let head = self.head.load(Relaxed, &guard); - n.next.store(head, Relaxed); - - match self - .head - .compare_exchange(head, n, Release, Relaxed, &guard) - { - Ok(_) => break, - Err(e) => n = e.new, - } - } - } - - /// Attempts to pop the top element from the stack. - /// - /// Returns `None` if the stack is empty. - pub fn pop(&self) -> Option<T> { - let guard = epoch::pin(); - loop { - let head = self.head.load(Acquire, &guard); - - match unsafe { head.as_ref() } { - Some(h) => { - let next = h.next.load(Relaxed, &guard); - - if self - .head - .compare_exchange(head, next, Relaxed, Relaxed, &guard) - .is_ok() - { - unsafe { - guard.defer_destroy(head); - return Some(ManuallyDrop::into_inner(ptr::read(&(*h).data))); - } - } - } - None => return None, - } - } - } - - /// Returns `true` if the stack is empty. - pub fn is_empty(&self) -> bool { - let guard = epoch::pin(); - self.head.load(Acquire, &guard).is_null() - } - } - - impl<T> Drop for TreiberStack<T> { - fn drop(&mut self) { - while self.pop().is_some() {} - } - } - - loom::model(|| { - let stack1 = Arc::new(TreiberStack::new()); - let stack2 = Arc::clone(&stack1); - - // use 5 since it's greater than the 4 used for the sanitize feature - let jh = spawn(move || { - for i in 0..5 { - stack2.push(i); - assert!(stack2.pop().is_some()); - } - }); - - for i in 0..5 { - stack1.push(i); - assert!(stack1.pop().is_some()); - } - - jh.join().unwrap(); - assert!(stack1.pop().is_none()); - assert!(stack1.is_empty()); - }); -} |