swym 0.1.0-preview

Transactional memory for rust
#![feature(test)]

mod memory {
    use crossbeam_utils::thread;
    use std::sync::atomic::{AtomicIsize, Ordering::Relaxed};
    use swym::{tcell::TCell, thread_key, tx::Ordering};

    #[test]
    fn _assert_single_threaded() {
        assert_eq!(
            std::env::var("RUST_TEST_THREADS")
                .expect("`RUST_TEST_THREADS` should be set to 1 for tests")
                .parse::<usize>()
                .expect("`RUST_TEST_THREADS` should be set to 1 for tests"),
            1,
            "`RUST_TEST_THREADS` should be set to 1 for tests"
        );
    }

    #[test]
    fn set_tcell_in_tptr() {
        const ITER_COUNT: usize = 1_000;
        const INNER_ITER_COUNT: usize = 10;
        const THREAD_COUNT: usize = 16;
        static ALLOC_COUNT: AtomicIsize = AtomicIsize::new(0);

        struct Foo(TCell<String>);
        impl Foo {
            fn new(x: &str) -> Self {
                ALLOC_COUNT.fetch_add(1, Relaxed);
                Foo(TCell::new(x.to_owned()))
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) {
                ALLOC_COUNT.fetch_sub(1, Relaxed);
            }
        }

        use swym::tptr::TPtr;
        let x = TPtr::new(Box::into_raw(Box::new(Foo::new("hello there"))));
        thread::scope(|s| {
            for _ in 0..THREAD_COUNT {
                s.spawn(|_| {
                    let thread_key = thread_key::get();
                    for _ in 0..ITER_COUNT {
                        thread_key.rw(|tx| {
                            for _ in 0..INNER_ITER_COUNT {
                                let ptr = x.as_ptr(tx, Ordering::default())?;
                                if !ptr.is_null() {
                                    let ptr_ref = unsafe { &*ptr };
                                    drop(ptr_ref.0.borrow(tx, Ordering::default())?);
                                    ptr_ref.0.set(tx, "hello here".to_owned())?;
                                    unsafe { TPtr::privatize_as_box(tx, ptr) };
                                    x.set(tx, std::ptr::null_mut())?;
                                } else {
                                    x.publish_box(tx, Box::new(Foo::new("hello everywhere")))?
                                };
                            }
                            Ok(())
                        })
                    }
                });
            }
        })
        .unwrap();
        let ptr = x.into_inner();
        if !ptr.is_null() {
            unsafe { Box::from_raw(ptr as *mut Foo) };
        }
        assert_eq!(ALLOC_COUNT.load(Relaxed), 0);
    }
}