Skip to content

Commit

Permalink
feat(wasi): add support for wasi:[email protected]
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Volosatovs <[email protected]>
  • Loading branch information
rvolosatovs committed Jan 21, 2025
1 parent 38c0f34 commit 171a532
Show file tree
Hide file tree
Showing 28 changed files with 535 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ci/vendor-wit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ make_vendor "wasi" "
[email protected]
[email protected]
random@[email protected]
clocks@[email protected]
"

make_vendor "wasi-http" "
Expand All @@ -55,6 +56,7 @@ make_vendor "wasi-http" "
[email protected]
[email protected]
random@[email protected]
clocks@[email protected]
"

make_vendor "wasi-config" "config@f4d699b"
Expand Down
2 changes: 2 additions & 0 deletions crates/test-programs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ anyhow = { workspace = true, features = ['std'] }
wasi = "0.11.0"
wasi-nn = "0.6.0"
wit-bindgen = { workspace = true, features = ['default'] }
wit-bindgen-rt = "0.37"
libc = { workspace = true }
getrandom = "0.2.9"
futures = { workspace = true, default-features = false, features = ['alloc'] }
url = { workspace = true }
sha2 = "0.10.2"
base64 = "0.21.0"
tokio = { workspace = true, features = ["macros"] }
2 changes: 1 addition & 1 deletion crates/test-programs/src/bin/preview2_sleep.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use test_programs::wasi::clocks::monotonic_clock;
use test_programs::wasi::clocks0_2_3::monotonic_clock;

fn main() {
sleep_10ms();
Expand Down
62 changes: 62 additions & 0 deletions crates/test-programs/src/bin/preview3_sleep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use core::future::Future as _;
use core::pin::pin;
use core::ptr;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

use test_programs::wasi::clocks0_3_0::monotonic_clock;

// Adapted from https://github.com/rust-lang/rust/blob/cd805f09ffbfa3896c8f50a619de9b67e1d9f3c3/library/core/src/task/wake.rs#L63-L77
// TODO: Replace by `Waker::noop` once MSRV is raised to 1.85
const NOOP_RAW_WAKER: RawWaker = {
const VTABLE: RawWakerVTable = RawWakerVTable::new(
// Cloning just returns a new no-op raw waker
|_| NOOP_RAW_WAKER,
// `wake` does nothing
|_| {},
// `wake_by_ref` does nothing
|_| {},
// Dropping does nothing as we don't allocate anything
|_| {},
);
RawWaker::new(ptr::null(), &VTABLE)
};

const NOOP_WAKER: &'static Waker = &unsafe { Waker::from_raw(NOOP_RAW_WAKER) };

#[tokio::main(flavor = "current_thread")]
async fn main() {
sleep_10ms().await;
sleep_0ms();
sleep_backwards_in_time();
}

async fn sleep_10ms() {
let dur = 10_000_000;
monotonic_clock::wait_until(monotonic_clock::now() + dur).await;
monotonic_clock::wait_for(dur).await;
}

fn sleep_0ms() {
let mut cx = Context::from_waker(NOOP_WAKER);

assert_eq!(
pin!(monotonic_clock::wait_until(monotonic_clock::now())).poll(&mut cx),
Poll::Ready(()),
"waiting until now() is ready immediately",
);
assert_eq!(
pin!(monotonic_clock::wait_for(0)).poll(&mut cx),
Poll::Ready(()),
"waiting for 0 is ready immediately",
);
}

fn sleep_backwards_in_time() {
let mut cx = Context::from_waker(NOOP_WAKER);

assert_eq!(
pin!(monotonic_clock::wait_until(monotonic_clock::now() - 1)).poll(&mut cx),
Poll::Ready(()),
"waiting until instant which has passed is ready immediately",
);
}
11 changes: 9 additions & 2 deletions crates/test-programs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ wit_bindgen::generate!({
include wasi:config/[email protected];
include wasi:keyvalue/[email protected];
include wasi:clocks/[email protected];
include wasi:random/[email protected];
}
",
Expand All @@ -23,6 +24,12 @@ wit_bindgen::generate!({
],
world: "wasmtime:test/test",
features: ["cli-exit-with-code"],
async: {
imports: [
"wasi:clocks/[email protected]#wait-for",
"wasi:clocks/[email protected]#wait-until",
],
},
generate_all,
});

Expand All @@ -42,8 +49,8 @@ pub mod proxy {
"wasi:cli/[email protected]": crate::wasi::cli::stdout,
"wasi:cli/[email protected]": crate::wasi::cli::stderr,
"wasi:cli/[email protected]": crate::wasi::cli::stdin,
"wasi:clocks/[email protected]": crate::wasi::clocks::monotonic_clock,
"wasi:clocks/[email protected]": crate::wasi::clocks::wall_clock,
"wasi:clocks/[email protected]": crate::wasi::clocks0_2_3::monotonic_clock,
"wasi:clocks/[email protected]": crate::wasi::clocks0_2_3::wall_clock,
},
});
}
2 changes: 1 addition & 1 deletion crates/test-programs/src/sockets.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::wasi::clocks::monotonic_clock;
use crate::wasi::clocks0_2_3::monotonic_clock;
use crate::wasi::io::poll::{self, Pollable};
use crate::wasi::io::streams::{InputStream, OutputStream, StreamError};
use crate::wasi::random0_2_3 as random;
Expand Down
1 change: 1 addition & 0 deletions crates/wasi-http/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub mod sync {
"wasi:http": crate::bindings::http, // http is in this crate
"wasi:io": wasmtime_wasi::bindings::sync::io, // io is sync
"wasi:random": wasmtime_wasi::bindings::random0_2_3, // use correct `wasi:random`
"wasi:clocks": wasmtime_wasi::bindings::clocks0_2_3, // use correct `wasi:clocks`
"wasi": wasmtime_wasi::bindings, // everything else
},
require_store_data_send: true,
Expand Down
8 changes: 4 additions & 4 deletions crates/wasi-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ where
{
let io_closure = type_annotate_io::<T, _>(|t| wasmtime_wasi::IoImpl(t));
let closure = type_annotate_wasi::<T, _>(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t)));
wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks0_2_3::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks0_2_3::monotonic_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::io::poll::add_to_linker_get_host(l, io_closure)?;
wasmtime_wasi::bindings::io::error::add_to_linker_get_host(l, io_closure)?;
wasmtime_wasi::bindings::io::streams::add_to_linker_get_host(l, io_closure)?;
Expand Down Expand Up @@ -385,8 +385,8 @@ where
let io_closure = type_annotate_io::<T, _>(|t| wasmtime_wasi::IoImpl(t));
let closure = type_annotate_wasi::<T, _>(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t)));

wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks0_2_3::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks0_2_3::monotonic_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?;
wasmtime_wasi::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?;
wasmtime_wasi::bindings::io::error::add_to_linker_get_host(l, io_closure)?;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package wasi:clocks@0.3.0;
/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
/// time.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
///
/// A monotonic clock is a clock which has an unspecified initial value, and
/// successive reads of the clock will produce non-decreasing values.
@since(version = 0.3.0)
interface monotonic-clock {
/// An instant in time, in nanoseconds. An instant is relative to an
/// unspecified initial value, and can only be compared to instances from
/// the same monotonic-clock.
@since(version = 0.3.0)
type instant = u64;

/// A duration of time, in nanoseconds.
@since(version = 0.3.0)
type duration = u64;

/// Read the current value of the clock.
///
/// The clock is monotonic, therefore calling this function repeatedly will
/// produce a sequence of non-decreasing values.
@since(version = 0.3.0)
now: func() -> instant;

/// Query the resolution of the clock. Returns the duration of time
/// corresponding to a clock tick.
@since(version = 0.3.0)
resolution: func() -> duration;

/// Wait until the specified instant has occurred.
@since(version = 0.3.0)
wait-until: func(
when: instant,
);

/// Wait for the specified duration has elapsed.
@since(version = 0.3.0)
wait-for: func(
how-long: duration,
);
}
55 changes: 55 additions & 0 deletions crates/wasi-http/wit/deps/clocks@[email protected]/timezone.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package wasi:clocks@0.3.0;

@unstable(feature = clocks-timezone)
interface timezone {
@unstable(feature = clocks-timezone)
use wall-clock.{datetime};

/// Return information needed to display the given `datetime`. This includes
/// the UTC offset, the time zone name, and a flag indicating whether
/// daylight saving time is active.
///
/// If the timezone cannot be determined for the given `datetime`, return a
/// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight
/// saving time.
@unstable(feature = clocks-timezone)
display: func(when: datetime) -> timezone-display;

/// The same as `display`, but only return the UTC offset.
@unstable(feature = clocks-timezone)
utc-offset: func(when: datetime) -> s32;

/// Information useful for displaying the timezone of a specific `datetime`.
///
/// This information may vary within a single `timezone` to reflect daylight
/// saving time adjustments.
@unstable(feature = clocks-timezone)
record timezone-display {
/// The number of seconds difference between UTC time and the local
/// time of the timezone.
///
/// The returned value will always be less than 86400 which is the
/// number of seconds in a day (24*60*60).
///
/// In implementations that do not expose an actual time zone, this
/// should return 0.
utc-offset: s32,

/// The abbreviated name of the timezone to display to a user. The name
/// `UTC` indicates Coordinated Universal Time. Otherwise, this should
/// reference local standards for the name of the time zone.
///
/// In implementations that do not expose an actual time zone, this
/// should be the string `UTC`.
///
/// In time zones that do not have an applicable name, a formatted
/// representation of the UTC offset may be returned, such as `-04:00`.
name: string,

/// Whether daylight saving time is active.
///
/// In implementations that do not expose an actual time zone, this
/// should return false.
in-daylight-saving-time: bool,
}
}
46 changes: 46 additions & 0 deletions crates/wasi-http/wit/deps/clocks@[email protected]/wall-clock.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package wasi:clocks@0.3.0;
/// WASI Wall Clock is a clock API intended to let users query the current
/// time. The name "wall" makes an analogy to a "clock on the wall", which
/// is not necessarily monotonic as it may be reset.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
///
/// A wall clock is a clock which measures the date and time according to
/// some external reference.
///
/// External references may be reset, so this clock is not necessarily
/// monotonic, making it unsuitable for measuring elapsed time.
///
/// It is intended for reporting the current date and time for humans.
@since(version = 0.3.0)
interface wall-clock {
/// A time and date in seconds plus nanoseconds.
@since(version = 0.3.0)
record datetime {
seconds: u64,
nanoseconds: u32,
}

/// Read the current value of the clock.
///
/// This clock is not monotonic, therefore calling this function repeatedly
/// will not necessarily produce a sequence of non-decreasing values.
///
/// The returned timestamps represent the number of seconds since
/// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
/// also known as [Unix Time].
///
/// The nanoseconds field of the output is always less than 1000000000.
///
/// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
/// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
@since(version = 0.3.0)
now: func() -> datetime;

/// Query the resolution of the clock.
///
/// The nanoseconds field of the output is always less than 1000000000.
@since(version = 0.3.0)
resolution: func() -> datetime;
}
11 changes: 11 additions & 0 deletions crates/wasi-http/wit/deps/clocks@[email protected]/world.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package wasi:clocks@0.3.0;

@since(version = 0.3.0)
world imports {
@since(version = 0.3.0)
import monotonic-clock;
@since(version = 0.3.0)
import wall-clock;
@unstable(feature = clocks-timezone)
import timezone;
}
2 changes: 1 addition & 1 deletion crates/wasi-preview1-component-adapter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)]
#![expect(clippy::allow_attributes, reason = "crate not migrated yet")]

use crate::bindings::wasi::clocks::{monotonic_clock, wall_clock};
use crate::bindings::wasi::clocks0_2_3::{monotonic_clock, wall_clock};
use crate::bindings::wasi::io::poll;
use crate::bindings::wasi::io::streams;
use crate::bindings::wasi::random0_2_3::random;
Expand Down
Loading

0 comments on commit 171a532

Please sign in to comment.