1+ use std:: cell:: RefCell ;
12use std:: collections:: VecDeque ;
2-
3- use rustc_index:: Idx ;
3+ use std:: rc:: Rc ;
44
55use super :: thread:: DynUnblockCallback ;
66use super :: vector_clock:: VClock ;
77use crate :: * ;
88
9- super :: sync:: declare_id!( InitOnceId ) ;
10-
119#[ derive( Default , Debug , Copy , Clone , PartialEq , Eq ) ]
1210/// The current status of a one time initialization.
1311pub enum InitOnceStatus {
@@ -25,44 +23,70 @@ pub(super) struct InitOnce {
2523 clock : VClock ,
2624}
2725
28- impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
29- pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
26+ impl InitOnce {
3027 #[ 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
4530 }
4631
4732 /// Begin initializing this InitOnce. Must only be called after checking that it is currently
4833 /// uninitialized.
4934 #[ 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 ) {
5336 assert_eq ! (
54- init_once . status,
37+ self . status( ) ,
5538 InitOnceStatus :: Uninitialized ,
5639 "beginning already begun or complete init once"
5740 ) ;
58- init_once . status = InitOnceStatus :: Begun ;
41+ self . status = InitOnceStatus :: Begun ;
5942 }
43+ }
6044
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.
6170 #[ 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+ ) {
6376 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+ }
6584
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 ( ) ;
6690 assert_eq ! (
6791 init_once. status,
6892 InitOnceStatus :: Begun ,
@@ -79,17 +103,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
79103
80104 // Wake up everyone.
81105 // 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 ) ?;
84110 }
85111
86112 interp_ok ( ( ) )
87113 }
88114
89115 #[ 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 > {
91117 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 ( ) ;
93119 assert_eq ! (
94120 init_once. status,
95121 InitOnceStatus :: Begun ,
@@ -106,7 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
106132
107133 // Wake up one waiting thread, so they can go ahead and try to init this.
108134 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 ) ?;
110137 }
111138
112139 interp_ok ( ( ) )
@@ -115,15 +142,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
115142 /// Synchronize with the previous completion of an InitOnce.
116143 /// Must only be called after checking that it is complete.
117144 #[ inline]
118- fn init_once_observe_completed ( & mut self , id : InitOnceId ) {
145+ fn init_once_observe_completed ( & mut self , init_once_ref : & InitOnceRef ) {
119146 let this = self . eval_context_mut ( ) ;
147+ let init_once = init_once_ref. 0 . borrow ( ) ;
120148
121149 assert_eq ! (
122- this . init_once_status ( id ) ,
150+ init_once . status ,
123151 InitOnceStatus :: Complete ,
124152 "observing the completion of incomplete init once"
125153 ) ;
126154
127- this. acquire_clock ( & this . machine . sync . init_onces [ id ] . clock ) ;
155+ this. acquire_clock ( & init_once . clock ) ;
128156 }
129157}
0 commit comments