#![cfg(loom)]
use loom::sync::{Arc, Mutex};
use pulse_map::AccessBuffer;
const PUSHED: [(usize, u8); 2] = [(1, 0), (2, 1)];
#[test]
fn concurrent_push_drain_never_delivers_a_wrong_event() {
loom::model(|| {
let buf = Arc::new(AccessBuffer::new(64));
let producers: Vec<_> = PUSHED
.iter()
.map(|&(bucket, slot)| {
let buf = buf.clone();
loom::thread::spawn(move || buf.push(bucket, slot))
})
.collect();
let mut delivered = Vec::new();
buf.drain(4, |bucket, slot| delivered.push((bucket, slot)));
for p in producers {
p.join().unwrap();
}
buf.drain(4, |bucket, slot| delivered.push((bucket, slot)));
for event in &delivered {
assert!(
PUSHED.contains(event),
"drained {event:?}, which was never pushed (delivered {delivered:?})"
);
assert_eq!(
delivered.iter().filter(|e| *e == event).count(),
1,
"{event:?} delivered more than once (delivered {delivered:?})"
);
}
assert!(
delivered.len() <= PUSHED.len(),
"more events out than in: {delivered:?}"
);
assert!(
!delivered.is_empty(),
"both events vanished from a buffer that was never full"
);
});
}
#[test]
fn single_producer_event_is_never_torn() {
loom::model(|| {
let buf = Arc::new(AccessBuffer::new(64));
let producer = {
let buf = buf.clone();
loom::thread::spawn(move || assert!(buf.push(7, 3), "empty buffer refused a push"))
};
let mut delivered = Vec::new();
buf.drain(4, |bucket, slot| delivered.push((bucket, slot)));
producer.join().unwrap();
buf.drain(4, |bucket, slot| delivered.push((bucket, slot)));
assert_eq!(
delivered,
vec![(7, 3)],
"single push must be delivered exactly once"
);
});
}
#[test]
fn concurrent_drains_deliver_every_event_exactly_once() {
loom::model(|| {
let buf = Arc::new(AccessBuffer::new(64));
for &(bucket, slot) in PUSHED.iter() {
buf.push(bucket, slot);
}
let delivered = Arc::new(Mutex::new(Vec::new()));
let drains: Vec<_> = (0..2)
.map(|_| {
let buf = buf.clone();
let delivered = delivered.clone();
loom::thread::spawn(move || {
buf.drain(4, |bucket, slot| {
delivered.lock().unwrap().push((bucket, slot));
})
})
})
.collect();
for d in drains {
d.join().unwrap();
}
let mut events = delivered.lock().unwrap().clone();
events.sort();
assert_eq!(
events,
vec![(1, 0), (2, 1)],
"both events must be delivered exactly once across two concurrent drains"
);
});
}