use shuttle::scheduler::DfsScheduler;
use shuttle::sync::Mutex;
use shuttle::{thread, Config, MaxSteps, Runner};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use test_log::test;
fn max_steps(n: usize) -> Config {
let mut config = Config::new();
config.max_steps = MaxSteps::ContinueAfter(n);
config
}
#[test]
fn trivial_one_thread() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 1);
}
#[test]
fn trivial_two_threads() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
thread::spawn(|| {});
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 2);
}
fn two_threads_work(counter: &Arc<AtomicUsize>) {
counter.fetch_add(1, Ordering::SeqCst);
let lock = Arc::new(Mutex::new(0));
{
let lock = Arc::clone(&lock);
thread::spawn(move || {
let mut l = lock.lock().unwrap();
*l += 1;
});
}
let mut l = lock.lock().unwrap();
*l += 1;
}
#[test]
fn two_threads() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || two_threads_work(&counter));
}
assert_eq!(iterations.load(Ordering::SeqCst), 16);
}
#[test]
fn two_threads_depth_4() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, max_steps(4));
runner.run(move || two_threads_work(&counter));
}
assert_eq!(iterations.load(Ordering::SeqCst), 6);
}
#[test]
fn two_threads_depth_5() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, max_steps(5));
runner.run(move || two_threads_work(&counter));
}
assert_eq!(iterations.load(Ordering::SeqCst), 10);
}
#[test]
fn yield_loop_one_thread() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
thread::spawn(|| {
for _ in 0..4 {
thread::yield_now();
}
});
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 6);
}
#[test]
fn yield_loop_two_threads() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
thread::spawn(|| {
for _ in 0..4 {
thread::yield_now();
}
});
for _ in 0..4 {
thread::yield_now();
}
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 252);
}
#[test]
fn yield_loop_two_threads_bounded() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(Some(100), false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
thread::spawn(|| {
for _ in 0..4 {
thread::yield_now();
}
});
for _ in 0..4 {
thread::yield_now();
}
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 100);
}
#[test]
fn yield_loop_three_threads() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, Default::default());
runner.run(move || {
counter.fetch_add(1, Ordering::SeqCst);
thread::spawn(|| {
for _ in 0..3 {
thread::yield_now();
}
});
thread::spawn(|| {
for _ in 0..3 {
thread::yield_now();
}
});
for _ in 0..3 {
thread::yield_now();
}
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 50050);
}
#[test]
fn yield_loop_max_depth() {
let iterations = Arc::new(AtomicUsize::new(0));
{
let counter = Arc::clone(&iterations);
let scheduler = DfsScheduler::new(None, false);
let runner = Runner::new(scheduler, max_steps(20));
runner.run(move || {
for _ in 0..100 {
counter.fetch_add(1, Ordering::SeqCst);
thread::yield_now();
}
});
}
assert_eq!(iterations.load(Ordering::SeqCst), 20);
}