blob: 47ad46d3a1c4114b8d9f38dd61798f0798ccdaf5 [file] [log] [blame]
use crate::util::slab::TransferStack;
use loom::cell::UnsafeCell;
use loom::sync::Arc;
use loom::thread;
#[test]
fn transfer_stack() {
loom::model(|| {
let causalities = [UnsafeCell::new(None), UnsafeCell::new(None)];
let shared = Arc::new((causalities, TransferStack::new()));
let shared1 = shared.clone();
let shared2 = shared.clone();
// Spawn two threads that both try to push to the stack.
let t1 = thread::spawn(move || {
let (causalities, stack) = &*shared1;
stack.push(0, |prev| {
causalities[0].with_mut(|c| unsafe {
*c = Some(prev);
});
});
});
let t2 = thread::spawn(move || {
let (causalities, stack) = &*shared2;
stack.push(1, |prev| {
causalities[1].with_mut(|c| unsafe {
*c = Some(prev);
});
});
});
let (causalities, stack) = &*shared;
// Try to pop from the stack...
let mut idx = stack.pop_all();
while idx == None {
idx = stack.pop_all();
thread::yield_now();
}
let idx = idx.unwrap();
let saw_both = causalities[idx].with(|val| {
let val = unsafe { *val };
assert!(
val.is_some(),
"UnsafeCell write must happen-before index is pushed to the stack!",
);
// were there two entries in the stack? if so, check that
// both saw a write.
if let Some(c) = causalities.get(val.unwrap()) {
c.with(|val| {
let val = unsafe { *val };
assert!(
val.is_some(),
"UnsafeCell write must happen-before index is pushed to the stack!",
);
});
true
} else {
false
}
});
// We only saw one push. Ensure that the other push happens too.
if !saw_both {
// Try to pop from the stack...
let mut idx = stack.pop_all();
while idx == None {
idx = stack.pop_all();
thread::yield_now();
}
let idx = idx.unwrap();
causalities[idx].with(|val| {
let val = unsafe { *val };
assert!(
val.is_some(),
"UnsafeCell write must happen-before index is pushed to the stack!",
);
});
}
t1.join().unwrap();
t2.join().unwrap();
});
}