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
43 changes: 42 additions & 1 deletion lib/wasix/src/os/command/builtins/cmd_wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
runtime::module_cache::HashedModuleData,
};
use shared_buffer::OwnedBuffer;
use virtual_fs::{AsyncReadExt, FileSystem};
use virtual_fs::{AsyncReadExt, AsyncWriteExt, FileSystem};
use virtual_mio::block_on;
use wasmer::FunctionEnvMut;
use wasmer_package::utils::from_bytes;
Expand All @@ -24,6 +24,7 @@ const HELP: &str = r#"USAGE:

OPTIONS:
-h, --help Print help information
-V, --version Print version information

SUBCOMMANDS:
run Run a WebAssembly file. Formats accepted: wasm, wat
Expand All @@ -50,6 +51,37 @@ impl CmdWasmer {
pub fn new(runtime: Arc<dyn Runtime + Send + Sync + 'static>) -> Self {
Self { runtime }
}

#[allow(clippy::await_holding_lock)]
async fn write_stdout(env: &WasiEnv, buf: &[u8]) -> Result<(), Errno> {
let fd = env.state.fs.get_fd(1)?;
let handle = {
let mut guard = fd.inode.write();
match &mut *guard {
crate::fs::Kind::File {
handle: Some(handle),
..
} => handle.clone(),
crate::fs::Kind::PipeTx { tx } => {
return std::io::Write::write_all(tx, buf).map_err(crate::utils::map_io_err);
}
crate::fs::Kind::DuplexPipe { pipe } => {
return std::io::Write::write_all(pipe, buf).map_err(crate::utils::map_io_err);
}
crate::fs::Kind::Buffer { buffer } => {
buffer.extend_from_slice(buf);
return Ok(());
}
_ => return Err(Errno::Badf),
}
};

let mut file = handle.write().unwrap();
file.write_all(buf)
.await
.map_err(crate::utils::map_io_err)?;
file.flush().await.map_err(crate::utils::map_io_err)
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -211,6 +243,15 @@ impl VirtualCommand for CmdWasmer {
OwnedTaskStatus::new_finished_with_code(Errno::Success.into()).handle();
Ok(handle)
}
Some("--version" | "-V") => {
let version = format!("wasmer {}\n", wasmer_types::VERSION);
if let Some(env) = env.as_ref() {
Self::write_stdout(env, version.as_bytes()).await.ok();
}
let handle =
OwnedTaskStatus::new_finished_with_code(Errno::Success.into()).handle();
Ok(handle)
}
Some(what) => {
let what = Some(what.to_string());
let args = args.map(|a| a.to_string()).collect();
Expand Down
22 changes: 22 additions & 0 deletions lib/wasix/src/syscalls/wasix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,28 @@ pub use thread_spawn::*;
pub use tty_get::*;
pub use tty_set::*;

fn propagate_virtual_task_completion(
tasks: &Arc<dyn VirtualTaskManager>,
mut task: crate::os::task::TaskJoinHandle,
child_finished: Arc<crate::os::task::OwnedTaskStatus>,
) -> Result<(), crate::WasiThreadError> {
if let Some(result) = task.status().into_finished() {
child_finished.set_finished(result);
return Ok(());
}

let finished_on_error = child_finished.clone();
let result = tasks.task_shared(Box::new(move || {
Box::pin(async move {
child_finished.set_finished(task.wait_finished().await);
})
}));
if result.is_err() {
finished_on_error.set_finished(Ok(Errno::Child.into()));
}
result
}

use tracing::{Span, debug_span, field, instrument, trace_span};
use wasmer::WasmRef;

Expand Down
14 changes: 10 additions & 4 deletions lib/wasix/src/syscalls/wasix/proc_spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ pub fn proc_spawn_internal(
}
};
let child_process = child_env.process.clone();
let child_finished = child_process.finished.clone();
let tasks = child_env.tasks().clone();
if let Some(args) = args {
let mut child_state = env.state.fork();
child_state.args = std::sync::Mutex::new(args);
Expand Down Expand Up @@ -238,8 +240,12 @@ pub fn proc_spawn_internal(
let mut builder = Some(child_env);

// First we try the built in commands
let mut process = match bin_factory.try_built_in(name.clone(), Some(&ctx), &mut builder) {
Ok(a) => a,
match bin_factory.try_built_in(name.clone(), Some(&ctx), &mut builder) {
Ok(task) => {
if let Err(err) = propagate_virtual_task_completion(&tasks, task, child_finished) {
return Ok(Err(err.into()));
}
}
Err(err) => {
if !err.is_not_found() {
error!("builtin failed - {}", err);
Expand All @@ -250,12 +256,12 @@ pub fn proc_spawn_internal(
match __asyncify(&mut ctx, None, async move { Ok(child_work.await) })?
.map_err(|err| Errno::Unknown)
{
Ok(Ok(a)) => a,
Ok(Ok(_)) => {}
Ok(Err(err)) => return Ok(Err(conv_spawn_err_to_errno(&err))),
Err(err) => return Ok(Err(err)),
}
}
};
}

// Add the process to the environment state
{
Expand Down
11 changes: 9 additions & 2 deletions lib/wasix/src/syscalls/wasix/proc_spawn3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ pub(crate) fn proc_spawn3_impl<M: MemorySize>(
// Setup some properties in the child environment
let pid = child_env.pid();
let tid = child_env.tid();
let child_finished = child_env.process.finished.clone();
let tasks = child_env.tasks().clone();
wasi_try_mem_ok!(ret.write(&memory, pid.raw()));
Span::current()
.record("pid", pid.raw())
Expand All @@ -157,7 +159,12 @@ pub(crate) fn proc_spawn3_impl<M: MemorySize>(
let mut builder = Some(child_env);

let process = match bin_factory.try_built_in(name.clone(), Some(&ctx), &mut builder) {
Ok(a) => Ok(a),
Ok(task) => {
if let Err(err) = propagate_virtual_task_completion(&tasks, task, child_finished) {
return Ok(err.into());
}
Ok(())
}
Err(err) => {
if !err.is_not_found() {
error!("builtin failed - {}", err);
Expand All @@ -166,7 +173,7 @@ pub(crate) fn proc_spawn3_impl<M: MemorySize>(
let env = builder.take().unwrap();

// Spawn a new process with this current execution environment
block_on(bin_factory.spawn(name.clone(), env))
block_on(bin_factory.spawn(name.clone(), env)).map(|_| ())
}
};

Expand Down
93 changes: 93 additions & 0 deletions lib/wasix/tests/wasm_tests/process/builtin-wasmer-version/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//#ExpectedStdout: builtin wasmer version passed

#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

extern char** environ;

static void fail(const char* message) {
perror(message);
exit(1);
}

static size_t read_all(int fd, char* buffer, size_t capacity) {
size_t length = 0;
while (length < capacity) {
ssize_t count = read(fd, buffer + length, capacity - length);
if (count < 0) {
fail("read");
}
if (count == 0) {
break;
}
length += count;
}
return length;
}

int main(void) {
int stdout_pipe[2];
int stderr_pipe[2];
if (pipe(stdout_pipe) != 0 || pipe(stderr_pipe) != 0) {
fail("pipe");
}

posix_spawn_file_actions_t actions;
if (posix_spawn_file_actions_init(&actions) != 0 ||
posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1],
STDOUT_FILENO) != 0 ||
posix_spawn_file_actions_adddup2(&actions, stderr_pipe[1],
STDERR_FILENO) != 0 ||
posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]) != 0 ||
posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]) != 0 ||
posix_spawn_file_actions_addclose(&actions, stderr_pipe[0]) != 0 ||
posix_spawn_file_actions_addclose(&actions, stderr_pipe[1]) != 0) {
return 1;
}

pid_t pid;
char* argv[] = {"wasmer", "--version", NULL};
int spawn_error = posix_spawnp(&pid, "wasmer", &actions, NULL, argv, environ);
posix_spawn_file_actions_destroy(&actions);
if (spawn_error != 0) {
return spawn_error;
}

close(stdout_pipe[1]);
close(stderr_pipe[1]);
char stdout_output[128] = {0};
char stderr_output[128] = {0};
size_t stdout_length =
read_all(stdout_pipe[0], stdout_output, sizeof(stdout_output) - 1);
size_t stderr_length =
read_all(stderr_pipe[0], stderr_output, sizeof(stderr_output) - 1);
close(stdout_pipe[0]);
close(stderr_pipe[0]);

int status;
if (waitpid(pid, &status, 0) != pid) {
fail("waitpid");
}

if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
fprintf(stderr, "wasmer exited with status %d\n", status);
return 1;
}
Comment on lines +77 to +80

if (stdout_length == 0 ||
strncmp(stdout_output, "wasmer ", strlen("wasmer ")) != 0) {
fprintf(stderr, "unexpected wasmer stdout: %s\n", stdout_output);
return 1;
}
if (stderr_length != 0) {
fprintf(stderr, "unexpected wasmer stderr: %s\n", stderr_output);
return 1;
}

puts("builtin wasmer version passed");
return 0;
}
Loading