@@ -17,7 +17,7 @@ use crate::*;
1717
1818pub ( crate ) enum ReasonToBreak {
1919 Errored ( Error ) ,
20- Suspended ( SuspendReason ) ,
20+ Suspended ( SuspendReason , Option < SuspendedHostCoroState > ) ,
2121 Finished ,
2222}
2323
@@ -40,18 +40,17 @@ pub(crate) struct SuspendedHostCoroState {
4040pub ( crate ) struct Executor < ' store , ' stack > {
4141 pub ( crate ) cf : CallFrame ,
4242 pub ( crate ) module : ModuleInstance ,
43- pub ( crate ) suspended_host_coro : Option < SuspendedHostCoroState > ,
4443 pub ( crate ) store : & ' store mut Store ,
4544 pub ( crate ) stack : & ' stack mut Stack ,
4645}
4746
48- pub ( crate ) type ExecOutcome = coro:: CoroStateResumeResult < ( ) > ;
47+ pub ( crate ) type ExecOutcome = coro:: PotentialCoroCallResult < ( ) , Option < SuspendedHostCoroState > > ;
4948
5049impl < ' store , ' stack > Executor < ' store , ' stack > {
5150 pub ( crate ) fn new ( store : & ' store mut Store , stack : & ' stack mut Stack ) -> Result < Self > {
5251 let current_frame = stack. call_stack . pop ( ) . expect ( "no call frame, this is a bug" ) ;
5352 let current_module = store. get_module_instance_raw ( current_frame. module_addr ( ) ) ;
54- Ok ( Self { cf : current_frame, module : current_module, suspended_host_coro : None , stack, store } )
53+ Ok ( Self { cf : current_frame, module : current_module, stack, store } )
5554 }
5655
5756 #[ inline( always) ]
@@ -60,38 +59,51 @@ impl<'store, 'stack> Executor<'store, 'stack> {
6059 if let ControlFlow :: Break ( res) = self . exec_next ( ) {
6160 return match res {
6261 ReasonToBreak :: Errored ( e) => Err ( e) ,
63- ReasonToBreak :: Suspended ( suspend_reason) => Ok ( ExecOutcome :: Suspended ( suspend_reason) ) ,
62+ ReasonToBreak :: Suspended ( suspend_reason, coro_state) => {
63+ Ok ( ExecOutcome :: Suspended ( suspend_reason, coro_state) )
64+ }
6465 ReasonToBreak :: Finished => Ok ( ExecOutcome :: Return ( ( ) ) ) ,
6566 } ;
6667 }
6768 }
6869 }
6970
71+ // on error running suspended_coro, returns it
72+ // so that it could be retried later
7073 #[ inline( always) ]
71- pub ( crate ) fn resume ( & mut self , res_arg : ResumeArgument ) -> Result < ExecOutcome > {
72- if let Some ( coro_state) = self . suspended_host_coro . as_mut ( ) {
74+ pub ( crate ) fn resume (
75+ & mut self ,
76+ res_arg : ResumeArgument ,
77+ mut suspended_coro : Option < SuspendedHostCoroState > ,
78+ ) -> Result < ExecOutcome , ( Error , Option < SuspendedHostCoroState > ) > {
79+ if let Some ( coro_state) = suspended_coro. as_mut ( ) {
7380 let ctx = FuncContext { store : self . store , module_addr : self . module . id ( ) } ;
74- let host_res = coro_state. coro_state . resume ( ctx, res_arg) ?;
81+ let host_res = match coro_state. coro_state . resume ( ctx, res_arg) {
82+ Ok ( val) => val,
83+ Err ( err) => return Err ( ( err, suspended_coro) ) ,
84+ } ;
85+
7586 let res = match host_res {
7687 CoroStateResumeResult :: Return ( res) => res,
7788 CoroStateResumeResult :: Suspended ( suspend_reason) => {
78- return Ok ( ExecOutcome :: Suspended ( suspend_reason) ) ;
89+ return Ok ( ExecOutcome :: Suspended ( suspend_reason, suspended_coro ) ) ;
7990 }
8091 } ;
8192 self . stack . values . extend_from_wasmvalues ( & res) ;
82- self . suspended_host_coro = None ;
8393
8494 // we don't know how much time we spent in host function
85- if let ControlFlow :: Break ( ReasonToBreak :: Suspended ( reason) ) = self . check_should_suspend ( ) {
86- return Ok ( ExecOutcome :: Suspended ( reason) ) ;
95+ if let ControlFlow :: Break ( ReasonToBreak :: Suspended ( reason, coro_state ) ) = self . check_should_suspend ( ) {
96+ return Ok ( ExecOutcome :: Suspended ( reason, coro_state ) ) ;
8797 }
8898 }
8999
90100 loop {
91101 if let ControlFlow :: Break ( res) = self . exec_next ( ) {
92102 return match res {
93- ReasonToBreak :: Errored ( e) => Err ( e) ,
94- ReasonToBreak :: Suspended ( suspend_reason) => Ok ( ExecOutcome :: Suspended ( suspend_reason) ) ,
103+ ReasonToBreak :: Errored ( e) => Err ( ( e, None ) ) ,
104+ ReasonToBreak :: Suspended ( suspend_reason, coro_state) => {
105+ Ok ( ExecOutcome :: Suspended ( suspend_reason, coro_state) )
106+ }
95107 ReasonToBreak :: Finished => Ok ( ExecOutcome :: Return ( ( ) ) ) ,
96108 } ;
97109 }
@@ -102,28 +114,28 @@ impl<'store, 'stack> Executor<'store, 'stack> {
102114 /// called when execution loops back, because that might happen indefinite amount of times
103115 /// and before and after function calls, because even without loops or infinite recursion, wasm function calls
104116 /// can mutliply time spent in execution
105- /// execution may not be suspended in the middle of execution the funcion :
117+ /// execution may not be suspended in the middle of execution the innsruction (without rolling back its effects) :
106118 /// so only do it as the last thing or first thing in the intsruction execution
107119 #[ must_use = "If this returns ControlFlow::Break, the caller should propagate it" ]
108120 fn check_should_suspend ( & mut self ) -> ControlFlow < ReasonToBreak > {
109121 if let Some ( flag) = & self . store . suspend_cond . suspend_flag {
110122 if flag. load ( core:: sync:: atomic:: Ordering :: Acquire ) {
111- return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedFlag ) . into ( ) ;
123+ return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedFlag , None ) . into ( ) ;
112124 }
113125 }
114126
115127 #[ cfg( feature = "std" ) ]
116128 if let Some ( when) = & self . store . suspend_cond . timeout_instant {
117129 if crate :: std:: time:: Instant :: now ( ) >= * when {
118- return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedEpoch ) . into ( ) ;
130+ return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedEpoch , None ) . into ( ) ;
119131 }
120132 }
121133
122134 if let Some ( mut cb) = self . store . suspend_cond . suspend_cb . take ( ) {
123135 let should_suspend = matches ! ( cb( self . store) , ControlFlow :: Break ( ( ) ) ) ;
124136 self . store . suspend_cond . suspend_cb = Some ( cb) ; // put it back
125137 if should_suspend {
126- return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedCallback ) . into ( ) ;
138+ return ReasonToBreak :: Suspended ( SuspendReason :: SuspendedCallback , None ) . into ( ) ;
127139 }
128140 }
129141
@@ -425,10 +437,9 @@ impl<'store, 'stack> Executor<'store, 'stack> {
425437 ControlFlow :: Continue ( ( ) )
426438 }
427439 PotentialCoroCallResult :: Suspended ( suspend_reason, state) => {
428- self . suspended_host_coro =
429- Some ( SuspendedHostCoroState { coro_state : state, coro_orig_function : func_ref } ) ;
440+ let coro_state = Some ( SuspendedHostCoroState { coro_state : state, coro_orig_function : func_ref } ) ;
430441 self . cf . incr_instr_ptr ( ) ;
431- ReasonToBreak :: Suspended ( suspend_reason) . into ( )
442+ ReasonToBreak :: Suspended ( suspend_reason, coro_state ) . into ( )
432443 }
433444 }
434445 }
0 commit comments