@@ -3,7 +3,7 @@ use std::num::NonZeroU32;
33
44use rustc_index:: vec:: Idx ;
55
6- use super :: sync:: EvalContextExtPriv ;
6+ use super :: sync:: EvalContextExtPriv as _ ;
77use super :: thread:: MachineCallback ;
88use super :: vector_clock:: VClock ;
99use crate :: * ;
@@ -52,6 +52,43 @@ impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> {
5252 }
5353}
5454
55+ impl < ' mir , ' tcx : ' mir > EvalContextExtPriv < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
56+ trait 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. validate_lock_acquire (
65+ & this. machine . threads . sync . init_onces [ id] . data_race ,
66+ current_thread,
67+ ) ;
68+ }
69+ }
70+
71+ #[ inline]
72+ fn init_once_wake_waiter (
73+ & mut self ,
74+ id : InitOnceId ,
75+ waiter : InitOnceWaiter < ' mir , ' tcx > ,
76+ ) -> InterpResult < ' tcx > {
77+ let this = self . eval_context_mut ( ) ;
78+ let current_thread = this. get_active_thread ( ) ;
79+
80+ this. unblock_thread ( waiter. thread ) ;
81+
82+ // Call callback, with the woken-up thread as `current`.
83+ this. set_active_thread ( waiter. thread ) ;
84+ this. init_once_observe_attempt ( id) ;
85+ waiter. callback . call ( this) ?;
86+ this. set_active_thread ( current_thread) ;
87+
88+ Ok ( ( ) )
89+ }
90+ }
91+
5592impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
5693pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
5794 fn init_once_get_or_create_id (
@@ -141,13 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
141178 // Wake up everyone.
142179 // need to take the queue to avoid having `this` be borrowed multiple times
143180 for waiter in std:: mem:: take ( & mut init_once. waiters ) {
144- this. unblock_thread ( waiter. thread ) ;
145-
146- // Call callback, with the woken-up thread as `current`.
147- this. set_active_thread ( waiter. thread ) ;
148- this. init_once_acquire ( id) ;
149- waiter. callback . call ( this) ?;
150- this. set_active_thread ( current_thread) ;
181+ this. init_once_wake_waiter ( id, waiter) ?;
151182 }
152183
153184 Ok ( ( ) )
@@ -171,13 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
171202
172203 // Wake up one waiting thread, so they can go ahead and try to init this.
173204 if let Some ( waiter) = init_once. waiters . pop_front ( ) {
174- this. unblock_thread ( waiter. thread ) ;
175-
176- // Call callback, with the woken-up thread as `current`.
177- this. set_active_thread ( waiter. thread ) ;
178- this. init_once_acquire ( id) ;
179- waiter. callback . call ( this) ?;
180- this. set_active_thread ( current_thread) ;
205+ this. init_once_wake_waiter ( id, waiter) ?;
181206 } else {
182207 // Nobody there to take this, so go back to 'uninit'
183208 init_once. status = InitOnceStatus :: Uninitialized ;
@@ -186,18 +211,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
186211 Ok ( ( ) )
187212 }
188213
189- /// Synchronize with the previous completion or failure of an InitOnce.
190- /// This is required to prevent data races .
214+ /// Synchronize with the previous completion of an InitOnce.
215+ /// Must only be called after checking that it is complete .
191216 #[ inline]
192- fn init_once_acquire ( & mut self , id : InitOnceId ) {
217+ fn init_once_observe_completed ( & mut self , id : InitOnceId ) {
193218 let this = self . eval_context_mut ( ) ;
194- let current_thread = this. get_active_thread ( ) ;
195219
196- if let Some ( data_race) = & this. machine . data_race {
197- data_race. validate_lock_acquire (
198- & this. machine . threads . sync . init_onces [ id] . data_race ,
199- current_thread,
200- ) ;
201- }
220+ assert_eq ! (
221+ this. init_once_status( id) ,
222+ InitOnceStatus :: Complete ,
223+ "observing the completion of incomplete init once"
224+ ) ;
225+
226+ this. init_once_observe_attempt ( id) ;
202227 }
203228}
0 commit comments