-
Notifications
You must be signed in to change notification settings - Fork 12
wasmtime - asyncify & signal interruption #349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ use anyhow::Result; | |
use rawposix::safeposix::dispatcher::lind_syscall_api; | ||
use std::sync::atomic::{AtomicU64, Ordering}; | ||
use std::sync::Arc; | ||
use wasmtime::Caller; | ||
use wasmtime::{AsContext, AsContextMut, AsyncifyState, Caller}; | ||
use wasmtime_lind_multi_process::{clone_constants::CloneArgStruct, get_memory_base, LindHost}; | ||
|
||
// lind-common serves as the main entry point when lind_syscall. Any syscalls made in glibc would reach here first, | ||
|
@@ -42,7 +42,7 @@ impl LindCommonCtx { | |
&self, | ||
call_number: u32, | ||
call_name: u64, | ||
caller: &mut Caller<'_, T>, | ||
mut caller: &mut Caller<'_, T>, | ||
arg1: u64, | ||
arg2: u64, | ||
arg3: u64, | ||
|
@@ -68,17 +68,54 @@ impl LindCommonCtx { | |
// exit syscall | ||
30 => wasmtime_lind_multi_process::exit_syscall(caller, arg1 as i32), | ||
// other syscalls goes into rawposix | ||
_ => lind_syscall_api( | ||
self.pid as u64, | ||
call_number, | ||
call_name, | ||
arg1, | ||
arg2, | ||
arg3, | ||
arg4, | ||
arg5, | ||
arg6, | ||
), | ||
_ => { | ||
// if we are reaching here at rewind state, that means fork is called within | ||
// syscall interrupted signals. We should restore the return value of syscall | ||
if let AsyncifyState::Rewind(_) = caller.as_context().get_asyncify_state() { | ||
// retrieve the return value of last syscall | ||
let retval = caller | ||
.as_context_mut() | ||
.get_current_syscall_rewind_data() | ||
.unwrap(); | ||
// let signal handler finish rest of the rewinding process | ||
wasmtime_lind_multi_process::signal::signal_handler(&mut caller); | ||
// return the return value of last syscall | ||
return retval; | ||
} | ||
|
||
let retval = lind_syscall_api( | ||
self.pid as u64, | ||
call_number, | ||
call_name, | ||
arg1, | ||
arg2, | ||
arg3, | ||
arg4, | ||
arg5, | ||
arg6, | ||
); | ||
|
||
// Assumption: lind_syscall_api will not switch asyncify state, which holds true for now | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we have an assumption like this we need to explain why its true |
||
|
||
// if the syscall is interrupted by signal | ||
if -retval == sysdefs::constants::Errno::EINTR as i32 { | ||
// store the return value of the syscall | ||
caller.as_context_mut().append_syscall_asyncify_data(retval); | ||
// run the signal handler | ||
wasmtime_lind_multi_process::signal::signal_handler(&mut caller); | ||
|
||
// if fork is invoked within signal handler and switched asyncify state to unwind | ||
if caller.as_context().get_asyncify_state() == AsyncifyState::Unwind { | ||
// return immediately | ||
return 0; | ||
} else { | ||
// otherwise, pop the retval of the syscall | ||
caller.as_context_mut().pop_syscall_asyncify_data(); | ||
} | ||
} | ||
|
||
retval | ||
} | ||
} | ||
} | ||
|
||
|
@@ -179,9 +216,6 @@ pub fn add_to_linker< | |
arg6, | ||
); | ||
|
||
// TODO: add a signal check here as Linux also has a signal check when transition from kernel to userspace | ||
// However, Asyncify management in this function should be carefully rethinking if adding signal check here | ||
|
||
retval | ||
}, | ||
)?; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -338,8 +338,13 @@ pub struct StoreOpaque { | |
host_globals: Vec<StoreBox<VMHostGlobalContext>>, | ||
|
||
asyncify_state: AsyncifyState, | ||
// signal asyncify data, holds the sequence of the parameters for signal handler | ||
signal_asyncify_data: Vec<SignalAsyncifyData>, | ||
signal_asyncify_counter: u64, | ||
// syscall asyncify data, holds the sequence of syscall return value | ||
syscall_asyncify_data: Vec<i32>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe naming as sth like sys_return_async would be clearer? |
||
syscall_asyncify_counter: u64, | ||
|
||
// stack top | ||
stack_top: u64, | ||
// stack bottom | ||
|
@@ -548,6 +553,8 @@ impl<T> Store<T> { | |
asyncify_state: super::AsyncifyState::Normal, | ||
signal_asyncify_data: Vec::new(), | ||
signal_asyncify_counter: 0, | ||
syscall_asyncify_data: Vec::new(), | ||
syscall_asyncify_counter: 0, | ||
#[cfg(feature = "component-model")] | ||
num_component_instances: 0, | ||
signal_handler: None, | ||
|
@@ -660,6 +667,8 @@ impl<T> Store<T> { | |
asyncify_state: super::AsyncifyState::Normal, | ||
signal_asyncify_data: Vec::new(), | ||
signal_asyncify_counter: 0, | ||
syscall_asyncify_data: Vec::new(), | ||
syscall_asyncify_counter: 0, | ||
#[cfg(feature = "component-model")] | ||
num_component_instances: 0, | ||
signal_handler: None, | ||
|
@@ -1428,6 +1437,39 @@ impl<'a, T> StoreContextMut<'a, T> { | |
self.0.signal_asyncify_counter = 0; | ||
} | ||
|
||
// append the syscall retval information | ||
pub fn append_syscall_asyncify_data(&mut self, retval: i32) { | ||
self.0.syscall_asyncify_data.push(retval); | ||
} | ||
|
||
// pop the syscall retval information | ||
pub fn pop_syscall_asyncify_data(&mut self) { | ||
self.0.syscall_asyncify_data.pop(); | ||
} | ||
|
||
// get the current syscall retval information | ||
pub fn get_current_syscall_rewind_data(&mut self) -> Option<i32> { | ||
let data = self | ||
.0 | ||
.syscall_asyncify_data | ||
.get(self.0.syscall_asyncify_counter as usize) | ||
.cloned(); | ||
let length = self.0.syscall_asyncify_data.len(); | ||
if self.0.syscall_asyncify_counter == (length - 1) as u64 { | ||
self.0.syscall_asyncify_counter = 0; | ||
} else { | ||
self.0.syscall_asyncify_counter += 1; | ||
} | ||
data | ||
} | ||
|
||
// set the syscall retval information | ||
// used by fork to copy asyncify information | ||
pub fn set_syscall_asyncify_data(&mut self, data: Vec<i32>) { | ||
self.0.syscall_asyncify_data = data; | ||
self.0.syscall_asyncify_counter = 0; | ||
} | ||
|
||
/// get stack top | ||
pub fn get_stack_top(&self) -> u64 { | ||
self.0.stack_top | ||
|
@@ -2982,6 +3024,10 @@ impl<T> StoreInner<T> { | |
self.signal_asyncify_data.clone() | ||
} | ||
|
||
pub fn get_syscall_asyncify_data(&mut self) -> Vec<i32> { | ||
self.syscall_asyncify_data.clone() | ||
} | ||
|
||
pub fn is_thread(&self) -> bool { | ||
self.is_thread | ||
} | ||
|
@@ -3218,4 +3264,4 @@ mod tests { | |
assert_eq!(tank.consumed_fuel, 4); | ||
assert_eq!(tank.get_fuel(), 0); | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add new line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment could be a bit more verbose, im not sure whats going on here exactly