@@ -31,13 +31,12 @@ use tokio::{
3131 io:: { AsyncRead , AsyncReadExt , AsyncWriteExt } ,
3232 net:: { TcpListener , TcpStream } ,
3333 process:: { Child , ChildStdin , Command } ,
34+ sync:: Mutex ,
3435} ;
3536use tracing:: { error, warn} ;
37+ use validation:: { GoGlobalState , ValidationInput } ;
3638
37- use crate :: {
38- engine:: { config:: JitMachineConfig , execution:: ValidationRequest } ,
39- spawner_endpoints:: { local_target, GlobalState } ,
40- } ;
39+ use crate :: { engine:: config:: JitMachineConfig , spawner_endpoints:: local_target} ;
4140
4241const SUCCESS_BYTE : u8 = 0x0 ;
4342const FAILURE_BYTE : u8 = 0x1 ;
@@ -80,10 +79,12 @@ async fn read_bytes_with_len<R: AsyncRead + Unpin>(reader: &mut R) -> Result<Vec
8079
8180#[ derive( Debug ) ]
8281pub struct JitMachine {
83- pub process_stdin : Option < ChildStdin > ,
84- pub process : Child ,
82+ /// Handler to jit binary stdin. Instead of using Mutex<> for the entire
83+ /// JitMachine we chose to use a more granular Mutex<> to avoid contention
84+ pub process_stdin : Mutex < Option < ChildStdin > > ,
85+ /// Handler to jit binary process. Needs a Mutex<> to force quit on server shutdown
86+ pub process : Mutex < Child > ,
8587 pub wasm_memory_usage_limit : u64 ,
86- is_active : bool ,
8788}
8889
8990impl JitMachine {
@@ -136,39 +137,41 @@ impl JitMachine {
136137 . ok_or_else ( || anyhow ! ( "failed to open stdin to jit process" ) ) ?;
137138
138139 Ok ( Self {
139- process_stdin : Some ( stdin) ,
140- process : child,
140+ process_stdin : Mutex :: new ( Some ( stdin) ) ,
141+ process : Mutex :: new ( child) ,
141142 wasm_memory_usage_limit : config. wasm_memory_usage_limit ,
142- is_active : true ,
143143 } )
144144 }
145145
146- pub fn is_active ( & self ) -> bool {
147- self . is_active && self . process_stdin . is_some ( )
146+ pub async fn is_active ( & self ) -> bool {
147+ self . process_stdin . lock ( ) . await . is_some ( )
148148 }
149149
150- pub async fn feed_machine ( & mut self , request : & ValidationRequest ) -> Result < GlobalState > {
150+ pub async fn feed_machine ( & self , request : & ValidationInput ) -> Result < GoGlobalState > {
151151 // 1. Create new TCP connection
152152 // Binding with a port number of 0 will request that the OS assigns a port to this listener.
153153 let listener = TcpListener :: bind ( "127.0.0.1:0" )
154154 . await
155155 . context ( "failed to create TCP listener" ) ?;
156156
157- let mut state = GlobalState :: default ( ) ;
157+ let mut state = GoGlobalState :: default ( ) ;
158158
159159 let addr = listener. local_addr ( ) . context ( "failed to get local addr" ) ?;
160160
161161 // 2. Format the address string (Go: "%v\n")
162162 let address_str = format ! ( "{addr}\n " ) ;
163163
164164 // 3. Send TCP connection via stdin pipe
165- if let Some ( stdin) = & mut self . process_stdin {
166- stdin
167- . write_all ( address_str. as_bytes ( ) )
168- . await
169- . context ( "failed to write address to jit stdin" ) ?;
170- } else {
171- return Err ( anyhow ! ( "JIT machine stdin is not available" ) ) ;
165+ {
166+ let mut locked_process_stdin = self . process_stdin . lock ( ) . await ;
167+ if let Some ( stdin) = locked_process_stdin. as_mut ( ) {
168+ stdin
169+ . write_all ( address_str. as_bytes ( ) )
170+ . await
171+ . context ( "failed to write address to jit stdin" ) ?;
172+ } else {
173+ return Err ( anyhow ! ( "JIT machine stdin is not available" ) ) ;
174+ }
172175 }
173176
174177 // 4. Wait for the child to call us back
@@ -195,7 +198,7 @@ impl JitMachine {
195198 // 7. Send Delayed Inbox
196199 if request. has_delayed_msg {
197200 write_u8 ( & mut conn, ANOTHER_BYTE ) . await ?;
198- write_u64 ( & mut conn, request. delayed_msg_number ) . await ?;
201+ write_u64 ( & mut conn, request. delayed_msg_nr ) . await ?;
199202 write_bytes ( & mut conn, & request. delayed_msg ) . await ?;
200203 }
201204 write_u8 ( & mut conn, SUCCESS_BYTE ) . await ?;
@@ -232,7 +235,7 @@ impl JitMachine {
232235 write_u32 ( & mut conn, local_user_wasm. len ( ) as u32 ) . await ?;
233236 for ( module_hash, program) in local_user_wasm {
234237 write_exact ( & mut conn, & module_hash. 0 ) . await ?;
235- write_bytes ( & mut conn, program) . await ?;
238+ write_bytes ( & mut conn, & program. as_vec ( ) ) . await ?;
236239 }
237240
238241 // 10. Signal that we are done sending global state
@@ -272,20 +275,21 @@ impl JitMachine {
272275 }
273276 }
274277
275- pub async fn complete_machine ( & mut self ) -> Result < ( ) > {
278+ pub async fn complete_machine ( & self ) -> Result < ( ) > {
276279 // Close stdin. This sends EOF to the child process, signaling it to stop.
277280 // We take the Option to ensure it's dropped and cannot be used again.
278- if let Some ( stdin) = self . process_stdin . take ( ) {
281+
282+ let mut locked_process_stdin = self . process_stdin . lock ( ) . await ;
283+ if let Some ( stdin) = locked_process_stdin. take ( ) {
279284 drop ( stdin) ;
280285 }
281286
282- self . process
287+ let mut locked_process = self . process . lock ( ) . await ;
288+ locked_process
283289 . kill ( )
284290 . await
285291 . context ( "failed to kill jit process" ) ?;
286292
287- self . is_active = false ;
288-
289293 Ok ( ( ) )
290294 }
291295}
0 commit comments