Skip to content

Commit c904ef4

Browse files
committed
feat: begin wasip3 implementation
Signed-off-by: Roman Volosatovs <[email protected]>
1 parent 20ceedc commit c904ef4

File tree

23 files changed

+1721
-119
lines changed

23 files changed

+1721
-119
lines changed

crates/test-programs/artifacts/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl Artifacts {
7878
s if s.starts_with("config_") => "config",
7979
s if s.starts_with("keyvalue_") => "keyvalue",
8080
s if s.starts_with("tls_") => "tls",
81+
s if s.starts_with("p3_") => "p3",
8182
// If you're reading this because you hit this panic, either add
8283
// it to a test suite above or add a new "suite". The purpose of
8384
// the categorization above is to have a static assertion that
@@ -100,6 +101,7 @@ impl Artifacts {
100101
}
101102
let adapter = match test.name.as_str() {
102103
"reactor" => &reactor_adapter,
104+
s if s.starts_with("p3_") => &reactor_adapter,
103105
s if s.starts_with("api_proxy") => &proxy_adapter,
104106
_ => &command_adapter,
105107
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use core::future::Future as _;
2+
use core::pin::pin;
3+
use core::task::{Context, Poll, Waker};
4+
5+
use test_programs::p3::wasi::clocks::monotonic_clock;
6+
7+
struct Component;
8+
9+
test_programs::p3::export!(Component);
10+
11+
impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
12+
async fn run() -> Result<(), ()> {
13+
sleep_10ms().await;
14+
sleep_0ms();
15+
sleep_backwards_in_time();
16+
Ok(())
17+
}
18+
}
19+
20+
async fn sleep_10ms() {
21+
let dur = 10_000_000;
22+
monotonic_clock::wait_until(monotonic_clock::now() + dur).await;
23+
monotonic_clock::wait_for(dur).await;
24+
}
25+
26+
fn sleep_0ms() {
27+
let mut cx = Context::from_waker(Waker::noop());
28+
29+
assert_eq!(
30+
pin!(monotonic_clock::wait_until(monotonic_clock::now())).poll(&mut cx),
31+
Poll::Ready(()),
32+
"waiting until now() is ready immediately",
33+
);
34+
assert_eq!(
35+
pin!(monotonic_clock::wait_for(0)).poll(&mut cx),
36+
Poll::Ready(()),
37+
"waiting for 0 is ready immediately",
38+
);
39+
}
40+
41+
fn sleep_backwards_in_time() {
42+
let mut cx = Context::from_waker(Waker::noop());
43+
44+
assert_eq!(
45+
pin!(monotonic_clock::wait_until(monotonic_clock::now() - 1)).poll(&mut cx),
46+
Poll::Ready(()),
47+
"waiting until instant which has passed is ready immediately",
48+
);
49+
}
50+
51+
fn main() {}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use test_programs::p3::wasi::random;
2+
3+
struct Component;
4+
5+
test_programs::p3::export!(Component);
6+
7+
impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
8+
async fn run() -> Result<(), ()> {
9+
let mut bytes = [0_u8; 256];
10+
unsafe {
11+
wasip1::random_get(bytes.as_mut_ptr(), bytes.len()).unwrap();
12+
}
13+
14+
assert!(bytes.iter().any(|x| *x != 0));
15+
16+
// Acquired random bytes should be of the expected length.
17+
let array = random::random::get_random_bytes(100);
18+
assert_eq!(array.len(), 100);
19+
20+
// It shouldn't take 100+ tries to get a nonzero random integer.
21+
for i in 0.. {
22+
if random::random::get_random_u64() == 0 {
23+
continue;
24+
}
25+
assert!(i < 100);
26+
break;
27+
}
28+
29+
// The `insecure_seed` API should return the same result each time.
30+
let (a1, b1) = random::insecure_seed::insecure_seed();
31+
let (a2, b2) = random::insecure_seed::insecure_seed();
32+
assert_eq!(a1, a2);
33+
assert_eq!(b1, b2);
34+
35+
// Acquired random bytes should be of the expected length.
36+
let array = random::insecure::get_insecure_random_bytes(100);
37+
assert_eq!(array.len(), 100);
38+
39+
// It shouldn't take 100+ tries to get a nonzero random integer.
40+
for i in 0.. {
41+
if random::insecure::get_insecure_random_u64() == 0 {
42+
continue;
43+
}
44+
assert!(i < 100);
45+
break;
46+
}
47+
Ok(())
48+
}
49+
}
50+
51+
fn main() {}

crates/test-programs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod http;
22
pub mod nn;
3+
pub mod p3;
34
pub mod preview1;
45
pub mod sockets;
56
pub mod tls;

crates/test-programs/src/p3/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
wit_bindgen::generate!({
2+
inline: "
3+
package wasmtime:test;
4+
5+
world testp3 {
6+
include wasi:cli/[email protected];
7+
8+
export wasi:cli/[email protected];
9+
}
10+
",
11+
path: "../wasi/src/p3/wit",
12+
world: "wasmtime:test/testp3",
13+
default_bindings_module: "test_programs::p3",
14+
pub_export_macro: true,
15+
async: [
16+
"wasi:cli/[email protected]#run",
17+
],
18+
generate_all
19+
});

crates/wasi/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ windows-sys = { workspace = true }
5555
rustix = { workspace = true, features = ["event", "net"] }
5656

5757
[features]
58-
default = [ "preview1"]
58+
default = ["preview1"]
5959
preview1 = [
6060
"dep:wiggle",
6161
]
62+
p3 = [
63+
"wasmtime/component-model-async",
64+
]
6265

6366
[[test]]
6467
name = "process_stdin"

crates/wasi/src/clocks.rs

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
1-
pub mod host;
2-
use cap_std::time::Duration;
1+
use cap_std::time::{Duration, Instant, SystemClock};
2+
use cap_std::{AmbientAuthority, ambient_authority};
3+
use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
4+
5+
#[repr(transparent)]
6+
pub struct WasiClocksImpl<T>(pub T);
7+
8+
impl<T: WasiClocksView> WasiClocksView for &mut T {
9+
fn clocks(&mut self) -> &WasiClocksCtx {
10+
(**self).clocks()
11+
}
12+
}
13+
14+
impl<T: WasiClocksView> WasiClocksView for WasiClocksImpl<T> {
15+
fn clocks(&mut self) -> &WasiClocksCtx {
16+
self.0.clocks()
17+
}
18+
}
19+
20+
impl WasiClocksView for WasiClocksCtx {
21+
fn clocks(&mut self) -> &WasiClocksCtx {
22+
self
23+
}
24+
}
25+
26+
pub trait WasiClocksView: Send {
27+
fn clocks(&mut self) -> &WasiClocksCtx;
28+
}
29+
30+
pub struct WasiClocksCtx {
31+
pub wall_clock: Box<dyn HostWallClock + Send>,
32+
pub monotonic_clock: Box<dyn HostMonotonicClock + Send>,
33+
}
34+
35+
impl Default for WasiClocksCtx {
36+
fn default() -> Self {
37+
Self {
38+
wall_clock: wall_clock(),
39+
monotonic_clock: monotonic_clock(),
40+
}
41+
}
42+
}
343

444
pub trait HostWallClock: Send {
545
fn resolution(&self) -> Duration;
@@ -10,3 +50,84 @@ pub trait HostMonotonicClock: Send {
1050
fn resolution(&self) -> u64;
1151
fn now(&self) -> u64;
1252
}
53+
54+
pub struct WallClock {
55+
/// The underlying system clock.
56+
clock: cap_std::time::SystemClock,
57+
}
58+
59+
impl Default for WallClock {
60+
fn default() -> Self {
61+
Self::new(ambient_authority())
62+
}
63+
}
64+
65+
impl WallClock {
66+
pub fn new(ambient_authority: AmbientAuthority) -> Self {
67+
Self {
68+
clock: cap_std::time::SystemClock::new(ambient_authority),
69+
}
70+
}
71+
}
72+
73+
impl HostWallClock for WallClock {
74+
fn resolution(&self) -> Duration {
75+
self.clock.resolution()
76+
}
77+
78+
fn now(&self) -> Duration {
79+
// WASI defines wall clocks to return "Unix time".
80+
self.clock
81+
.now()
82+
.duration_since(SystemClock::UNIX_EPOCH)
83+
.unwrap()
84+
}
85+
}
86+
87+
pub struct MonotonicClock {
88+
/// The underlying system clock.
89+
clock: cap_std::time::MonotonicClock,
90+
91+
/// The `Instant` this clock was created. All returned times are
92+
/// durations since that time.
93+
initial: Instant,
94+
}
95+
96+
impl Default for MonotonicClock {
97+
fn default() -> Self {
98+
Self::new(ambient_authority())
99+
}
100+
}
101+
102+
impl MonotonicClock {
103+
pub fn new(ambient_authority: AmbientAuthority) -> Self {
104+
let clock = cap_std::time::MonotonicClock::new(ambient_authority);
105+
let initial = clock.now();
106+
Self { clock, initial }
107+
}
108+
}
109+
110+
impl HostMonotonicClock for MonotonicClock {
111+
fn resolution(&self) -> u64 {
112+
self.clock.resolution().as_nanos().try_into().unwrap()
113+
}
114+
115+
fn now(&self) -> u64 {
116+
// Unwrap here and in `resolution` above; a `u64` is wide enough to
117+
// hold over 584 years of nanoseconds.
118+
self.clock
119+
.now()
120+
.duration_since(self.initial)
121+
.as_nanos()
122+
.try_into()
123+
.unwrap()
124+
}
125+
}
126+
127+
pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
128+
Box::new(MonotonicClock::default())
129+
}
130+
131+
pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
132+
Box::new(WallClock::default())
133+
}

crates/wasi/src/clocks/host.rs

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)