@@ -4,29 +4,11 @@ use rustc_index::Idx;
4
4
use rustc_middle:: ty:: layout:: TyAndLayout ;
5
5
6
6
use super :: sync:: EvalContextExtPriv as _;
7
- use super :: thread:: MachineCallback ;
8
7
use super :: vector_clock:: VClock ;
9
8
use crate :: * ;
10
9
11
10
declare_id ! ( InitOnceId ) ;
12
11
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
-
30
12
#[ derive( Default , Debug , Copy , Clone , PartialEq , Eq ) ]
31
13
/// The current status of a one time initialization.
32
14
pub enum InitOnceStatus {
@@ -38,68 +20,14 @@ pub enum InitOnceStatus {
38
20
39
21
/// The one time initialization state.
40
22
#[ derive( Default , Debug ) ]
41
- pub ( super ) struct InitOnce < ' mir , ' tcx > {
23
+ pub ( super ) struct InitOnce {
42
24
status : InitOnceStatus ,
43
- waiters : VecDeque < InitOnceWaiter < ' mir , ' tcx > > ,
25
+ waiters : VecDeque < ThreadId > ,
44
26
clock : VClock ,
45
27
}
46
28
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
-
55
29
impl < ' mir , ' tcx : ' mir > EvalContextExtPriv < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
56
30
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. 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
-
103
31
/// Provides the closure with the next InitOnceId. Creates that InitOnce if the closure returns None,
104
32
/// otherwise returns the value from the closure.
105
33
#[ inline]
@@ -120,6 +48,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
120
48
Ok ( new_index)
121
49
}
122
50
}
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
+ }
123
66
124
67
#[ inline]
125
68
fn init_once_status ( & mut self , id : InitOnceId ) -> InitOnceStatus {
@@ -132,14 +75,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
132
75
fn init_once_enqueue_and_block (
133
76
& mut self ,
134
77
id : InitOnceId ,
135
- thread : ThreadId ,
136
- callback : Box < dyn MachineCallback < ' mir , ' tcx > + ' tcx > ,
78
+ callback : impl UnblockCallback < ' mir , ' tcx > + ' tcx ,
137
79
) {
138
80
let this = self . eval_context_mut ( ) ;
81
+ let thread = this. active_thread ( ) ;
139
82
let init_once = & mut this. machine . sync . init_onces [ id] ;
140
83
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 ) ;
143
86
}
144
87
145
88
/// 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> {
177
120
// Wake up everyone.
178
121
// need to take the queue to avoid having `this` be borrowed multiple times
179
122
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 ) ) ?;
181
124
}
182
125
183
126
Ok ( ( ) )
@@ -192,6 +135,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
192
135
InitOnceStatus :: Begun ,
193
136
"failing already completed or uninit init once"
194
137
) ;
138
+ // This is again uninitialized.
139
+ init_once. status = InitOnceStatus :: Uninitialized ;
195
140
196
141
// Each complete happens-before the end of the wait
197
142
if let Some ( data_race) = & this. machine . data_race {
@@ -200,10 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
200
145
201
146
// Wake up one waiting thread, so they can go ahead and try to init this.
202
147
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) ) ?;
207
149
}
208
150
209
151
Ok ( ( ) )
@@ -221,6 +163,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
221
163
"observing the completion of incomplete init once"
222
164
) ;
223
165
224
- this. init_once_observe_attempt ( id ) ;
166
+ this. acquire_clock ( & this . machine . sync . init_onces [ id ] . clock ) ;
225
167
}
226
168
}
0 commit comments