test and fix for rwlock unlock bug

This commit is contained in:
Ralf Jung 2020-05-30 22:48:43 +02:00
parent a80821e046
commit acb3ec0866
3 changed files with 50 additions and 2 deletions
src
tests/run-pass/concurrency

@ -1,5 +1,6 @@
use std::convert::TryInto;
use std::time::{Duration, SystemTime};
use std::ops::Not;
use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut};
use rustc_target::abi::{LayoutOf, Size};
@ -603,7 +604,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
if this.rwlock_reader_unlock(id, active_thread) {
// The thread was a reader.
if this.rwlock_is_locked(id) {
if this.rwlock_is_locked(id).not() {
// No more readers owning the lock. Give it to a writer if there
// is any.
this.rwlock_dequeue_and_lock_writer(id);

@ -282,7 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// Lock by setting the writer that owns the lock.
fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) {
let this = self.eval_context_mut();
assert!(!this.rwlock_is_locked(id), "the relock is already locked");
assert!(!this.rwlock_is_locked(id), "the rwlock is already locked");
this.machine.threads.sync.rwlocks[id].writer = Some(writer);
}

@ -267,6 +267,51 @@ fn check_once() {
}
}
fn check_rwlock_unlock_bug1() {
// There was a bug where when un-read-locking an rwlock that still has other
// readers waiting, we'd accidentally also let a writer in.
// That caused an ICE.
let l = Arc::new(RwLock::new(0));
let r1 = l.read().unwrap();
let r2 = l.read().unwrap();
// Make a waiting writer.
let l2 = l.clone();
thread::spawn(move || {
let mut w = l2.write().unwrap();
*w += 1;
});
thread::yield_now();
drop(r1);
assert_eq!(*r2, 0);
thread::yield_now();
thread::yield_now();
thread::yield_now();
assert_eq!(*r2, 0);
drop(r2);
}
fn check_rwlock_unlock_bug2() {
// There was a bug where when un-read-locking an rwlock by letting the last reader leaver,
// we'd forget to wake up a writer.
// That meant the writer thread could never run again.
let l = Arc::new(RwLock::new(0));
let r = l.read().unwrap();
// Make a waiting writer.
let l2 = l.clone();
let h = thread::spawn(move || {
let _w = l2.write().unwrap();
});
thread::yield_now();
drop(r);
h.join().unwrap();
}
fn main() {
check_barriers();
check_conditional_variables_notify_one();
@ -280,4 +325,6 @@ fn main() {
multiple_send();
send_on_sync();
check_once();
check_rwlock_unlock_bug1();
check_rwlock_unlock_bug2();
}