mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-27 07:55:03 +00:00
Add a test case for #7065.
This commit is contained in:
parent
bd019c4c26
commit
68e8fe9b6e
@ -813,4 +813,66 @@ mod tests {
|
|||||||
|
|
||||||
wp2.recv(); // complete handshake with writer
|
wp2.recv(); // complete handshake with writer
|
||||||
}
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
fn test_rw_write_cond_downgrade_read_race_helper() {
|
||||||
|
// Tests that when a downgrader hands off the "reader cloud" lock
|
||||||
|
// because of a contending reader, a writer can't race to get it
|
||||||
|
// instead, which would result in readers_and_writers. This tests
|
||||||
|
// the sync module rather than this one, but it's here because an
|
||||||
|
// rwarc gives us extra shared state to help check for the race.
|
||||||
|
// If you want to see this test fail, go to sync.rs and replace the
|
||||||
|
// line in RWlock::write_cond() that looks like:
|
||||||
|
// "blk(&Condvar { order: opt_lock, ..*cond })"
|
||||||
|
// with just "blk(cond)".
|
||||||
|
let x = ~RWARC(true);
|
||||||
|
let (wp, wc) = comm::stream();
|
||||||
|
|
||||||
|
// writer task
|
||||||
|
let xw = (*x).clone();
|
||||||
|
do task::spawn {
|
||||||
|
do xw.write_cond |state, c| {
|
||||||
|
wc.send(()); // tell downgrader it's ok to go
|
||||||
|
c.wait();
|
||||||
|
// The core of the test is here: the condvar reacquire path
|
||||||
|
// must involve order_lock, so that it cannot race with a reader
|
||||||
|
// trying to receive the "reader cloud lock hand-off".
|
||||||
|
*state = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp.recv(); // wait for writer to get in
|
||||||
|
|
||||||
|
do x.write_downgrade |mut write_mode| {
|
||||||
|
do write_mode.write_cond |state, c| {
|
||||||
|
assert!(*state);
|
||||||
|
// make writer contend in the cond-reacquire path
|
||||||
|
c.signal();
|
||||||
|
}
|
||||||
|
// make a reader task to trigger the "reader cloud lock" handoff
|
||||||
|
let xr = (*x).clone();
|
||||||
|
let (rp, rc) = comm::stream();
|
||||||
|
do task::spawn {
|
||||||
|
rc.send(());
|
||||||
|
do xr.read |_state| { }
|
||||||
|
}
|
||||||
|
rp.recv(); // wait for reader task to exist
|
||||||
|
|
||||||
|
let read_mode = x.downgrade(write_mode);
|
||||||
|
do read_mode.read |state| {
|
||||||
|
// if writer mistakenly got in, make sure it mutates state
|
||||||
|
// before we assert on it
|
||||||
|
for 5.times { task::yield(); }
|
||||||
|
// make sure writer didn't get in.
|
||||||
|
assert!(*state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_rw_write_cond_downgrade_read_race() {
|
||||||
|
// Ideally the above test case would have yield statements in it that
|
||||||
|
// helped to expose the race nearly 100% of the time... but adding
|
||||||
|
// yields in the intuitively-right locations made it even less likely,
|
||||||
|
// and I wasn't sure why :( . This is a mediocre "next best" option.
|
||||||
|
for 8.times { test_rw_write_cond_downgrade_read_race_helper() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user