@@ -67,6 +67,11 @@ impl MutexRef {
67
67
fn new ( ) -> Self {
68
68
MutexRef ( Rc :: new ( RefCell :: new ( Mutex :: default ( ) ) ) )
69
69
}
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
+ }
70
75
}
71
76
72
77
impl VisitProvenance for MutexRef {
@@ -109,13 +114,41 @@ struct RwLock {
109
114
clock_current_readers : VClock ,
110
115
}
111
116
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
+
112
137
#[ derive( Default , Clone , Debug ) ]
113
138
pub struct RwLockRef ( Rc < RefCell < RwLock > > ) ;
114
139
115
140
impl RwLockRef {
116
141
fn new ( ) -> Self {
117
142
RwLockRef ( Rc :: new ( RefCell :: new ( RwLock :: default ( ) ) ) )
118
143
}
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
+ }
119
152
}
120
153
121
154
impl VisitProvenance for RwLockRef {
@@ -186,17 +219,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
186
219
pub ( super ) trait EvalContextExtPriv < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
187
220
fn condvar_reacquire_mutex (
188
221
& mut self ,
189
- mutex_ref : & MutexRef ,
222
+ mutex_ref : MutexRef ,
190
223
retval : Scalar ,
191
224
dest : MPlaceTy < ' tcx > ,
192
225
) -> InterpResult < ' tcx > {
193
226
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( ) ) ;
196
229
this. mutex_enqueue_and_block ( mutex_ref, Some ( ( retval, dest) ) ) ;
197
230
} else {
198
231
// We can have it right now!
199
- this. mutex_lock ( mutex_ref) ;
232
+ this. mutex_lock ( & mutex_ref) ;
200
233
// Don't forget to write the return value.
201
234
this. write_scalar ( retval, & dest) ?;
202
235
}
@@ -346,18 +379,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
346
379
Some ( alloc_extra. get_sync :: < T > ( offset) . unwrap ( ) )
347
380
}
348
381
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
-
361
382
/// Lock by setting the mutex owner and increasing the lock count.
362
383
fn mutex_lock ( & mut self , mutex_ref : & MutexRef ) {
363
384
let this = self . eval_context_mut ( ) ;
@@ -425,14 +446,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
425
446
#[ inline]
426
447
fn mutex_enqueue_and_block (
427
448
& mut self ,
428
- mutex_ref : & MutexRef ,
449
+ mutex_ref : MutexRef ,
429
450
retval_dest : Option < ( Scalar , MPlaceTy < ' tcx > ) > ,
430
451
) {
431
452
let this = self . eval_context_mut ( ) ;
432
- assert ! ( this. mutex_is_locked( mutex_ref) , "queuing on unlocked mutex" ) ;
433
453
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) ;
436
458
this. block_thread (
437
459
BlockReason :: Mutex ,
438
460
None ,
@@ -444,7 +466,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
444
466
|this, unblock: UnblockKind | {
445
467
assert_eq!( unblock, UnblockKind :: Ready ) ;
446
468
447
- assert!( !this . mutex_is_locked ( & mutex_ref ) ) ;
469
+ assert!( mutex_ref . owner ( ) . is_none ( ) ) ;
448
470
this. mutex_lock( & mutex_ref) ;
449
471
450
472
if let Some ( ( retval, dest) ) = retval_dest {
@@ -457,34 +479,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
457
479
) ;
458
480
}
459
481
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
-
480
482
/// Read-lock the lock by adding the `reader` the list of threads that own
481
483
/// this lock.
482
484
fn rwlock_reader_lock ( & mut self , rwlock_ref : & RwLockRef ) {
483
485
let this = self . eval_context_mut ( ) ;
484
486
let thread = this. active_thread ( ) ;
485
- assert ! ( !this. rwlock_is_write_locked( rwlock_ref) , "the lock is write locked" ) ;
486
487
trace ! ( "rwlock_reader_lock: now also held (one more time) by {:?}" , thread) ;
487
488
let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
489
+ assert ! ( !rwlock. is_write_locked( ) , "the lock is write locked" ) ;
488
490
let count = rwlock. readers . entry ( thread) . or_insert ( 0 ) ;
489
491
* count = count. strict_add ( 1 ) ;
490
492
if let Some ( data_race) = this. machine . data_race . as_vclocks_ref ( ) {
@@ -518,14 +520,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
518
520
rwlock. clock_current_readers . join ( clock)
519
521
} ) ;
520
522
}
521
- drop ( rwlock) ; // FIXME can we avoid releasing and re-acquiring the RefCell?
522
523
523
524
// 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 ( ) {
525
526
// All the readers are finished, so set the writer data-race handle to the value
526
527
// of the union of all reader data race handles, since the set of readers
527
528
// happen-before the writers
528
- let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
529
529
let rwlock_ref = & mut * rwlock;
530
530
rwlock_ref. clock_unlocked . clone_from ( & rwlock_ref. clock_current_readers ) ;
531
531
// See if there is a thread to unblock.
@@ -548,11 +548,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
548
548
) {
549
549
let this = self . eval_context_mut ( ) ;
550
550
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) ;
556
555
this. block_thread (
557
556
BlockReason :: RwLock ,
558
557
None ,
@@ -577,10 +576,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
577
576
fn rwlock_writer_lock ( & mut self , rwlock_ref : & RwLockRef ) {
578
577
let this = self . eval_context_mut ( ) ;
579
578
let thread = this. active_thread ( ) ;
580
- assert ! ( !this. rwlock_is_locked( rwlock_ref) , "the rwlock is already locked" ) ;
581
579
trace ! ( "rwlock_writer_lock: now held by {:?}" , thread) ;
582
580
583
581
let mut rwlock = rwlock_ref. 0 . borrow_mut ( ) ;
582
+ assert ! ( !rwlock. is_locked( ) , "the rwlock is already locked" ) ;
584
583
rwlock. writer = Some ( thread) ;
585
584
if let Some ( data_race) = this. machine . data_race . as_vclocks_ref ( ) {
586
585
data_race. acquire_clock ( & rwlock. clock_unlocked , & this. machine . threads ) ;
@@ -640,9 +639,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
640
639
dest : MPlaceTy < ' tcx > ,
641
640
) {
642
641
let this = self . eval_context_mut ( ) ;
643
- assert ! ( this. rwlock_is_locked( & rwlock_ref) , "write-queueing on unlocked rwlock" ) ;
644
642
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) ;
646
647
this. block_thread (
647
648
BlockReason :: RwLock ,
648
649
None ,
@@ -719,15 +720,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
719
720
}
720
721
// Try to acquire the mutex.
721
722
// 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)
723
724
}
724
725
UnblockKind :: TimedOut => {
725
726
// We have to remove the waiter from the queue again.
726
727
let thread = this. active_thread( ) ;
727
728
let waiters = & mut this. machine. sync. condvars[ condvar] . waiters;
728
729
waiters. retain( |waiter| * waiter != thread) ;
729
730
// 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)
731
732
}
732
733
}
733
734
}
0 commit comments