Crate loomy

source · []
Expand description

A shim crate to easily test code with loom.

Import common types and modules like UnsafeCell, thread, Arc, AtomicI32, etc from this crate, and run loom tests from the command line with cargo test --features loomy/enable.

Example

The following module can be tested in two ways:

$ cargo test
$ cargo test --features loomy/enable

When loomy/enable is set, then the code will be tested as a loomy model, otherwise all types default to their std equivalents, and the code will be tested as normal.

// Note the use of `loomy` instead of `std` or `loom`.
use loomy::{
    hint,
    cell::UnsafeCell,
    sync::atomic::{AtomicBool, Ordering},
};

pub struct SpinLock<T> {
    flag: AtomicBool,
    data: UnsafeCell<T>,
}

unsafe impl<T> Send for SpinLock<T> {}
unsafe impl<T> Sync for SpinLock<T> {}

impl<T> SpinLock<T> {
    pub fn new(t: T) -> Self {
        Self {
            flag: AtomicBool::new(false),
            data: UnsafeCell::new(t),
        }
    }

    pub fn with<R, F: FnOnce(&mut T) -> R>(&self, f: F) -> R {
        while let Err(_) = self
            .flag
            .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
        {
            hint::spin_loop()
        }

        let out = self.data.with_mut(move |t| unsafe { f(&mut *t) });
        self.flag.store(false, Ordering::Release);
        out
    }
}

#[cfg(test)]
mod tests {
    // Also using `loomy` instead of `loom` or `std`.
    use loomy::{thread, sync::Arc};
    use super::*;

    #[test]
    fn test_simple() {
        loomy::model(|| {
            let lock = Arc::new(SpinLock::new(123));
            let lock2 = Arc::clone(&lock);

            let t = thread::spawn(move || {
                lock2.with(|n| *n += 1);
            });

            lock.with(|n| *n = 456);

            let out = lock.with(|n| *n);

            t.join().unwrap();

            assert!(out == 456 || out == 457);
        });
    }
}

A note on UnsafeCell

UnsafeCell in loom has a closure-based API. When using std types, UnsafeCell is wrapped in order to provide the same API.

Modules

Memory allocation APIs.

Hints to compiler that affects how code should be emitted or optimized. Hints may be compile time or runtime.

Useful synchronization primitives.

Native threads.

Functions