Skip to content

Commit

Permalink
Add proper posix_spawn support without needing asyncify
Browse files Browse the repository at this point in the history
  • Loading branch information
Arshia001 committed Feb 24, 2025
1 parent 760022a commit acf244f
Show file tree
Hide file tree
Showing 24 changed files with 878 additions and 56 deletions.
87 changes: 87 additions & 0 deletions lib/wasi-types/src/wasi/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,93 @@ impl core::fmt::Debug for Signal {
}
}
}

#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, num_enum :: TryFromPrimitive, Hash)]
pub enum SigAction {
Default,
Ignore,
}
impl core::fmt::Debug for SigAction {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SigAction::Default => f.debug_tuple("SigAction::Default").finish(),
SigAction::Ignore => f.debug_tuple("SigAction::Ignore").finish(),
}
}
}

#[doc = " A signal and its corresponding action."]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct SignalAndAction {
pub sig: Signal,
pub act: SigAction,
}
impl core::fmt::Debug for SignalAndAction {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SignalAndAction")
.field("sig", &self.sig)
.field("act", &self.act)
.finish()
}
}

#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, num_enum :: TryFromPrimitive, Hash)]
pub enum ProcSpawnFdOpName {
Close,
Dup2,
Open,
Chdir,
Fchdir,
}
impl core::fmt::Debug for ProcSpawnFdOpName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ProcSpawnFdOpName::Close => f.debug_tuple("ProcSpawnFdOpName::Close").finish(),
ProcSpawnFdOpName::Dup2 => f.debug_tuple("ProcSpawnFdOpName::Dup2").finish(),
ProcSpawnFdOpName::Open => f.debug_tuple("ProcSpawnFdOpName::Open").finish(),
ProcSpawnFdOpName::Chdir => f.debug_tuple("ProcSpawnFdOpName::Chdir").finish(),
ProcSpawnFdOpName::Fchdir => f.debug_tuple("ProcSpawnFdOpName::Fchdir").finish(),
}
}
}

#[doc = " An FD operation performed during proc_spawn2, which is the backing syscall for posix_spawn."]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ProcSpawnFdOp<M: MemorySize> {
pub cmd: ProcSpawnFdOpName,
pub fd: Fd,
pub src_fd: Fd,
pub name: M::Offset,
pub name_len: M::Offset,
pub dirflags: LookupFlags,
pub oflags: Oflags,
pub fs_rights_base: Rights,
pub fs_rights_inheriting: Rights,
pub fdflags: Fdflags,
pub fdflagsext: Fdflagsext,
}
impl<M: MemorySize> core::fmt::Debug for ProcSpawnFdOp<M> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ProcSpawnFdOp")
.field("cmd", &self.cmd)
.field("fd", &self.fd)
.field("src_fd", &self.src_fd)
.field("name", &self.name)
.field("name_len", &self.name_len)
.field("dirflags", &self.dirflags)
.field("oflags", &self.oflags)
.field("fs_rights_base", &self.fs_rights_base)
.field("fs_rights_inheriting", &self.fs_rights_inheriting)
.field("fdflags", &self.fdflags)
.field("fdflagsext", &self.fdflagsext)
.finish()
}
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AddrUnspec {
Expand Down
15 changes: 13 additions & 2 deletions lib/wasi-types/src/wasi/wasix_manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use std::mem::MaybeUninit;
use wasmer::{FromToNativeWasmType, MemorySize, ValueType};

use super::{
Errno, ErrnoSignal, EventFdReadwrite, Eventtype, Fd, JoinStatusType, Signal,
Snapshot0SubscriptionClock, SubscriptionClock, SubscriptionFsReadwrite, Userdata,
Errno, ErrnoSignal, EventFdReadwrite, Eventtype, Fd, JoinStatusType, ProcSpawnFdOp, Signal,
SignalAndAction, Snapshot0SubscriptionClock, SubscriptionClock, SubscriptionFsReadwrite,
Userdata,
};

/// Thread local key
Expand Down Expand Up @@ -505,3 +506,13 @@ where
#[inline]
fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
}

unsafe impl ValueType for SignalAndAction {
#[inline]
fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
}

unsafe impl<M: MemorySize> ValueType for ProcSpawnFdOp<M> {
#[inline]
fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
}
6 changes: 3 additions & 3 deletions lib/wasix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ sys-default = [
"sys-thread",
"host-vnet",
"host-threads",
"host-reqwest",
"wasmer/sys",
"ctrlc"
"host-reqwest",
"wasmer/sys",
"ctrlc",
]
sys-poll = []
extra-logging = []
Expand Down
2 changes: 1 addition & 1 deletion lib/wasix/src/journal/effector/syscalls/chdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ impl JournalEffector {
}

pub fn apply_chdir(ctx: &mut FunctionEnvMut<'_, WasiEnv>, path: &str) -> anyhow::Result<()> {
crate::syscalls::chdir_internal(ctx, path).map_err(|err| {
crate::syscalls::chdir_internal(ctx.data(), path).map_err(|err| {
anyhow::format_err!(
"snapshot restore error: failed to change directory (path={}) - {}",
path,
Expand Down
2 changes: 1 addition & 1 deletion lib/wasix/src/journal/effector/syscalls/path_open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl JournalEffector {
fd_flags: Fdflagsext,
) -> anyhow::Result<()> {
let res = crate::syscalls::path_open_internal(
ctx,
ctx.data(),
dirfd,
dirflags,
path,
Expand Down
6 changes: 6 additions & 0 deletions lib/wasix/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,13 +549,16 @@ fn wasix_exports_32(mut store: &mut impl AsStoreMut, env: &FunctionEnv<WasiEnv>)
"proc_fork" => Function::new_typed_with_env(&mut store, env, proc_fork::<Memory32>),
"proc_join" => Function::new_typed_with_env(&mut store, env, proc_join::<Memory32>),
"proc_signal" => Function::new_typed_with_env(&mut store, env, proc_signal::<Memory32>),
"proc_signals_count_get" => Function::new_typed_with_env(&mut store, env, proc_signals_count_get::<Memory32>),
"proc_signals_get" => Function::new_typed_with_env(&mut store, env, proc_signals_get::<Memory32>),
"proc_exec" => Function::new_typed_with_env(&mut store, env, proc_exec::<Memory32>),
"proc_exec2" => Function::new_typed_with_env(&mut store, env, proc_exec2::<Memory32>),
"proc_exec3" => Function::new_typed_with_env(&mut store, env, proc_exec3::<Memory32>),
"proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise),
"proc_raise_interval" => Function::new_typed_with_env(&mut store, env, proc_raise_interval),
"proc_snapshot" => Function::new_typed_with_env(&mut store, env, proc_snapshot::<Memory32>),
"proc_spawn" => Function::new_typed_with_env(&mut store, env, proc_spawn::<Memory32>),
"proc_spawn2" => Function::new_typed_with_env(&mut store, env, proc_spawn2::<Memory32>),
"proc_id" => Function::new_typed_with_env(&mut store, env, proc_id::<Memory32>),
"proc_parent" => Function::new_typed_with_env(&mut store, env, proc_parent::<Memory32>),
"random_get" => Function::new_typed_with_env(&mut store, env, random_get::<Memory32>),
Expand Down Expand Up @@ -678,13 +681,16 @@ fn wasix_exports_64(mut store: &mut impl AsStoreMut, env: &FunctionEnv<WasiEnv>)
"proc_fork" => Function::new_typed_with_env(&mut store, env, proc_fork::<Memory64>),
"proc_join" => Function::new_typed_with_env(&mut store, env, proc_join::<Memory64>),
"proc_signal" => Function::new_typed_with_env(&mut store, env, proc_signal::<Memory64>),
"proc_signals_count_get" => Function::new_typed_with_env(&mut store, env, proc_signals_count_get::<Memory64>),
"proc_signals_get" => Function::new_typed_with_env(&mut store, env, proc_signals_get::<Memory64>),
"proc_exec" => Function::new_typed_with_env(&mut store, env, proc_exec::<Memory64>),
"proc_exec2" => Function::new_typed_with_env(&mut store, env, proc_exec2::<Memory64>),
"proc_exec3" => Function::new_typed_with_env(&mut store, env, proc_exec3::<Memory64>),
"proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise),
"proc_raise_interval" => Function::new_typed_with_env(&mut store, env, proc_raise_interval),
"proc_snapshot" => Function::new_typed_with_env(&mut store, env, proc_snapshot::<Memory64>),
"proc_spawn" => Function::new_typed_with_env(&mut store, env, proc_spawn::<Memory64>),
"proc_spawn2" => Function::new_typed_with_env(&mut store, env, proc_spawn2::<Memory64>),
"proc_id" => Function::new_typed_with_env(&mut store, env, proc_id::<Memory64>),
"proc_parent" => Function::new_typed_with_env(&mut store, env, proc_parent::<Memory64>),
"random_get" => Function::new_typed_with_env(&mut store, env, random_get::<Memory64>),
Expand Down
62 changes: 54 additions & 8 deletions lib/wasix/src/state/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
Runtime, WasiEnv, WasiError, WasiFunctionEnv, WasiRuntimeError,
};
use wasmer_types::ModuleHash;
use wasmer_wasix_types::wasi::SignalAndAction;

use super::env::WasiEnvInit;

Expand Down Expand Up @@ -55,6 +56,8 @@ pub struct WasiEnvBuilder {
pub(super) args: Vec<String>,
/// Environment variables.
pub(super) envs: Vec<(String, Vec<u8>)>,
/// Signals that should get their handler overridden.
pub(super) signals: Vec<SignalAndAction>,
/// Pre-opened directories that will be accessible from WASI.
pub(super) preopens: Vec<PreopenedDir>,
/// Pre-opened virtual directories that will be accessible from WASI.
Expand Down Expand Up @@ -102,6 +105,7 @@ impl std::fmt::Debug for WasiEnvBuilder {
.field("entry_function", &self.entry_function)
.field("args", &self.args)
.field("envs", &self.envs)
.field("signals", &self.signals)
.field("preopens", &self.preopens)
.field("uses", &self.uses)
.field("setup_fs_fn exists", &self.setup_fs_fn.is_some())
Expand Down Expand Up @@ -163,6 +167,14 @@ impl WasiEnvBuilder {
}
}

/// Attaches a ctrl-c handler which will send signals to the
/// process rather than immediately termiante it
#[cfg(feature = "ctrlc")]
pub fn attach_ctrl_c(mut self) -> Self {
self.attach_ctrl_c = true;
self
}

/// Add an environment variable pair.
///
/// Both the key and value of an environment variable must not
Expand All @@ -177,14 +189,6 @@ impl WasiEnvBuilder {
self
}

/// Attaches a ctrl-c handler which will send signals to the
/// process rather than immediately termiante it
#[cfg(feature = "ctrlc")]
pub fn attach_ctrl_c(mut self) -> Self {
self.attach_ctrl_c = true;
self
}

/// Add an environment variable pair.
///
/// Both the key and value of an environment variable must not
Expand Down Expand Up @@ -243,6 +247,47 @@ impl WasiEnvBuilder {
&mut self.envs
}

/// Add a signal handler override.
pub fn signal(mut self, sig_action: SignalAndAction) -> Self {
self.add_signal(sig_action);
self
}

/// Add a signal handler override.
pub fn add_signal(&mut self, sig_action: SignalAndAction) {
self.signals.push(sig_action);
}

/// Add multiple signal handler overrides.
pub fn signals<I>(mut self, signal_pairs: I) -> Self
where
I: IntoIterator<Item = SignalAndAction>,
{
self.add_signals(signal_pairs);

self
}

/// Add multiple signal handler overrides.
pub fn add_signals<I>(&mut self, signal_pairs: I)
where
I: IntoIterator<Item = SignalAndAction>,
{
for sig in signal_pairs {
self.add_signal(sig);
}
}

/// Get a reference to the configured signal handler overrides.
pub fn get_signal(&self) -> &[SignalAndAction] {
&self.signals
}

/// Get a mutable reference to the configured signalironment variables.
pub fn get_signal_mut(&mut self) -> &mut Vec<SignalAndAction> {
&mut self.signals
}

pub fn entry_function<S>(mut self, entry_function: S) -> Self
where
S: AsRef<str>,
Expand Down Expand Up @@ -891,6 +936,7 @@ impl WasiEnvBuilder {
futexs: Default::default(),
clock_offset: Default::default(),
envs: std::sync::Mutex::new(conv_env_vars(self.envs)),
signals: std::sync::Mutex::new(self.signals.iter().map(|s| (s.sig, s.act)).collect()),
};

let runtime = self.runtime.unwrap_or_else(|| {
Expand Down
1 change: 1 addition & 0 deletions lib/wasix/src/state/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ impl WasiEnvInit {
),
args: std::sync::Mutex::new(self.state.args.lock().unwrap().clone()),
envs: std::sync::Mutex::new(self.state.envs.lock().unwrap().deref().clone()),
signals: std::sync::Mutex::new(self.state.signals.lock().unwrap().deref().clone()),
preopen: self.state.preopen.clone(),
},
runtime: self.runtime.clone(),
Expand Down
4 changes: 3 additions & 1 deletion lib/wasix/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use run::*;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use virtual_fs::{FileOpener, FileSystem, FsError, OpenOptions, VirtualFile};
use wasmer_wasix_types::wasi::{Errno, Fd as WasiFd, Rights, Snapshot0Clockid};
use wasmer_wasix_types::wasi::{Errno, Fd as WasiFd, Rights, SigAction, Signal, Snapshot0Clockid};

pub use self::{
builder::*,
Expand Down Expand Up @@ -135,6 +135,7 @@ pub(crate) struct WasiState {
pub clock_offset: Mutex<HashMap<Snapshot0Clockid, i64>>,
pub args: Mutex<Vec<String>>,
pub envs: Mutex<Vec<Vec<u8>>>,
pub signals: Mutex<HashMap<Signal, SigAction>>,

// TODO: should not be here, since this requires active work to resolve.
// State should only hold active runtime state that can be reproducibly re-created.
Expand Down Expand Up @@ -257,6 +258,7 @@ impl WasiState {
clock_offset: Mutex::new(self.clock_offset.lock().unwrap().clone()),
args: Mutex::new(self.args.lock().unwrap().clone()),
envs: Mutex::new(self.envs.lock().unwrap().clone()),
signals: Mutex::new(self.signals.lock().unwrap().clone()),
preopen: self.preopen.clone(),
}
}
Expand Down
17 changes: 12 additions & 5 deletions lib/wasix/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ pub(crate) use self::types::{
wasi::{
Addressfamily, Advice, Clockid, Dircookie, Dirent, Errno, Event, EventFdReadwrite,
Eventrwflags, Eventtype, ExitCode, Fd as WasiFd, Fdflags, Fdflagsext, Fdstat, Filesize,
Filestat, Filetype, Fstflags, Linkcount, Longsize, OptionFd, Pid, Prestat, Rights,
Snapshot0Clockid, Sockoption, Sockstatus, Socktype, StackSnapshot,
Filestat, Filetype, Fstflags, Linkcount, Longsize, OptionFd, Pid, Prestat, ProcSpawnFdOp,
Rights, SignalAndAction, Snapshot0Clockid, Sockoption, Sockstatus, Socktype, StackSnapshot,
StdioMode as WasiStdioMode, Streamsecurity, Subscription, SubscriptionFsReadwrite, Tid,
Timestamp, TlKey, TlUser, TlVal, Tty, Whence,
},
Expand Down Expand Up @@ -1460,12 +1460,11 @@ pub(crate) fn _prepare_wasi(
wasi_env: &mut WasiEnv,
args: Option<Vec<String>>,
envs: Option<Vec<(String, String)>>,
signals: Option<Vec<SignalAndAction>>,
) {
// Swap out the arguments with the new ones
if let Some(args) = args {
let mut wasi_state = wasi_env.state.fork();
*wasi_state.args.lock().unwrap() = args;
wasi_env.state = Arc::new(wasi_state);
*wasi_env.state.args.lock().unwrap() = args;
}

// Update the env vars
Expand Down Expand Up @@ -1499,6 +1498,14 @@ pub(crate) fn _prepare_wasi(

drop(guard)
}

if let Some(signals) = signals {
let mut guard = wasi_env.state.signals.lock().unwrap();
for signal in signals {
guard.insert(signal.sig, signal.act);
}
drop(guard);
}
}

pub(crate) fn conv_spawn_err_to_errno(err: &SpawnError) -> Errno {
Expand Down
2 changes: 1 addition & 1 deletion lib/wasix/src/syscalls/wasi/path_open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub fn path_open<M: MemorySize>(
Span::current().record("path", path_string.as_str());

let out_fd = wasi_try_ok!(path_open_internal(
&mut ctx,
ctx.data(),
dirfd,
dirflags,
&path_string,
Expand Down
7 changes: 3 additions & 4 deletions lib/wasix/src/syscalls/wasix/chdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn chdir<M: MemorySize>(
let path = unsafe { get_input_str_ok!(&memory, path, path_len) };
Span::current().record("path", path.as_str());

wasi_try_ok!(chdir_internal(&mut ctx, &path));
wasi_try_ok!(chdir_internal(ctx.data(), &path));
let env = ctx.data();

#[cfg(feature = "journal")]
Expand All @@ -28,9 +28,8 @@ pub fn chdir<M: MemorySize>(
Ok(Errno::Success)
}

pub fn chdir_internal(ctx: &mut FunctionEnvMut<'_, WasiEnv>, path: &str) -> Result<(), Errno> {
let env = ctx.data();
let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(ctx, 0) };
pub fn chdir_internal(env: &WasiEnv, path: &str) -> Result<(), Errno> {
let state = &env.state;

// Check if the directory exists
if state.fs.root_fs.read_dir(Path::new(path)).is_err() {
Expand Down
Loading

0 comments on commit acf244f

Please sign in to comment.