[go: up one dir, main page]

loom 0.2.5

Permutation testing for concurrent code
Documentation
#![deny(warnings, rust_2018_idioms)]

use loom;

use loom::sync::atomic::AtomicUsize;
use loom::thread;

use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use std::sync::Arc;

#[test]
fn valid() {
    struct Inc {
        num: AtomicUsize,
    }

    impl Inc {
        fn new() -> Inc {
            Inc {
                num: AtomicUsize::new(0),
            }
        }

        fn inc(&self) {
            let mut curr = self.num.load(Relaxed);

            loop {
                let actual = self.num.compare_and_swap(curr, curr + 1, Relaxed);

                if actual == curr {
                    return;
                }

                curr = actual;
            }
        }
    }

    loom::model(|| {
        let inc = Arc::new(Inc::new());

        let ths: Vec<_> = (0..2)
            .map(|_| {
                let inc = inc.clone();
                thread::spawn(move || {
                    inc.inc();
                })
            })
            .collect();

        for th in ths {
            th.join().unwrap();
        }

        assert_eq!(2, inc.num.load(Relaxed));
    });
}

#[test]
#[should_panic]
fn checks_fail() {
    struct BuggyInc {
        num: AtomicUsize,
    }

    impl BuggyInc {
        fn new() -> BuggyInc {
            BuggyInc {
                num: AtomicUsize::new(0),
            }
        }

        fn inc(&self) {
            let curr = self.num.load(Acquire);
            self.num.store(curr + 1, Release);
        }
    }

    loom::model(|| {
        let buggy_inc = Arc::new(BuggyInc::new());

        let ths: Vec<_> = (0..2)
            .map(|_| {
                let buggy_inc = buggy_inc.clone();
                thread::spawn(move || buggy_inc.inc())
            })
            .collect();

        for th in ths {
            th.join().unwrap();
        }

        assert_eq!(2, buggy_inc.num.load(Relaxed));
    });
}

#[test]
#[should_panic]
fn check_ordering() {
    loom::model(|| {
        let n1 = Arc::new((AtomicUsize::new(0), AtomicUsize::new(0)));
        let n2 = n1.clone();

        thread::spawn(move || {
            n1.0.store(1, Relaxed);
            n1.1.store(1, Relaxed);
        });

        if 1 == n2.1.load(Relaxed) {
            assert_eq!(1, n2.0.load(Relaxed));
        }
    });
}