Skip to content
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
22 changes: 21 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,12 @@ jobs:
-p wasmtime --no-default-features --features profiling
-p wasmtime --no-default-features --features cache
-p wasmtime --no-default-features --features async
-p wasmtime --no-default-features --features std
-p wasmtime --no-default-features --features pooling-allocator
-p wasmtime --no-default-features --features cranelift
-p wasmtime --no-default-features --features component-model
-p wasmtime --no-default-features --features runtime,component-model
-p wasmtime --no-default-features --features cranelift,wat,async,cache
-p wasmtime --no-default-features --features cranelift,wat,async,std,cache
-p wasmtime --no-default-features --features winch
-p wasmtime --no-default-features --features wmemcheck
-p wasmtime --no-default-features --features wmemcheck,cranelift,runtime
Expand All @@ -384,6 +385,12 @@ jobs:
-p wasmtime --features incremental-cache
-p wasmtime --all-features

- name: wasmtime-fiber
checks: |
-p wasmtime-fiber --no-default-features
-p wasmtime-fiber --no-default-features --features std
-p wasmtime-fiber --all-features

- name: wasmtime-cli
checks: |
-p wasmtime-cli --no-default-features
Expand Down Expand Up @@ -432,6 +439,18 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}

fiber_tests:
name: wasmtime-fiber tests
runs-on: ubuntu-latest
env:
CARGO_NDK_VERSION: 2.12.2
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: cargo test -p wasmtime-fiber --no-default-features

# Checks for no_std support, ensure that crates can build on a no_std target
no_std_checks:
name: no_std checks
Expand Down Expand Up @@ -1189,6 +1208,7 @@ jobs:
- cargo_vet
- doc
- micro_checks
- fiber_tests
- no_std_checks
- clippy
- monolith_checks
Expand Down
6 changes: 3 additions & 3 deletions crates/asm-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ cfg_if::cfg_if! {
#[macro_export]
macro_rules! asm_func {
($name:expr, $body:expr $(, $($args:tt)*)?) => {
std::arch::global_asm!(
core::arch::global_asm!(
concat!(
".p2align 4\n",
".private_extern _", $name, "\n",
Expand All @@ -29,7 +29,7 @@ cfg_if::cfg_if! {
#[macro_export]
macro_rules! asm_func {
($name:expr, $body:expr $(, $($args:tt)*)?) => {
std::arch::global_asm!(
core::arch::global_asm!(
concat!(
".def ", $name, "\n",
".scl 2\n",
Expand Down Expand Up @@ -65,7 +65,7 @@ cfg_if::cfg_if! {
#[macro_export]
macro_rules! asm_func {
($name:expr, $body:expr $(, $($args:tt)*)?) => {
std::arch::global_asm!(
core::arch::global_asm!(
concat!(
".p2align 4\n",
".hidden ", $name, "\n",
Expand Down
8 changes: 7 additions & 1 deletion crates/fiber/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ workspace = true
anyhow = { workspace = true }
cfg-if = { workspace = true }
wasmtime-versioned-export-macros = { workspace = true }
wasmtime-asm-macros = { workspace = true }

[target.'cfg(unix)'.dependencies]
rustix = { workspace = true, features = ["mm", "param"] }
wasmtime-asm-macros = { workspace = true }

[target.'cfg(windows)'.dependencies.windows-sys]
workspace = true
Expand All @@ -33,3 +33,9 @@ wasmtime-versioned-export-macros = { workspace = true }

[dev-dependencies]
backtrace = "0.3.68"

[features]

# Assume presence of the standard library. Allows propagating
# panic-unwinds across fiber invocations.
std = []
4 changes: 2 additions & 2 deletions crates/fiber/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ fn main() {
build.file("src/windows.c");
build.define("VERSIONED_SUFFIX", Some(versioned_suffix!()));
} else if arch == "s390x" {
println!("cargo:rerun-if-changed=src/unix/s390x.S");
build.file("src/unix/s390x.S");
println!("cargo:rerun-if-changed=src/stackswitch/s390x.S");
build.file("src/stackswitch/s390x.S");
build.define("VERSIONED_SUFFIX", Some(versioned_suffix!()));
} else {
// assume that this is included via inline assembly in the crate itself,
Expand Down
82 changes: 58 additions & 24 deletions crates/fiber/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#![expect(clippy::allow_attributes, reason = "crate not migrated yet")]
#![no_std]

#[cfg(any(feature = "std", unix, windows))]
#[macro_use]
extern crate std;
extern crate alloc;

use alloc::boxed::Box;
use anyhow::Error;
use std::any::Any;
use std::cell::Cell;
use std::io;
use std::marker::PhantomData;
use std::ops::Range;
use std::panic::{self, AssertUnwindSafe};
use core::cell::Cell;
use core::marker::PhantomData;
use core::ops::Range;

cfg_if::cfg_if! {
if #[cfg(windows)] {
if #[cfg(not(feature = "std"))] {
mod nostd;
use nostd as imp;
} else if #[cfg(windows)] {
mod windows;
use windows as imp;
} else if #[cfg(unix)] {
Expand All @@ -20,6 +27,11 @@ cfg_if::cfg_if! {
}
}

// Our own stack switcher routines are used on Unix and no_std
// platforms, but not on Windows (it has its own fiber API).
#[cfg(any(unix, not(feature = "std")))]
pub(crate) mod stackswitch;

/// Represents an execution stack to use for a fiber.
pub struct FiberStack(imp::FiberStack);

Expand All @@ -31,14 +43,16 @@ fn _assert_send_sync() {
_assert_sync::<FiberStack>();
}

pub type Result<T, E = imp::Error> = core::result::Result<T, E>;

impl FiberStack {
/// Creates a new fiber stack of the given size.
pub fn new(size: usize) -> io::Result<Self> {
pub fn new(size: usize) -> Result<Self> {
Ok(Self(imp::FiberStack::new(size)?))
}

/// Creates a new fiber stack of the given size.
pub fn from_custom(custom: Box<dyn RuntimeFiberStack>) -> io::Result<Self> {
pub fn from_custom(custom: Box<dyn RuntimeFiberStack>) -> Result<Self> {
Ok(Self(imp::FiberStack::from_custom(custom)?))
}

Expand All @@ -55,11 +69,7 @@ impl FiberStack {
///
/// The caller must properly allocate the stack space with a guard page and
/// make the pages accessible for correct behavior.
pub unsafe fn from_raw_parts(
bottom: *mut u8,
guard_size: usize,
len: usize,
) -> io::Result<Self> {
pub unsafe fn from_raw_parts(bottom: *mut u8, guard_size: usize, len: usize) -> Result<Self> {
Ok(Self(imp::FiberStack::from_raw_parts(
bottom, guard_size, len,
)?))
Expand Down Expand Up @@ -128,7 +138,8 @@ enum RunResult<Resume, Yield, Return> {
Resuming(Resume),
Yield(Yield),
Returned(Return),
Panicked(Box<dyn Any + Send>),
#[cfg(feature = "std")]
Panicked(Box<dyn core::any::Any + Send>),
}

impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> {
Expand All @@ -140,7 +151,7 @@ impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> {
pub fn new(
stack: FiberStack,
func: impl FnOnce(Resume, &mut Suspend<Resume, Yield, Return>) -> Return + 'a,
) -> io::Result<Self> {
) -> Result<Self> {
let inner = imp::Fiber::new(&stack.0, func)?;

Ok(Self {
Expand Down Expand Up @@ -177,7 +188,11 @@ impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> {
Err(y)
}
RunResult::Returned(r) => Ok(r),
RunResult::Panicked(payload) => std::panic::resume_unwind(payload),
#[cfg(feature = "std")]
RunResult::Panicked(_payload) => {
use std::panic;
panic::resume_unwind(_payload);
}
}
}

Expand Down Expand Up @@ -222,11 +237,27 @@ impl<Resume, Yield, Return> Suspend<Resume, Yield, Return> {
inner,
_phantom: PhantomData,
};
let result = panic::catch_unwind(AssertUnwindSafe(|| (func)(initial, &mut suspend)));
suspend.inner.switch::<Resume, Yield, Return>(match result {
Ok(result) => RunResult::Returned(result),
Err(panic) => RunResult::Panicked(panic),
});

#[cfg(feature = "std")]
{
use std::panic::{self, AssertUnwindSafe};
let result = panic::catch_unwind(AssertUnwindSafe(|| (func)(initial, &mut suspend)));
suspend.inner.switch::<Resume, Yield, Return>(match result {
Ok(result) => RunResult::Returned(result),
Err(panic) => RunResult::Panicked(panic),
});
}
// Note that it is sound to omit the `catch_unwind` here: it
// will not result in unwinding going off the top of the fiber
// stack, because the code on the fiber stack is invoked via
// an extern "C" boundary which will panic on unwinds.
#[cfg(not(feature = "std"))]
{
let result = (func)(initial, &mut suspend);
suspend
.inner
.switch::<Resume, Yield, Return>(RunResult::Returned(result));
}
}
}

Expand All @@ -236,11 +267,11 @@ impl<A, B, C> Drop for Fiber<'_, A, B, C> {
}
}

#[cfg(test)]
#[cfg(all(test))]
mod tests {
use super::{Fiber, FiberStack};
use alloc::string::ToString;
use std::cell::Cell;
use std::panic::{self, AssertUnwindSafe};
use std::rc::Rc;

#[test]
Expand Down Expand Up @@ -332,7 +363,10 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn panics_propagated() {
use std::panic::{self, AssertUnwindSafe};

let a = Rc::new(Cell::new(false));
let b = SetOnDrop(a.clone());
let fiber =
Expand Down
Loading