@@ -10,20 +10,23 @@ use crate::host::wasm_common::module_host_actor::{
1010use crate :: host:: ArgsTuple ;
1111use crate :: { host:: Scheduler , module_host_context:: ModuleCreationContext , replica_context:: ReplicaContext } ;
1212use anyhow:: anyhow;
13- use std:: time:: Instant ;
13+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
14+ use core:: time:: Duration ;
1415use de:: deserialize_js;
1516use error:: { catch_exception, exception_already_thrown, log_traceback, ExcResult , Throwable } ;
1617use from_value:: cast;
1718use key_cache:: get_or_create_key_cache;
1819use ser:: serialize_to_js;
19- use spacetimedb_client_api_messages:: energy:: { EnergyQuanta , ReducerBudget } ;
20+ use spacetimedb_client_api_messages:: energy:: ReducerBudget ;
2021use spacetimedb_datastore:: locking_tx_datastore:: MutTxId ;
2122use spacetimedb_datastore:: traits:: Program ;
2223use spacetimedb_lib:: RawModuleDef ;
2324use spacetimedb_lib:: { ConnectionId , Identity } ;
2425use spacetimedb_schema:: auto_migrate:: MigrationPolicy ;
2526use std:: sync:: { Arc , LazyLock } ;
26- use v8:: { Context , ContextOptions , ContextScope , Function , HandleScope , Isolate , Local , Value } ;
27+ use std:: thread;
28+ use std:: time:: Instant ;
29+ use v8:: { Context , ContextOptions , ContextScope , Function , HandleScope , Isolate , IsolateHandle , Local , Value } ;
2730
2831mod de;
2932mod error;
@@ -152,25 +155,28 @@ impl ModuleInstance for JsInstance {
152155 tx,
153156 params,
154157 log_traceback,
155- |tx, op, _budget | {
158+ |tx, op, budget | {
156159 // TODO(centril): snapshots, module->host calls
157160 // Setup V8 scope.
158161 let mut isolate: v8:: OwnedIsolate = Isolate :: new ( <_ >:: default ( ) ) ;
162+ let isolate_handle = isolate. thread_safe_handle ( ) ;
159163 let mut scope_1 = HandleScope :: new ( & mut isolate) ;
160164 let context = Context :: new ( & mut scope_1, ContextOptions :: default ( ) ) ;
161165 let mut scope_2 = ContextScope :: new ( & mut scope_1, context) ;
162166
167+ let timeout_thread_cancel_flag = run_reducer_timeout ( isolate_handle, budget) ;
168+
163169 // Call the reducer.
164170 let start = Instant :: now ( ) ;
165171 let call_result = call_call_reducer_from_op ( & mut scope_2, op) ;
166172 let total_duration = start. elapsed ( ) ;
173+ // Cancel the execution timeout in `run_reducer_timeout`.
174+ timeout_thread_cancel_flag. store ( true , Ordering :: Relaxed ) ;
167175
168- // TODO(centril): energy metrering.
169- let energy = EnergyStats {
170- used : EnergyQuanta :: ZERO ,
171- wasmtime_fuel_used : 0 ,
172- remaining : ReducerBudget :: ZERO ,
173- } ;
176+ // Handle energy and timings.
177+ let used = duration_to_budget ( total_duration) ;
178+ let remaining = budget - used;
179+ let energy = EnergyStats { budget, remaining } ;
174180 let timings = ExecutionTimings {
175181 total_duration,
176182 // TODO(centril): call times.
@@ -195,6 +201,41 @@ impl ModuleInstance for JsInstance {
195201 }
196202}
197203
204+ fn run_reducer_timeout ( isolate_handle : IsolateHandle , budget : ReducerBudget ) -> Arc < AtomicBool > {
205+ let execution_done_flag = Arc :: new ( AtomicBool :: new ( false ) ) ;
206+ let execution_done_flag2 = execution_done_flag. clone ( ) ;
207+ let timeout = budget_to_duration ( budget) ;
208+
209+ // TODO(centril): Using an OS thread is a bit heavy handed...?
210+ thread:: spawn ( move || {
211+ // Sleep until the timeout.
212+ thread:: sleep ( timeout) ;
213+
214+ if execution_done_flag2. load ( Ordering :: Relaxed ) {
215+ // The reducer completed successfully.
216+ return ;
217+ }
218+
219+ // Reducer is still running.
220+ // Terminate V8 execution.
221+ isolate_handle. terminate_execution ( ) ;
222+ } ) ;
223+
224+ execution_done_flag
225+ }
226+
227+ fn budget_to_duration ( _budget : ReducerBudget ) -> Duration {
228+ // TODO(centril): This is fake logic that allows a maximum timeout.
229+ // Replace with sensible math.
230+ Duration :: MAX
231+ }
232+
233+ fn duration_to_budget ( _duration : Duration ) -> ReducerBudget {
234+ // TODO(centril): This is fake logic that allows minimum energy usage.
235+ // Replace with sensible math.
236+ ReducerBudget :: ZERO
237+ }
238+
198239/// Returns the global property `key`.
199240fn get_global_property < ' scope > (
200241 scope : & mut HandleScope < ' scope > ,
0 commit comments