Skip to content
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

Update to wasmtime 22 #824

Merged
merged 1 commit into from
Jul 8, 2024
Merged
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
8 changes: 4 additions & 4 deletions crates/livesplit-auto-splitting/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ sysinfo = { version = "0.30.0", default-features = false, features = [
"multithread",
] }
time = { version = "0.3.3", default-features = false }
wasmtime = { version = "17.0.0", default-features = false, features = [
wasmtime = { version = "22.0.0", default-features = false, features = [
"cranelift",
"parallel-compilation",
"runtime",
] }
wasmtime-wasi = { version = "17.0.0", default-features = false, features = [
"sync",
wasmtime-wasi = { version = "22.0.0", default-features = false, features = [
"preview1",
] }
wasi-common = "17.0.0"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52.0", features = ["Win32_Storage_FileSystem"] }
Expand Down
5 changes: 2 additions & 3 deletions crates/livesplit-auto-splitting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ extern "C" {
list_ptr: *mut ProcessId,
list_len_ptr: *mut usize,
) -> bool;
/// Checks whether is a process is still open. You should detach from a
/// Checks whether a process is still open. You should detach from a
/// process and stop using it if this returns `false`.
pub fn process_is_open(process: Process) -> bool;
/// Reads memory from a process at the address given. This will write
Expand Down Expand Up @@ -534,8 +534,7 @@ support:
nothing.
- The file system is currently almost entirely empty. The host's file system is
accessible through `/mnt`. It is entirely read-only. Windows paths are mapped
to `/mnt/c`, `/mnt/d`, etc. to match WSL. Additionally `/mnt/device` maps to
`\\?\` on Windows to access additional paths.
to `/mnt/c`, `/mnt/d`, etc. to match WSL.
- There are no environment variables.
- There are no command line arguments.
- There is no networking.
Expand Down
5 changes: 2 additions & 3 deletions crates/livesplit-auto-splitting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
//! list_ptr: *mut ProcessId,
//! list_len_ptr: *mut usize,
//! ) -> bool;
//! /// Checks whether is a process is still open. You should detach from a
//! /// Checks whether a process is still open. You should detach from a
//! /// process and stop using it if this returns `false`.
//! pub fn process_is_open(process: Process) -> bool;
//! /// Reads memory from a process at the address given. This will write
Expand Down Expand Up @@ -534,8 +534,7 @@
//! nothing.
//! - The file system is currently almost entirely empty. The host's file system
//! is accessible through `/mnt`. It is entirely read-only. Windows paths are
//! mapped to `/mnt/c`, `/mnt/d`, etc. to match WSL. Additionally
//! `/mnt/device` maps to `\\?\` on Windows to access additional paths.
//! mapped to `/mnt/c`, `/mnt/d`, etc. to match WSL.
//! - There are no environment variables.
//! - There are no command line arguments.
//! - There is no networking.
Expand Down
185 changes: 19 additions & 166 deletions crates/livesplit-auto-splitting/src/runtime/api/wasi.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
use std::{
path::{Path, PathBuf},
str,
};
use std::{path::Path, str};

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / Check clippy lints

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux x86_64)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux x86_64 musl)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux aarch64)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux aarch64 musl)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux riscv64gc)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux s390x)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (macOS aarch64)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (macOS x86_64)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux Beta)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (Linux Nightly)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (macOS Beta)

unused import: `str`

Check warning on line 1 in crates/livesplit-auto-splitting/src/runtime/api/wasi.rs

View workflow job for this annotation

GitHub Actions / build (macOS Nightly)

unused import: `str`

use wasi_common::{
dir::{OpenResult, ReaddirCursor, ReaddirEntity},
file::{FdFlags, Filestat, OFlags},
ErrorExt, WasiCtx, WasiDir,
};
use wasmtime_wasi::{ambient_authority, WasiCtxBuilder};
use wasmtime_wasi::{preview1::WasiP1Ctx, DirPerms, FilePerms, WasiCtxBuilder};

use crate::wasi_path;

pub fn build(script_path: Option<&Path>) -> WasiCtx {
let mut wasi = WasiCtxBuilder::new().build();
pub fn build(script_path: Option<&Path>) -> WasiP1Ctx {
let mut wasi = WasiCtxBuilder::new();

if let Some(script_path) = script_path {
if let Some(path) = wasi_path::from_native(script_path) {
let _ = wasi.push_env("SCRIPT_PATH", &path);
wasi.env("SCRIPT_PATH", &path);
}
}

Expand All @@ -32,164 +24,25 @@
}
drives &= !(1 << drive_idx);
let drive = drive_idx as u8 + b'a';
if let Ok(path) = wasmtime_wasi::Dir::open_ambient_dir(
// Unfortunate if this fails, but we should still continue.
let _ = wasi.preopened_dir(
str::from_utf8(&[b'\\', b'\\', b'?', b'\\', drive, b':', b'\\']).unwrap(),
ambient_authority(),
) {
wasi.push_dir(
Box::new(ReadOnlyDir(wasmtime_wasi::dir::Dir::from_cap_std(path))),
PathBuf::from(str::from_utf8(&[b'/', b'm', b'n', b't', b'/', drive]).unwrap()),
)
.unwrap();
}
str::from_utf8(&[b'/', b'm', b'n', b't', b'/', drive]).unwrap(),
DirPerms::READ,
FilePerms::READ,
);
}

wasi.push_dir(Box::new(DeviceDir), PathBuf::from("/mnt/device"))
.unwrap();
// FIXME: Unfortunately wasmtime doesn't support us defining our own
// file system logic anymore.

// wasi.push_dir(Box::new(DeviceDir), PathBuf::from("/mnt/device"))
// .unwrap();
}
#[cfg(not(windows))]
{
if let Ok(path) = wasmtime_wasi::Dir::open_ambient_dir("/", ambient_authority()) {
wasi.push_dir(
Box::new(ReadOnlyDir(wasmtime_wasi::dir::Dir::from_cap_std(path))),
PathBuf::from("/mnt"),
)
.unwrap();
}
}
wasi
}

struct ReadOnlyDir(wasmtime_wasi::dir::Dir);

#[async_trait::async_trait]
impl WasiDir for ReadOnlyDir {
fn as_any(&self) -> &dyn std::any::Any {
self
}

async fn open_file(
&self,
symlink_follow: bool,
path: &str,
oflags: OFlags,
read: bool,
write: bool,
fdflags: FdFlags,
) -> Result<OpenResult, wasi_common::Error> {
// We whitelist the OFlags and FdFlags to not accidentally allow
// ways to modify the file system.
const WHITELISTED_O_FLAGS: OFlags = OFlags::DIRECTORY;
const WHITELISTED_FD_FLAGS: FdFlags = FdFlags::NONBLOCK;

if write || !WHITELISTED_O_FLAGS.contains(oflags) || !WHITELISTED_FD_FLAGS.contains(fdflags)
{
return Err(wasi_common::Error::not_supported());
}

Ok(
match self
.0
.open_file_(symlink_follow, path, oflags, read, write, fdflags)?
{
wasmtime_wasi::dir::OpenResult::Dir(d) => OpenResult::Dir(Box::new(ReadOnlyDir(d))),
// We assume that wrapping the file type itself is not
// necessary, because we ensure that the open flags don't allow
// for any modifications anyway.
wasmtime_wasi::dir::OpenResult::File(f) => OpenResult::File(Box::new(f)),
},
)
}

async fn readdir(
&self,
cursor: ReaddirCursor,
) -> Result<
Box<dyn Iterator<Item = Result<ReaddirEntity, wasi_common::Error>> + Send>,
wasi_common::Error,
> {
self.0.readdir(cursor).await
}

async fn read_link(&self, path: &str) -> Result<PathBuf, wasi_common::Error> {
self.0.read_link(path).await
}

async fn get_filestat(&self) -> Result<Filestat, wasi_common::Error> {
// FIXME: Make sure this says it's readonly, if it ever contains the
// permissions.
self.0.get_filestat().await
// Unfortunate if this fails, but we should still continue.
let _ = wasi.preopened_dir("/", "/mnt", DirPerms::READ, FilePerms::READ);
}

async fn get_path_filestat(
&self,
path: &str,
follow_symlinks: bool,
) -> Result<Filestat, wasi_common::Error> {
// FIXME: Make sure this says it's readonly, if it ever contains the
// permissions.
self.0.get_path_filestat(path, follow_symlinks).await
}
}

#[cfg(windows)]
struct DeviceDir;

#[cfg(windows)]
#[async_trait::async_trait]
impl WasiDir for DeviceDir {
fn as_any(&self) -> &dyn std::any::Any {
self
}

async fn open_file(
&self,
symlink_follow: bool,
path: &str,
oflags: OFlags,
read: bool,
write: bool,
fdflags: FdFlags,
) -> Result<OpenResult, wasi_common::Error> {
let (dir, file) = device_path(path)?;
dir.open_file(symlink_follow, file, oflags, read, write, fdflags)
.await
}

// FIXME: cap-primitives/src/windows/fs/get_path tries to strip `\\?\`,
// which breaks paths that aren't valid without it, such as UNC paths:
// https://github.com/bytecodealliance/cap-std/issues/348

async fn read_link(&self, path: &str) -> Result<PathBuf, wasi_common::Error> {
let (dir, file) = device_path(path)?;
dir.read_link(file).await
}

async fn get_path_filestat(
&self,
path: &str,
follow_symlinks: bool,
) -> Result<Filestat, wasi_common::Error> {
let (dir, file) = device_path(path)?;
dir.get_path_filestat(file, follow_symlinks).await
}
}

#[cfg(windows)]
fn device_path(path: &str) -> Result<(ReadOnlyDir, &str), wasi_common::Error> {
let (parent, file) = path
.strip_suffix('/')
.unwrap_or(path)
.rsplit_once('/')
.ok_or_else(wasi_common::Error::not_supported)?;

let parent = wasi_path::to_native(&format!("/mnt/device/{parent}"), true)
.ok_or_else(wasi_common::Error::not_supported)?;

let dir = wasmtime_wasi::dir::Dir::from_cap_std(
wasmtime_wasi::Dir::open_ambient_dir(parent, ambient_authority())
.map_err(|_| wasi_common::Error::not_supported())?,
);

Ok((ReadOnlyDir(dir), file))
wasi.build_p1()
}
11 changes: 4 additions & 7 deletions crates/livesplit-auto-splitting/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use wasmtime::{
Engine, Extern, Linker, Memory, Module, OptLevel, Store, TypedFunc, WasmBacktraceDetails,
};
use wasmtime_wasi::WasiCtx;
use wasmtime_wasi::preview1::WasiP1Ctx;

mod api;

Expand Down Expand Up @@ -89,7 +89,7 @@
timer: T,
memory: Option<Memory>,
process_list: ProcessList,
wasi: WasiCtx,
wasi: WasiP1Ctx,
}

/// A thread-safe handle used to interrupt the execution of the script.
Expand Down Expand Up @@ -354,7 +354,7 @@

impl CompiledAutoSplitter {
/// Instantiates the auto splitter with the given timer.
pub fn instantiate<T: Timer>(

Check warning on line 357 in crates/livesplit-auto-splitting/src/runtime/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows Nightly gnu)

this function depends on never type fallback being `()`

Check warning on line 357 in crates/livesplit-auto-splitting/src/runtime/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux Nightly)

this function depends on never type fallback being `()`

Check warning on line 357 in crates/livesplit-auto-splitting/src/runtime/mod.rs

View workflow job for this annotation

GitHub Actions / build (macOS Nightly)

this function depends on never type fallback being `()`
&self,
timer: T,
settings_map: Option<settings::Map>,
Expand Down Expand Up @@ -396,11 +396,8 @@
.any(|import| import.module() == "wasi_snapshot_preview1");

if uses_wasi {
wasmtime_wasi::snapshots::preview_1::add_wasi_snapshot_preview1_to_linker(
&mut linker,
|ctx| &mut ctx.wasi,
)
.map_err(|source| CreationError::Wasi { source })?;
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |ctx| &mut ctx.wasi)
.map_err(|source| CreationError::Wasi { source })?;
}

let instance = linker
Expand Down
2 changes: 1 addition & 1 deletion crates/livesplit-auto-splitting/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub enum TimerState {
}

/// A timer that can be controlled by an auto splitter.
pub trait Timer {
pub trait Timer: Send {
/// Returns the current state of the timer.
fn state(&self) -> TimerState;
/// Starts the timer.
Expand Down
7 changes: 3 additions & 4 deletions src/auto_splitting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,7 @@
//! nothing.
//! - The file system is currently almost entirely empty. The host's file system
//! is accessible through `/mnt`. It is entirely read-only. Windows paths are
//! mapped to `/mnt/c`, `/mnt/d`, etc. to match WSL. Additionally
//! `/mnt/device` maps to `\\?\` on Windows to access additional paths.
//! mapped to `/mnt/c`, `/mnt/d`, etc. to match WSL.
//! - There are no environment variables.
//! - There are no command line arguments.
//! - There is no networking.
Expand Down Expand Up @@ -719,7 +718,7 @@ impl<T: event::CommandSink + TimerQuery + Send + 'static> Runtime<T> {
// is an Arc<RwLock<T>>, so we can't implement the trait directly on it.
struct Timer<E>(E);

impl<E: event::CommandSink + TimerQuery> AutoSplitTimer for Timer<E> {
impl<E: event::CommandSink + TimerQuery + Send> AutoSplitTimer for Timer<E> {
fn state(&self) -> TimerState {
match self.0.get_timer().current_phase() {
TimerPhase::NotRunning => TimerState::NotRunning,
Expand Down Expand Up @@ -770,7 +769,7 @@ impl<E: event::CommandSink + TimerQuery> AutoSplitTimer for Timer<E> {
}
}

async fn run<T: event::CommandSink + TimerQuery>(
async fn run<T: event::CommandSink + TimerQuery + Send>(
mut auto_splitter: watch::Receiver<Option<AutoSplitter<Timer<T>>>>,
timeout_sender: watch::Sender<Option<Instant>>,
interrupt_sender: watch::Sender<Option<InterruptHandle>>,
Expand Down
Loading