@@ -4,29 +4,11 @@ use rustc_index::Idx;
44use rustc_middle:: ty:: layout:: TyAndLayout ;
55
66use super :: sync:: EvalContextExtPriv as _;
7- use super :: thread:: MachineCallback ;
87use super :: vector_clock:: VClock ;
98use crate :: * ;
109
1110declare_id ! ( InitOnceId ) ;
1211
13- /// A thread waiting on an InitOnce object.
14- struct InitOnceWaiter < ' mir , ' tcx > {
15- /// The thread that is waiting.
16- thread : ThreadId ,
17- /// The callback that should be executed, after the thread has been woken up.
18- callback : Box < dyn MachineCallback < ' mir , ' tcx > + ' tcx > ,
19- }
20-
21- impl < ' mir , ' tcx > std:: fmt:: Debug for InitOnceWaiter < ' mir , ' tcx > {
22- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
23- f. debug_struct ( "InitOnce" )
24- . field ( "thread" , & self . thread )
25- . field ( "callback" , & "dyn MachineCallback" )
26- . finish ( )
27- }
28- }
29-
3012#[ derive( Default , Debug , Copy , Clone , PartialEq , Eq ) ]
3113/// The current status of a one time initialization.
3214pub enum InitOnceStatus {
@@ -38,68 +20,14 @@ pub enum InitOnceStatus {
3820
3921/// The one time initialization state.
4022#[ derive( Default , Debug ) ]
41- pub ( super ) struct InitOnce < ' mir , ' tcx > {
23+ pub ( super ) struct InitOnce {
4224 status : InitOnceStatus ,
43- waiters : VecDeque < InitOnceWaiter < ' mir , ' tcx > > ,
25+ waiters : VecDeque < ThreadId > ,
4426 clock : VClock ,
4527}
4628
47- impl < ' mir , ' tcx > VisitProvenance for InitOnce < ' mir , ' tcx > {
48- fn visit_provenance ( & self , visit : & mut VisitWith < ' _ > ) {
49- for waiter in self . waiters . iter ( ) {
50- waiter. callback . visit_provenance ( visit) ;
51- }
52- }
53- }
54-
5529impl < ' mir , ' tcx : ' mir > EvalContextExtPriv < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
5630trait EvalContextExtPriv < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
57- /// Synchronize with the previous initialization attempt of an InitOnce.
58- #[ inline]
59- fn init_once_observe_attempt ( & mut self , id : InitOnceId ) {
60- let this = self . eval_context_mut ( ) ;
61- let current_thread = this. get_active_thread ( ) ;
62-
63- if let Some ( data_race) = & this. machine . data_race {
64- data_race. acquire_clock ( & this. machine . sync . init_onces [ id] . clock , current_thread) ;
65- }
66- }
67-
68- #[ inline]
69- fn init_once_wake_waiter (
70- & mut self ,
71- id : InitOnceId ,
72- waiter : InitOnceWaiter < ' mir , ' tcx > ,
73- ) -> InterpResult < ' tcx > {
74- let this = self . eval_context_mut ( ) ;
75- let current_thread = this. get_active_thread ( ) ;
76-
77- this. unblock_thread ( waiter. thread , BlockReason :: InitOnce ( id) ) ;
78-
79- // Call callback, with the woken-up thread as `current`.
80- this. set_active_thread ( waiter. thread ) ;
81- this. init_once_observe_attempt ( id) ;
82- waiter. callback . call ( this) ?;
83- this. set_active_thread ( current_thread) ;
84-
85- Ok ( ( ) )
86- }
87- }
88-
89- impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
90- pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
91- fn init_once_get_or_create_id (
92- & mut self ,
93- lock_op : & OpTy < ' tcx , Provenance > ,
94- lock_layout : TyAndLayout < ' tcx > ,
95- offset : u64 ,
96- ) -> InterpResult < ' tcx , InitOnceId > {
97- let this = self . eval_context_mut ( ) ;
98- this. init_once_get_or_create ( |ecx, next_id| {
99- ecx. get_or_create_id ( next_id, lock_op, lock_layout, offset)
100- } )
101- }
102-
10331 /// Provides the closure with the next InitOnceId. Creates that InitOnce if the closure returns None,
10432 /// otherwise returns the value from the closure.
10533 #[ inline]
@@ -120,6 +48,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
12048 Ok ( new_index)
12149 }
12250 }
51+ }
52+
53+ impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
54+ pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
55+ fn init_once_get_or_create_id (
56+ & mut self ,
57+ lock_op : & OpTy < ' tcx , Provenance > ,
58+ lock_layout : TyAndLayout < ' tcx > ,
59+ offset : u64 ,
60+ ) -> InterpResult < ' tcx , InitOnceId > {
61+ let this = self . eval_context_mut ( ) ;
62+ this. init_once_get_or_create ( |ecx, next_id| {
63+ ecx. get_or_create_id ( next_id, lock_op, lock_layout, offset)
64+ } )
65+ }
12366
12467 #[ inline]
12568 fn init_once_status ( & mut self , id : InitOnceId ) -> InitOnceStatus {
@@ -132,14 +75,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
13275 fn init_once_enqueue_and_block (
13376 & mut self ,
13477 id : InitOnceId ,
135- thread : ThreadId ,
136- callback : Box < dyn MachineCallback < ' mir , ' tcx > + ' tcx > ,
78+ callback : impl UnblockCallback < ' mir , ' tcx > + ' tcx ,
13779 ) {
13880 let this = self . eval_context_mut ( ) ;
81+ let thread = this. active_thread ( ) ;
13982 let init_once = & mut this. machine . sync . init_onces [ id] ;
14083 assert_ne ! ( init_once. status, InitOnceStatus :: Complete , "queueing on complete init once" ) ;
141- init_once. waiters . push_back ( InitOnceWaiter { thread, callback } ) ;
142- this. block_thread ( thread , BlockReason :: InitOnce ( id) ) ;
84+ init_once. waiters . push_back ( thread) ;
85+ this. block_thread ( BlockReason :: InitOnce ( id) , None , callback ) ;
14386 }
14487
14588 /// Begin initializing this InitOnce. Must only be called after checking that it is currently
@@ -177,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
177120 // Wake up everyone.
178121 // need to take the queue to avoid having `this` be borrowed multiple times
179122 for waiter in std:: mem:: take ( & mut init_once. waiters ) {
180- this. init_once_wake_waiter ( id , waiter ) ?;
123+ this. unblock_thread ( waiter , BlockReason :: InitOnce ( id ) ) ?;
181124 }
182125
183126 Ok ( ( ) )
@@ -192,6 +135,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
192135 InitOnceStatus :: Begun ,
193136 "failing already completed or uninit init once"
194137 ) ;
138+ // This is again uninitialized.
139+ init_once. status = InitOnceStatus :: Uninitialized ;
195140
196141 // Each complete happens-before the end of the wait
197142 if let Some ( data_race) = & this. machine . data_race {
@@ -200,10 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
200145
201146 // Wake up one waiting thread, so they can go ahead and try to init this.
202147 if let Some ( waiter) = init_once. waiters . pop_front ( ) {
203- this. init_once_wake_waiter ( id, waiter) ?;
204- } else {
205- // Nobody there to take this, so go back to 'uninit'
206- init_once. status = InitOnceStatus :: Uninitialized ;
148+ this. unblock_thread ( waiter, BlockReason :: InitOnce ( id) ) ?;
207149 }
208150
209151 Ok ( ( ) )
@@ -221,6 +163,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
221163 "observing the completion of incomplete init once"
222164 ) ;
223165
224- this. init_once_observe_attempt ( id ) ;
166+ this. acquire_clock ( & this . machine . sync . init_onces [ id ] . clock ) ;
225167 }
226168}
0 commit comments