@@ -67,6 +67,11 @@ impl MutexRef {
6767 fn new ( ) -> Self {
6868 MutexRef ( Rc :: new ( RefCell :: new ( Mutex :: default ( ) ) ) )
6969 }
70+
71+ /// Get the id of the thread that currently owns this lock, or `None` if it is not locked.
72+ pub fn owner ( & self ) -> Option < ThreadId > {
73+ self . 0 . borrow ( ) . owner
74+ }
7075}
7176
7277impl VisitProvenance for MutexRef {
@@ -109,13 +114,41 @@ struct RwLock {
109114 clock_current_readers : VClock ,
110115}
111116
117+ impl RwLock {
118+ #[ inline]
119+ /// Check if locked.
120+ fn is_locked ( & self ) -> bool {
121+ trace ! (
122+ "rwlock_is_locked: writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)" ,
123+ self . writer,
124+ self . readers. len( ) ,
125+ ) ;
126+ self . writer . is_some ( ) || self . readers . is_empty ( ) . not ( )
127+ }
128+
129+ /// Check if write locked.
130+ #[ inline]
131+ fn is_write_locked ( & self ) -> bool {
132+ trace ! ( "rwlock_is_write_locked: writer is {:?}" , self . writer) ;
133+ self . writer . is_some ( )
134+ }
135+ }
136+
112137#[ derive( Default , Clone , Debug ) ]
113138pub struct RwLockRef ( Rc < RefCell < RwLock > > ) ;
114139
115140impl RwLockRef {
116141 fn new ( ) -> Self {
117142 RwLockRef ( Rc :: new ( RefCell :: new ( RwLock :: default ( ) ) ) )
118143 }
144+
145+ pub fn is_locked ( & self ) -> bool {
146+ self . 0 . borrow ( ) . is_locked ( )
147+ }
148+
149+ pub fn is_write_locked ( & self ) -> bool {
150+ self . 0 . borrow ( ) . is_write_locked ( )
151+ }
119152}
120153
121154impl VisitProvenance for RwLockRef {
@@ -186,17 +219,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
186219pub ( super ) trait EvalContextExtPriv < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
187220 fn condvar_reacquire_mutex (
188221 & mut self ,
189- mutex_ref : & MutexRef ,
222+ mutex_ref : MutexRef ,
190223 retval : Scalar ,
191224 dest : MPlaceTy < ' tcx > ,
192225 ) -> InterpResult < ' tcx > {
193226 let this = self . eval_context_mut ( ) ;
194- if this . mutex_is_locked ( mutex_ref) {
195- assert_ne ! ( this . mutex_get_owner ( mutex_ref ) , this. active_thread( ) ) ;
227+ if let Some ( owner ) = mutex_ref. owner ( ) {
228+ assert_ne ! ( owner , this. active_thread( ) ) ;
196229 this. mutex_enqueue_and_block ( mutex_ref, Some ( ( retval, dest) ) ) ;
197230 } else {
198231 // We can have it right now!
199- this. mutex_lock ( mutex_ref) ;
232+ this. mutex_lock ( & mutex_ref) ;
200233 // Don't forget to write the return value.
201234 this. write_scalar ( retval, & dest) ?;
202235 }
@@ -346,18 +379,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
346379 Some ( alloc_extra. get_sync :: < T > ( offset) . unwrap ( ) )
347380 }
348381
349- #[ inline]
350- /// Get the id of the thread that currently owns this lock.
351- fn mutex_get_owner ( & self , mutex_ref : & MutexRef ) -> ThreadId {
352- mutex_ref. 0 . borrow ( ) . owner . unwrap ( )
353- }
354-
355- #[ inline]
356- /// Check if locked.
357- fn mutex_is_locked ( & self , mutex_ref : & MutexRef ) -> bool {
358- mutex_ref. 0 . borrow ( ) . owner . is_some ( )
359- }
360-
361382 /// Lock by setting the mutex owner and increasing the lock count.
362383 fn mutex_lock ( & mut self , mutex_ref : & MutexRef ) {
363384 let this = self . eval_context_mut ( ) ;
@@ -425,14 +446,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
425446 #[ inline]
426447 fn mutex_enqueue_and_block (
427448 & mut self ,
428- mutex_ref : & MutexRef ,
449+ mutex_ref : MutexRef ,
429450 retval_dest : Option < ( Scalar , MPlaceTy < ' tcx > ) > ,
430451 ) {
431452 let this = self . eval_context_mut ( ) ;
432- assert ! ( this. mutex_is_locked( mutex_ref) , "queuing on unlocked mutex" ) ;
433453 let thread = this. active_thread ( ) ;
434- mutex_ref. 0 . borrow_mut ( ) . queue . push_back ( thread) ;
435- let mutex_ref = mutex_ref. clone ( ) ;
454+ let mut mutex = mutex_ref. 0 . borrow_mut ( ) ;
455+ mutex. queue . push_back ( thread) ;
456+ assert ! ( mutex. owner. is_some( ) , "queuing on unlocked mutex" ) ;
457+ drop ( mutex) ;
436458 this. block_thread (
437459 BlockReason :: Mutex ,
438460 None ,
@@ -444,7 +466,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
444466 |this, unblock: UnblockKind | {
445467 assert_eq!( unblock, UnblockKind :: Ready ) ;
446468
447- assert!( !this . mutex_is_locked ( & mutex_ref ) ) ;
469+ assert!( mutex_ref . owner ( ) . is_none ( ) ) ;
448470 this. mutex_lock( & mutex_ref) ;
449471
450472 if let Some ( ( retval, dest) ) = retval_dest {
@@ -457,34 +479,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
457479 ) ;
458480 }
459481
460- #[ inline]
461- /// Check if locked.
462- fn rwlock_is_locked ( & self , rw_lock_ref : & RwLockRef ) -> bool {
463- let rwlock = rw_lock_ref. 0 . borrow ( ) ;
464- trace ! (
465- "rwlock_is_locked: writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)" ,
466- rwlock. writer,
467- rwlock. readers. len( ) ,
468- ) ;
469- rwlock. writer . is_some ( ) || rwlock. readers . is_empty ( ) . not ( )
470- }
471-
472- /// Check if write locked.
473- #[ inline]
474- fn rwlock_is_write_locked ( & self , rwlock_ref : & RwLockRef ) -> bool {
475- let rwlock = rwlock_ref. 0 . borrow ( ) ;
476- trace ! ( "rwlock_is_write_locked: writer is {:?}" , rwlock. writer) ;
477- rwlock. writer . is_some ( )
478- }
479-
480482 /// Read-lock the lock by adding the `reader` the list of threads that own
481483 /// this lock.
482484 fn rwlock_reader_lock ( & mut self , rwlock_ref : & RwLockRef ) {
483485 let this = self . eval_context_mut ( ) ;
484486 let thread = this. active_thread ( ) ;
485- assert ! ( !this. rwlock_is_write_locked( rwlock_ref) , "the lock is write locked" ) ;
486487 trace ! ( "rwlock_reader_lock: now also held (one more time) by {:?}" , thread) ;
487488 let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
489+ assert ! ( !rwlock. is_write_locked( ) , "the lock is write locked" ) ;
488490 let count = rwlock. readers . entry ( thread) . or_insert ( 0 ) ;
489491 * count = count. strict_add ( 1 ) ;
490492 if let Some ( data_race) = this. machine . data_race . as_vclocks_ref ( ) {
@@ -518,14 +520,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
518520 rwlock. clock_current_readers . join ( clock)
519521 } ) ;
520522 }
521- drop ( rwlock) ; // FIXME can we avoid releasing and re-acquiring the RefCell?
522523
523524 // The thread was a reader. If the lock is not held any more, give it to a writer.
524- if this . rwlock_is_locked ( rwlock_ref ) . not ( ) {
525+ if rwlock . is_locked ( ) . not ( ) {
525526 // All the readers are finished, so set the writer data-race handle to the value
526527 // of the union of all reader data race handles, since the set of readers
527528 // happen-before the writers
528- let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
529529 let rwlock_ref = & mut * rwlock;
530530 rwlock_ref. clock_unlocked . clone_from ( & rwlock_ref. clock_current_readers ) ;
531531 // See if there is a thread to unblock.
@@ -548,11 +548,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
548548 ) {
549549 let this = self . eval_context_mut ( ) ;
550550 let thread = this. active_thread ( ) ;
551- assert ! (
552- this. rwlock_is_write_locked( & rwlock_ref) ,
553- "read-queueing on not write locked rwlock"
554- ) ;
555- rwlock_ref. 0 . borrow_mut ( ) . reader_queue . push_back ( thread) ;
551+ let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
552+ rwlock. reader_queue . push_back ( thread) ;
553+ assert ! ( rwlock. is_write_locked( ) , "read-queueing on not write locked rwlock" ) ;
554+ drop ( rwlock) ;
556555 this. block_thread (
557556 BlockReason :: RwLock ,
558557 None ,
@@ -577,10 +576,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
577576 fn rwlock_writer_lock ( & mut self , rwlock_ref : & RwLockRef ) {
578577 let this = self . eval_context_mut ( ) ;
579578 let thread = this. active_thread ( ) ;
580- assert ! ( !this. rwlock_is_locked( rwlock_ref) , "the rwlock is already locked" ) ;
581579 trace ! ( "rwlock_writer_lock: now held by {:?}" , thread) ;
582580
583581 let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
582+ assert ! ( !rwlock. is_locked( ) , "the rwlock is already locked" ) ;
584583 rwlock. writer = Some ( thread) ;
585584 if let Some ( data_race) = this. machine . data_race . as_vclocks_ref ( ) {
586585 data_race. acquire_clock ( & rwlock. clock_unlocked , & this. machine . threads ) ;
@@ -640,9 +639,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
640639 dest : MPlaceTy < ' tcx > ,
641640 ) {
642641 let this = self . eval_context_mut ( ) ;
643- assert ! ( this. rwlock_is_locked( & rwlock_ref) , "write-queueing on unlocked rwlock" ) ;
644642 let thread = this. active_thread ( ) ;
645- rwlock_ref. 0 . borrow_mut ( ) . writer_queue . push_back ( thread) ;
643+ let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
644+ rwlock. writer_queue . push_back ( thread) ;
645+ assert ! ( rwlock. is_locked( ) , "write-queueing on unlocked rwlock" ) ;
646+ drop ( rwlock) ;
646647 this. block_thread (
647648 BlockReason :: RwLock ,
648649 None ,
@@ -719,15 +720,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
719720 }
720721 // Try to acquire the mutex.
721722 // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
722- this. condvar_reacquire_mutex( & mutex_ref, retval_succ, dest)
723+ this. condvar_reacquire_mutex( mutex_ref, retval_succ, dest)
723724 }
724725 UnblockKind :: TimedOut => {
725726 // We have to remove the waiter from the queue again.
726727 let thread = this. active_thread( ) ;
727728 let waiters = & mut this. machine. sync. condvars[ condvar] . waiters;
728729 waiters. retain( |waiter| * waiter != thread) ;
729730 // Now get back the lock.
730- this. condvar_reacquire_mutex( & mutex_ref, retval_timeout, dest)
731+ this. condvar_reacquire_mutex( mutex_ref, retval_timeout, dest)
731732 }
732733 }
733734 }
0 commit comments