diff --git a/ci/script.sh b/ci/script.sh index 9137e63b6d09fb8427c4e30f657e69667805f096..07260f43a8b567eb7dd2d032b5b8ed4157119142 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -11,8 +11,9 @@ main() { cargo test --target $TARGET cargo test --target $TARGET --release - export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt" export RUSTFLAGS="-Z sanitizer=thread" + export RUST_TEST_THREADS=1 + export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt" cargo test --test tsan --target $TARGET cargo test --test tsan --target $TARGET --release diff --git a/src/ring_buffer/mod.rs b/src/ring_buffer/mod.rs index 3f53646d2ad1173f93c1d8cf236cdb1bbcca0a83..52bbb04a463c968c4a5645442de19e74cd911333 100644 --- a/src/ring_buffer/mod.rs +++ b/src/ring_buffer/mod.rs @@ -129,6 +129,11 @@ where } } + /// Returns `true` if the ring buffer has a length of 0 + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Iterates from the front of the queue to the back pub fn iter(&self) -> Iter<T, A> { Iter { diff --git a/tests/tsan.rs b/tests/tsan.rs index 6680cd248500fb6a910f18e3c992541e434f58fc..9fbcb8d59b553bd6c513f63872db9595566244b1 100644 --- a/tests/tsan.rs +++ b/tests/tsan.rs @@ -73,3 +73,48 @@ fn scoped() { rb.dequeue().unwrap(); } + +#[test] +fn contention() { + const N: usize = 1024; + + let mut rb: RingBuffer<u8, [u8; N]> = RingBuffer::new(); + + { + let (mut p, mut c) = rb.split(); + + Pool::new(2).scoped(move |scope| { + scope.execute(move || { + let mut sum: u32 = 0; + + for i in 0..N { + let i = i as u8; + sum = sum.wrapping_add(i as u32); + while let Err(_) = p.enqueue(i) {} + } + + println!("producer: {}", sum); + }); + + scope.execute(move || { + let mut sum: u32 = 0; + + for _ in 0..N { + loop { + match c.dequeue() { + Some(v) => { + sum = sum.wrapping_add(v as u32); + break; + } + _ => {} + } + } + } + + println!("consumer: {}", sum); + }); + }); + } + + assert!(rb.is_empty()); +}