Skip to content

Commit e7d9c96

Browse files
committed
feat(wasi): add support for wasi:[email protected]
Signed-off-by: Roman Volosatovs <[email protected]>
1 parent 3ba676b commit e7d9c96

File tree

21 files changed

+364
-9
lines changed

21 files changed

+364
-9
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ci/vendor-wit.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ make_vendor "wasi/src/p2" "
4646
"
4747

4848
make_vendor "wasi/src/p3" "
49+
4950
5051
"
5152

crates/test-programs/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ anyhow = { workspace = true, features = ['std'] }
1515
wasi = "0.11.0"
1616
wasi-nn = "0.6.0"
1717
wit-bindgen = { workspace = true, features = ['default'] }
18+
# TODO: Remove once https://github.com/bytecodealliance/wit-bindgen/pull/1136 lands
19+
wit-bindgen-rt = "0.37"
1820
libc = { workspace = true }
1921
getrandom = "0.2.9"
2022
futures = { workspace = true, default-features = false, features = ['alloc'] }
2123
url = { workspace = true }
2224
sha2 = "0.10.2"
2325
base64 = "0.21.0"
2426
wasip2 = { version = "0.14.0", package = 'wasi' }
27+
tokio = { workspace = true, features = ["macros"] }

crates/test-programs/src/bin/preview2_sleep.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use test_programs::wasi::clocks::monotonic_clock;
1+
use test_programs::wasi::clocks0_2_3::monotonic_clock;
22

33
fn main() {
44
sleep_10ms();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use core::future::Future as _;
2+
use core::pin::pin;
3+
use core::ptr;
4+
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
5+
6+
use test_programs::wasi::clocks0_3_0::monotonic_clock;
7+
8+
// Adapted from https://github.com/rust-lang/rust/blob/cd805f09ffbfa3896c8f50a619de9b67e1d9f3c3/library/core/src/task/wake.rs#L63-L77
9+
// TODO: Replace by `Waker::noop` once MSRV is raised to 1.85
10+
const NOOP_RAW_WAKER: RawWaker = {
11+
const VTABLE: RawWakerVTable = RawWakerVTable::new(
12+
// Cloning just returns a new no-op raw waker
13+
|_| NOOP_RAW_WAKER,
14+
// `wake` does nothing
15+
|_| {},
16+
// `wake_by_ref` does nothing
17+
|_| {},
18+
// Dropping does nothing as we don't allocate anything
19+
|_| {},
20+
);
21+
RawWaker::new(ptr::null(), &VTABLE)
22+
};
23+
24+
const NOOP_WAKER: &'static Waker = &unsafe { Waker::from_raw(NOOP_RAW_WAKER) };
25+
26+
#[tokio::main(flavor = "current_thread")]
27+
async fn main() {
28+
sleep_10ms().await;
29+
sleep_0ms();
30+
sleep_backwards_in_time();
31+
}
32+
33+
async fn sleep_10ms() {
34+
let dur = 10_000_000;
35+
monotonic_clock::wait_until(monotonic_clock::now() + dur).await;
36+
monotonic_clock::wait_for(dur).await;
37+
}
38+
39+
fn sleep_0ms() {
40+
let mut cx = Context::from_waker(NOOP_WAKER);
41+
42+
assert_eq!(
43+
pin!(monotonic_clock::wait_until(monotonic_clock::now())).poll(&mut cx),
44+
Poll::Ready(()),
45+
"waiting until now() is ready immediately",
46+
);
47+
assert_eq!(
48+
pin!(monotonic_clock::wait_for(0)).poll(&mut cx),
49+
Poll::Ready(()),
50+
"waiting for 0 is ready immediately",
51+
);
52+
}
53+
54+
fn sleep_backwards_in_time() {
55+
let mut cx = Context::from_waker(NOOP_WAKER);
56+
57+
assert_eq!(
58+
pin!(monotonic_clock::wait_until(monotonic_clock::now() - 1)).poll(&mut cx),
59+
Poll::Ready(()),
60+
"waiting until instant which has passed is ready immediately",
61+
);
62+
}

crates/test-programs/src/lib.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ wit_bindgen::generate!({
1313
include wasi:config/[email protected];
1414
include wasi:keyvalue/[email protected];
1515
16+
include wasi:clocks/[email protected];
1617
include wasi:random/[email protected];
1718
}
1819
",
@@ -24,6 +25,12 @@ wit_bindgen::generate!({
2425
],
2526
world: "wasmtime:test/test",
2627
features: ["cli-exit-with-code"],
28+
async: {
29+
imports: [
30+
"wasi:clocks/[email protected]#wait-for",
31+
"wasi:clocks/[email protected]#wait-until",
32+
],
33+
},
2734
generate_all,
2835
});
2936

@@ -43,8 +50,8 @@ pub mod proxy {
4350
"wasi:cli/[email protected]": crate::wasi::cli::stdout,
4451
"wasi:cli/[email protected]": crate::wasi::cli::stderr,
4552
"wasi:cli/[email protected]": crate::wasi::cli::stdin,
46-
"wasi:clocks/[email protected]": crate::wasi::clocks::monotonic_clock,
47-
"wasi:clocks/[email protected]": crate::wasi::clocks::wall_clock,
53+
"wasi:clocks/[email protected]": crate::wasi::clocks0_2_3::monotonic_clock,
54+
"wasi:clocks/[email protected]": crate::wasi::clocks0_2_3::wall_clock,
4855
},
4956
});
5057
}

crates/test-programs/src/sockets.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::wasi::clocks::monotonic_clock;
1+
use crate::wasi::clocks0_2_3::monotonic_clock;
22
use crate::wasi::io::poll::{self, Pollable};
33
use crate::wasi::io::streams::{InputStream, OutputStream, StreamError};
44
use crate::wasi::random0_2_3 as random;

crates/wasi/src/p2/host/clocks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl TryFrom<SystemTime> for Datetime {
1717
let duration =
1818
time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
1919

20-
Ok(Datetime {
20+
Ok(Self {
2121
seconds: duration.as_secs(),
2222
nanoseconds: duration.subsec_nanos(),
2323
})

crates/wasi/src/p3/bindings.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
//! inline: "
2525
//! package example:wasi;
2626
//!
27-
//! // An example of extending the `wasi:random/imports` world with a
27+
//! // An example of extending the `wasi:cli/command` world with a
2828
//! // custom host interface.
2929
//! world my-world {
30+
//! include wasi:clocks/[email protected];
3031
//! include wasi:random/[email protected];
3132
//!
3233
//! import custom-host;
@@ -96,9 +97,10 @@
9697
/// inline: "
9798
/// package example:wasi;
9899
///
99-
/// // An example of extending the `wasi:random/imports` world with a
100+
/// // An example of extending the `wasi:cli/command` world with a
100101
/// // custom host interface.
101102
/// world my-world {
103+
/// include wasi:clocks/[email protected];
102104
/// include wasi:random/[email protected];
103105
///
104106
/// import custom-host;
@@ -157,6 +159,7 @@ pub mod sync {
157159
package inline:wasi;
158160
159161
world command {
162+
include wasi:clocks/[email protected];
160163
include wasi:random/[email protected];
161164
}
162165
",
@@ -166,6 +169,7 @@ pub mod sync {
166169
// These interfaces come from the outer module, as it's
167170
// sync/async agnostic.
168171
"wasi:random": crate::p3::bindings::random,
172+
"wasi:clocks/wall-clock": crate::p3::bindings::clocks::wall_clock,
169173
},
170174
require_store_data_send: true,
171175
});
@@ -324,6 +328,7 @@ mod async_io {
324328
package inline:wasi;
325329
326330
world command {
331+
include wasi:clocks/[email protected];
327332
include wasi:random/[email protected];
328333
}
329334
",
@@ -338,6 +343,8 @@ mod async_io {
338343
// which in theory can be shared across interfaces, so this may
339344
// need fancier syntax in the future.
340345
only_imports: [
346+
"wait-for",
347+
"wait-until",
341348
],
342349
},
343350
});

crates/wasi/src/p3/host/clocks.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use crate::p3::bindings::{
2+
clocks::monotonic_clock::{self, Duration as WasiDuration, Instant},
3+
clocks::wall_clock::{self, Datetime},
4+
};
5+
use crate::{WasiImpl, WasiView};
6+
use cap_std::time::SystemTime;
7+
use std::time::Duration;
8+
use tokio::time::sleep;
9+
10+
mod sync;
11+
12+
impl TryFrom<SystemTime> for Datetime {
13+
type Error = anyhow::Error;
14+
15+
fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
16+
let duration =
17+
time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
18+
19+
Ok(Self {
20+
seconds: duration.as_secs(),
21+
nanoseconds: duration.subsec_nanos(),
22+
})
23+
}
24+
}
25+
26+
impl<T> wall_clock::Host for WasiImpl<T>
27+
where
28+
T: WasiView,
29+
{
30+
fn now(&mut self) -> anyhow::Result<Datetime> {
31+
let now = self.ctx().wall_clock.now();
32+
Ok(Datetime {
33+
seconds: now.as_secs(),
34+
nanoseconds: now.subsec_nanos(),
35+
})
36+
}
37+
38+
fn resolution(&mut self) -> anyhow::Result<Datetime> {
39+
let res = self.ctx().wall_clock.resolution();
40+
Ok(Datetime {
41+
seconds: res.as_secs(),
42+
nanoseconds: res.subsec_nanos(),
43+
})
44+
}
45+
}
46+
47+
impl<T> monotonic_clock::Host for WasiImpl<T>
48+
where
49+
T: WasiView,
50+
{
51+
fn now(&mut self) -> anyhow::Result<Instant> {
52+
Ok(self.ctx().monotonic_clock.now())
53+
}
54+
55+
fn resolution(&mut self) -> anyhow::Result<Instant> {
56+
Ok(self.ctx().monotonic_clock.resolution())
57+
}
58+
59+
async fn wait_until(&mut self, when: Instant) -> anyhow::Result<()> {
60+
let clock_now = self.ctx().monotonic_clock.now();
61+
if when > clock_now {
62+
sleep(Duration::from_nanos(when - clock_now)).await;
63+
};
64+
Ok(())
65+
}
66+
67+
async fn wait_for(&mut self, duration: WasiDuration) -> anyhow::Result<()> {
68+
if duration > 0 {
69+
sleep(Duration::from_nanos(duration)).await;
70+
}
71+
Ok(())
72+
}
73+
}

0 commit comments

Comments
 (0)