Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/wasmtime/crates/lind-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ wasmtime = { workspace = true, features = ['threads'] }
wasmtime-environ = { workspace = true }
rawposix = { path = "../rawposix" }
wasmtime-lind-multi-process = { path = "../lind-multi-process" }
sysdefs = { path = "../sysdefs" }
66 changes: 50 additions & 16 deletions src/wasmtime/crates/lind-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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
Copy link
Contributor

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

// 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
}
}
}

Expand Down Expand Up @@ -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
},
)?;
Expand Down
14 changes: 10 additions & 4 deletions src/wasmtime/crates/lind-multi-process/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ impl<
// set up unwind callback function
let store = caller.as_context_mut().0;
let signal_asyncify_data = store.get_signal_asyncify_data();
let syscall_asyncify_data = store.get_syscall_asyncify_data();
let is_parent_thread = store.is_thread();
store.set_on_called(Box::new(move |mut store| {
// unwind finished and we need to stop the unwind
Expand Down Expand Up @@ -442,6 +443,11 @@ impl<

barrier_clone.wait();

let stack_pointer_setter = instance
.get_typed_func::<i32, ()>(&mut store, "set_stack_pointer")
.unwrap();
let _ = stack_pointer_setter.call(&mut store, stack_pointer as i32);

// get the asyncify_rewind_start and module start function
let child_rewind_start;

Expand Down Expand Up @@ -482,6 +488,9 @@ impl<
store
.as_context_mut()
.set_signal_asyncify_data(signal_asyncify_data);
store
.as_context_mut()
.set_syscall_asyncify_data(syscall_asyncify_data);

let invoke_res = child_start_func.call(&mut store, &values, &mut results);

Expand Down Expand Up @@ -966,12 +975,9 @@ impl<
// for exec, we do not need to do rewind after unwinding is done
store.set_asyncify_state(AsyncifyState::Normal);

// to-do: exec should not change the process id/cage id, however, the exec call from rustposix takes an
// argument to change the process id. If we pass the same cageid, it would cause some error
// lind_exec(cloned_pid as u64, cloned_pid as u64);
lind_syscall_api(
cloned_pid as u64,
EXEC_SYSCALL as u32, // exec syscall
EXEC_SYSCALL as u32,
0,
0,
0,
Expand Down
2 changes: 1 addition & 1 deletion src/wasmtime/crates/wasmtime/src/runtime/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
use alloc::sync::Arc;
use core::ptr::NonNull;
use rawposix::safeposix::dispatcher::lind_syscall_api;
use sysdefs::constants::fs_const::{
use sysdefs::constants::{
MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PAGESHIFT, PROT_READ, PROT_WRITE,
};
use wasmparser::WasmFeatures;
Expand Down
48 changes: 47 additions & 1 deletion src/wasmtime/crates/wasmtime/src/runtime/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -3218,4 +3264,4 @@ mod tests {
assert_eq!(tank.consumed_fuel, 4);
assert_eq!(tank.get_fuel(), 0);
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add new line

Loading