test and fix for rwlock unlock bug
This commit is contained in:
parent
a80821e046
commit
acb3ec0866
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user