@@ -141,18 +141,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
141141 // Wake up everyone.
142142 // need to take the queue to avoid having `this` be borrowed multiple times
143143 for waiter in std:: mem:: take ( & mut init_once. waiters ) {
144- // End of the wait happens-before woken-up thread.
145- if let Some ( data_race) = & this. machine . data_race {
146- data_race. validate_lock_acquire (
147- & this. machine . threads . sync . init_onces [ id] . data_race ,
148- waiter. thread ,
149- ) ;
150- }
151-
152144 this. unblock_thread ( waiter. thread ) ;
153145
154146 // Call callback, with the woken-up thread as `current`.
155147 this. set_active_thread ( waiter. thread ) ;
148+ this. init_once_acquire ( id) ;
156149 waiter. callback . call ( this) ?;
157150 this. set_active_thread ( current_thread) ;
158151 }
@@ -172,26 +165,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
172165 ) ;
173166
174167 // Each complete happens-before the end of the wait
175- // FIXME: should this really induce synchronization? If we think of it as a lock, then yes,
176- // but the docs don't talk about such details.
177168 if let Some ( data_race) = & this. machine . data_race {
178169 data_race. validate_lock_release ( & mut init_once. data_race , current_thread) ;
179170 }
180171
181172 // Wake up one waiting thread, so they can go ahead and try to init this.
182173 if let Some ( waiter) = init_once. waiters . pop_front ( ) {
183- // End of the wait happens-before woken-up thread.
184- if let Some ( data_race) = & this. machine . data_race {
185- data_race. validate_lock_acquire (
186- & this. machine . threads . sync . init_onces [ id] . data_race ,
187- waiter. thread ,
188- ) ;
189- }
190-
191174 this. unblock_thread ( waiter. thread ) ;
192175
193176 // Call callback, with the woken-up thread as `current`.
194177 this. set_active_thread ( waiter. thread ) ;
178+ this. init_once_acquire ( id) ;
195179 waiter. callback . call ( this) ?;
196180 this. set_active_thread ( current_thread) ;
197181 } else {
@@ -201,4 +185,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
201185
202186 Ok ( ( ) )
203187 }
188+
189+ /// Synchronize with the previous completion or failure of an InitOnce.
190+ /// This is required to prevent data races.
191+ #[ inline]
192+ fn init_once_acquire ( & mut self , id : InitOnceId ) {
193+ let this = self . eval_context_mut ( ) ;
194+ let current_thread = this. get_active_thread ( ) ;
195+
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+ }
202+ }
204203}
0 commit comments