1
+ use std:: cell:: RefCell ;
1
2
use std:: collections:: VecDeque ;
2
-
3
- use rustc_index:: Idx ;
3
+ use std:: rc:: Rc ;
4
4
5
5
use super :: thread:: DynUnblockCallback ;
6
6
use super :: vector_clock:: VClock ;
7
7
use crate :: * ;
8
8
9
- super :: sync:: declare_id!( InitOnceId ) ;
10
-
11
9
#[ derive( Default , Debug , Copy , Clone , PartialEq , Eq ) ]
12
10
/// The current status of a one time initialization.
13
11
pub enum InitOnceStatus {
@@ -25,44 +23,70 @@ pub(super) struct InitOnce {
25
23
clock : VClock ,
26
24
}
27
25
28
- impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
29
- pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
26
+ impl InitOnce {
30
27
#[ inline]
31
- fn init_once_status ( & mut self , id : InitOnceId ) -> InitOnceStatus {
32
- let this = self . eval_context_ref ( ) ;
33
- this. machine . sync . init_onces [ id] . status
34
- }
35
-
36
- /// Put the thread into the queue waiting for the initialization.
37
- #[ inline]
38
- fn init_once_enqueue_and_block ( & mut self , id : InitOnceId , callback : DynUnblockCallback < ' tcx > ) {
39
- let this = self . eval_context_mut ( ) ;
40
- let thread = this. active_thread ( ) ;
41
- let init_once = & mut this. machine . sync . init_onces [ id] ;
42
- assert_ne ! ( init_once. status, InitOnceStatus :: Complete , "queueing on complete init once" ) ;
43
- init_once. waiters . push_back ( thread) ;
44
- this. block_thread ( BlockReason :: InitOnce ( id) , None , callback) ;
28
+ pub fn status ( & self ) -> InitOnceStatus {
29
+ self . status
45
30
}
46
31
47
32
/// Begin initializing this InitOnce. Must only be called after checking that it is currently
48
33
/// uninitialized.
49
34
#[ inline]
50
- fn init_once_begin ( & mut self , id : InitOnceId ) {
51
- let this = self . eval_context_mut ( ) ;
52
- let init_once = & mut this. machine . sync . init_onces [ id] ;
35
+ pub fn begin ( & mut self ) {
53
36
assert_eq ! (
54
- init_once . status,
37
+ self . status( ) ,
55
38
InitOnceStatus :: Uninitialized ,
56
39
"beginning already begun or complete init once"
57
40
) ;
58
- init_once . status = InitOnceStatus :: Begun ;
41
+ self . status = InitOnceStatus :: Begun ;
59
42
}
43
+ }
60
44
45
+ #[ derive( Default , Clone , Debug ) ]
46
+ pub struct InitOnceRef ( Rc < RefCell < InitOnce > > ) ;
47
+
48
+ impl InitOnceRef {
49
+ pub fn new ( ) -> Self {
50
+ Self ( Default :: default ( ) )
51
+ }
52
+
53
+ pub fn status ( & self ) -> InitOnceStatus {
54
+ self . 0 . borrow ( ) . status ( )
55
+ }
56
+
57
+ pub fn begin ( & self ) {
58
+ self . 0 . borrow_mut ( ) . begin ( ) ;
59
+ }
60
+ }
61
+
62
+ impl VisitProvenance for InitOnceRef {
63
+ // InitOnce contains no provenance.
64
+ fn visit_provenance ( & self , _visit : & mut VisitWith < ' _ > ) { }
65
+ }
66
+
67
+ impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
68
+ pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
69
+ /// Put the thread into the queue waiting for the initialization.
61
70
#[ inline]
62
- fn init_once_complete ( & mut self , id : InitOnceId ) -> InterpResult < ' tcx > {
71
+ fn init_once_enqueue_and_block (
72
+ & mut self ,
73
+ init_once_ref : InitOnceRef ,
74
+ callback : DynUnblockCallback < ' tcx > ,
75
+ ) {
63
76
let this = self . eval_context_mut ( ) ;
64
- let init_once = & mut this. machine . sync . init_onces [ id] ;
77
+ let thread = this. active_thread ( ) ;
78
+ let mut init_once = init_once_ref. 0 . borrow_mut ( ) ;
79
+ assert_ne ! ( init_once. status, InitOnceStatus :: Complete , "queueing on complete init once" ) ;
80
+
81
+ init_once. waiters . push_back ( thread) ;
82
+ this. block_thread ( BlockReason :: InitOnce , None , callback) ;
83
+ }
65
84
85
+ #[ inline]
86
+ fn init_once_complete ( & mut self , init_once_ref : & InitOnceRef ) -> InterpResult < ' tcx > {
87
+ let this = self . eval_context_mut ( ) ;
88
+
89
+ let mut init_once = init_once_ref. 0 . borrow_mut ( ) ;
66
90
assert_eq ! (
67
91
init_once. status,
68
92
InitOnceStatus :: Begun ,
@@ -79,17 +103,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
79
103
80
104
// Wake up everyone.
81
105
// need to take the queue to avoid having `this` be borrowed multiple times
82
- for waiter in std:: mem:: take ( & mut init_once. waiters ) {
83
- this. unblock_thread ( waiter, BlockReason :: InitOnce ( id) ) ?;
106
+ let waiters = std:: mem:: take ( & mut init_once. waiters ) ;
107
+ drop ( init_once) ;
108
+ for waiter in waiters {
109
+ this. unblock_thread ( waiter, BlockReason :: InitOnce ) ?;
84
110
}
85
111
86
112
interp_ok ( ( ) )
87
113
}
88
114
89
115
#[ inline]
90
- fn init_once_fail ( & mut self , id : InitOnceId ) -> InterpResult < ' tcx > {
116
+ fn init_once_fail ( & mut self , init_once_ref : & InitOnceRef ) -> InterpResult < ' tcx > {
91
117
let this = self . eval_context_mut ( ) ;
92
- let init_once = & mut this . machine . sync . init_onces [ id ] ;
118
+ let mut init_once = init_once_ref . 0 . borrow_mut ( ) ;
93
119
assert_eq ! (
94
120
init_once. status,
95
121
InitOnceStatus :: Begun ,
@@ -106,7 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
106
132
107
133
// Wake up one waiting thread, so they can go ahead and try to init this.
108
134
if let Some ( waiter) = init_once. waiters . pop_front ( ) {
109
- this. unblock_thread ( waiter, BlockReason :: InitOnce ( id) ) ?;
135
+ drop ( init_once) ;
136
+ this. unblock_thread ( waiter, BlockReason :: InitOnce ) ?;
110
137
}
111
138
112
139
interp_ok ( ( ) )
@@ -115,15 +142,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
115
142
/// Synchronize with the previous completion of an InitOnce.
116
143
/// Must only be called after checking that it is complete.
117
144
#[ inline]
118
- fn init_once_observe_completed ( & mut self , id : InitOnceId ) {
145
+ fn init_once_observe_completed ( & mut self , init_once_ref : & InitOnceRef ) {
119
146
let this = self . eval_context_mut ( ) ;
147
+ let init_once = init_once_ref. 0 . borrow ( ) ;
120
148
121
149
assert_eq ! (
122
- this . init_once_status ( id ) ,
150
+ init_once . status ,
123
151
InitOnceStatus :: Complete ,
124
152
"observing the completion of incomplete init once"
125
153
) ;
126
154
127
- this. acquire_clock ( & this . machine . sync . init_onces [ id ] . clock ) ;
155
+ this. acquire_clock ( & init_once . clock ) ;
128
156
}
129
157
}
0 commit comments