@@ -141,18 +141,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
141
141
// Wake up everyone.
142
142
// need to take the queue to avoid having `this` be borrowed multiple times
143
143
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
-
152
144
this. unblock_thread ( waiter. thread ) ;
153
145
154
146
// Call callback, with the woken-up thread as `current`.
155
147
this. set_active_thread ( waiter. thread ) ;
148
+ this. init_once_acquire ( id) ;
156
149
waiter. callback . call ( this) ?;
157
150
this. set_active_thread ( current_thread) ;
158
151
}
@@ -172,26 +165,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
172
165
) ;
173
166
174
167
// 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.
177
168
if let Some ( data_race) = & this. machine . data_race {
178
169
data_race. validate_lock_release ( & mut init_once. data_race , current_thread) ;
179
170
}
180
171
181
172
// Wake up one waiting thread, so they can go ahead and try to init this.
182
173
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
-
191
174
this. unblock_thread ( waiter. thread ) ;
192
175
193
176
// Call callback, with the woken-up thread as `current`.
194
177
this. set_active_thread ( waiter. thread ) ;
178
+ this. init_once_acquire ( id) ;
195
179
waiter. callback . call ( this) ?;
196
180
this. set_active_thread ( current_thread) ;
197
181
} else {
@@ -201,4 +185,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
201
185
202
186
Ok ( ( ) )
203
187
}
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
+ }
204
203
}
0 commit comments