@@ -3,7 +3,7 @@ use std::num::NonZeroU32;
3
3
4
4
use rustc_index:: vec:: Idx ;
5
5
6
- use super :: sync:: EvalContextExtPriv ;
6
+ use super :: sync:: EvalContextExtPriv as _ ;
7
7
use super :: thread:: MachineCallback ;
8
8
use super :: vector_clock:: VClock ;
9
9
use crate :: * ;
@@ -52,6 +52,43 @@ impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> {
52
52
}
53
53
}
54
54
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
+
55
92
impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
56
93
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
57
94
fn init_once_get_or_create_id (
@@ -141,13 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
141
178
// Wake up everyone.
142
179
// need to take the queue to avoid having `this` be borrowed multiple times
143
180
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) ?;
151
182
}
152
183
153
184
Ok ( ( ) )
@@ -171,13 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
171
202
172
203
// Wake up one waiting thread, so they can go ahead and try to init this.
173
204
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) ?;
181
206
} else {
182
207
// Nobody there to take this, so go back to 'uninit'
183
208
init_once. status = InitOnceStatus :: Uninitialized ;
@@ -186,18 +211,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
186
211
Ok ( ( ) )
187
212
}
188
213
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 .
191
216
#[ inline]
192
- fn init_once_acquire ( & mut self , id : InitOnceId ) {
217
+ fn init_once_observe_completed ( & mut self , id : InitOnceId ) {
193
218
let this = self . eval_context_mut ( ) ;
194
- let current_thread = this. get_active_thread ( ) ;
195
219
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) ;
202
227
}
203
228
}
0 commit comments