1
+ use std:: cell:: RefCell ;
1
2
use std:: collections:: VecDeque ;
2
3
use std:: collections:: hash_map:: Entry ;
3
4
use std:: ops:: Not ;
5
+ use std:: rc:: Rc ;
4
6
use std:: time:: Duration ;
5
7
6
8
use rustc_data_structures:: fx:: FxHashMap ;
@@ -121,6 +123,15 @@ struct Futex {
121
123
clock : VClock ,
122
124
}
123
125
126
+ #[ derive( Default , Clone ) ]
127
+ pub struct FutexRef ( Rc < RefCell < Futex > > ) ;
128
+
129
+ impl VisitProvenance for FutexRef {
130
+ fn visit_provenance ( & self , _visit : & mut VisitWith < ' _ > ) {
131
+ // No provenance
132
+ }
133
+ }
134
+
124
135
/// A thread waiting on a futex.
125
136
#[ derive( Debug ) ]
126
137
struct FutexWaiter {
@@ -137,9 +148,6 @@ pub struct SynchronizationObjects {
137
148
rwlocks : IndexVec < RwLockId , RwLock > ,
138
149
condvars : IndexVec < CondvarId , Condvar > ,
139
150
pub ( super ) init_onces : IndexVec < InitOnceId , InitOnce > ,
140
-
141
- /// Futex info for the futex at the given address.
142
- futexes : FxHashMap < u64 , Futex > ,
143
151
}
144
152
145
153
// Private extension trait for local helper methods
@@ -184,7 +192,7 @@ impl SynchronizationObjects {
184
192
}
185
193
186
194
impl < ' tcx > AllocExtra < ' tcx > {
187
- pub fn get_sync < T : ' static > ( & self , offset : Size ) -> Option < & T > {
195
+ fn get_sync < T : ' static > ( & self , offset : Size ) -> Option < & T > {
188
196
self . sync . get ( & offset) . and_then ( |s| s. downcast_ref :: < T > ( ) )
189
197
}
190
198
}
@@ -690,7 +698,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
690
698
/// On a timeout, `retval_timeout` is written to `dest` and `errno_timeout` is set as the last error.
691
699
fn futex_wait (
692
700
& mut self ,
693
- addr : u64 ,
701
+ futex_ref : FutexRef ,
694
702
bitset : u32 ,
695
703
timeout : Option < ( TimeoutClock , TimeoutAnchor , Duration ) > ,
696
704
retval_succ : Scalar ,
@@ -700,23 +708,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
700
708
) {
701
709
let this = self . eval_context_mut ( ) ;
702
710
let thread = this. active_thread ( ) ;
703
- let futex = & mut this . machine . sync . futexes . entry ( addr ) . or_default ( ) ;
711
+ let mut futex = futex_ref . 0 . borrow_mut ( ) ;
704
712
let waiters = & mut futex. waiters ;
705
713
assert ! ( waiters. iter( ) . all( |waiter| waiter. thread != thread) , "thread is already waiting" ) ;
706
714
waiters. push_back ( FutexWaiter { thread, bitset } ) ;
715
+ drop ( futex) ;
716
+
707
717
this. block_thread (
708
- BlockReason :: Futex { addr } ,
718
+ BlockReason :: Futex ,
709
719
timeout,
710
720
callback ! (
711
721
@capture<' tcx> {
712
- addr : u64 ,
722
+ futex_ref : FutexRef ,
713
723
retval_succ: Scalar ,
714
724
retval_timeout: Scalar ,
715
725
dest: MPlaceTy <' tcx>,
716
726
errno_timeout: Scalar ,
717
727
}
718
728
@unblock = |this| {
719
- let futex = this . machine . sync . futexes . get ( & addr ) . unwrap ( ) ;
729
+ let futex = futex_ref . 0 . borrow ( ) ;
720
730
// Acquire the clock of the futex.
721
731
if let Some ( data_race) = & this. machine. data_race {
722
732
data_race. acquire_clock( & futex. clock, & this. machine. threads) ;
@@ -728,7 +738,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
728
738
@timeout = |this| {
729
739
// Remove the waiter from the futex.
730
740
let thread = this. active_thread( ) ;
731
- let futex = this . machine . sync . futexes . get_mut ( & addr ) . unwrap ( ) ;
741
+ let mut futex = futex_ref . 0 . borrow_mut ( ) ;
732
742
futex. waiters. retain( |waiter| waiter. thread != thread) ;
733
743
// Set errno and write return value.
734
744
this. set_last_error( errno_timeout) ?;
@@ -740,11 +750,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
740
750
}
741
751
742
752
/// Returns whether anything was woken.
743
- fn futex_wake ( & mut self , addr : u64 , bitset : u32 ) -> InterpResult < ' tcx , bool > {
753
+ fn futex_wake ( & mut self , futex_ref : & FutexRef , bitset : u32 ) -> InterpResult < ' tcx , bool > {
744
754
let this = self . eval_context_mut ( ) ;
745
- let Some ( futex) = this. machine . sync . futexes . get_mut ( & addr) else {
746
- return interp_ok ( false ) ;
747
- } ;
755
+ let mut futex = futex_ref. 0 . borrow_mut ( ) ;
748
756
let data_race = & this. machine . data_race ;
749
757
750
758
// Each futex-wake happens-before the end of the futex wait
@@ -757,7 +765,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
757
765
return interp_ok ( false ) ;
758
766
} ;
759
767
let waiter = futex. waiters . remove ( i) . unwrap ( ) ;
760
- this. unblock_thread ( waiter. thread , BlockReason :: Futex { addr } ) ?;
768
+ drop ( futex) ;
769
+ this. unblock_thread ( waiter. thread , BlockReason :: Futex ) ?;
761
770
interp_ok ( true )
762
771
}
763
772
}
0 commit comments