Skip to content
This repository has been archived by the owner on Oct 13, 2023. It is now read-only.

Commit

Permalink
Add pseudo-streams. (#29)
Browse files Browse the repository at this point in the history
* Add pseudo-streams.

This add a pseudo-stream type to the wasi-poll interface, and adds ways
to obtain streams from command invocation and from files. In the future,
it can support sockets too. With this, `command` takes streams for
stdin/stdout, rather than filesystem descriptors.

Streams support reading and writing, as well as skipping,
repeated-element writing, and splicing from one stream to another. And
there are `subscribe-*` functions to produce pseudo-futures from
pseudo-streams, allowing them to be polled.

This makes the polyfill somewhat more complex, but this is largely due
to the polyfill being tied to the preview1 API.

This replaces the `seek` and `tell` functions, and implemented `fd_seek`
and `fd_tell` in terms of the polyfill's own position.

Also, add a dedicated stderr API for writing to stderr in a way that
tolerates strings that aren't necessarily expected to be newlines. And
add a way to test whether stderr is a terminal.

* Implement the host side of `poll_oneoff`.

This implements pseudo-futures and subscription functions, and adds
polling for streams.

* Implement clock subscriptions.

wasi.wit:

 - Remove the "timers" API from wasi-clocks, as it's now redundant with
   pseudo-future clock subscriptions.

 - Remove `subscribe-wall-clock`. Wall-clock timeouts were implemented by
   converting them to monotonic-clock timeouts anyway, so just make that
   explicit in the WASI API, and teach the polyfill how to convert
   wall-clock timeouts into monotonic-clock timeouts.

 - Move `subscribe-monotonic-clock` out of wasi-clocks and into wasi-poll,
   as it's closely tied to the pseudo-futures mechanism and the `poll-oneoff`
   implementation.

 - While here, fix `stream-read` and related functions to return an
   end-of-stream/file indicator.

Code changes:

 - `default_wall_clock()` and `default_monotonic_clock()` now always
   create a new table entry, rather than holding a table index in the
   `WasiCtx` which could potentially dangle.

 - Add support for monotonic-clock poll subscriptions.

 - Say "wall clock" instead of "system clock" when we have a choice.

* Remove the `OFlags::APPEND` flag, which is no longer used.
  • Loading branch information
sunfishcode committed Dec 23, 2022
1 parent b1c261a commit 106d19a
Show file tree
Hide file tree
Showing 34 changed files with 2,050 additions and 882 deletions.
29 changes: 21 additions & 8 deletions Cargo.lock

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

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ edition = "2021"
anyhow = "1.0.22"
thiserror = "1.0.15"
tracing = "0.1.26"
cap-std = "1.0.0"
cap-rand = "1.0.0"
cap-std = "1.0.2"
cap-rand = "1.0.2"
cap-fs-ext = "1.0.2"
bitflags = "1.2"
windows-sys = "0.42.0"
rustix = "0.36.0"
Expand Down
2 changes: 2 additions & 0 deletions host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ tracing = { workspace = true }
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", features = ["component-model"] }
wasi-common = { path = "../wasi-common" }
wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" }
is-terminal = "0.4.1"
terminal_size = "0.2.3"

[dev-dependencies]
test-programs-macros = { path = "../test-programs/macros" }
Expand Down
89 changes: 21 additions & 68 deletions host/src/clocks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{wasi_clocks, wasi_default_clocks, WasiCtx};
use anyhow::Context;
use cap_std::time::SystemTime;
use wasi_common::clocks::{MonotonicClock, MonotonicTimer, WallClock};
use wasi_common::clocks::{TableMonotonicClockExt, TableWallClockExt};

impl TryFrom<SystemTime> for wasi_clocks::Datetime {
type Error = anyhow::Error;
Expand All @@ -19,102 +18,56 @@ impl TryFrom<SystemTime> for wasi_clocks::Datetime {

#[async_trait::async_trait]
impl wasi_default_clocks::WasiDefaultClocks for WasiCtx {
async fn default_monotonic_clock(&mut self) -> anyhow::Result<wasi_clocks::MonotonicClock> {
Ok(self.clocks.default_monotonic)
async fn default_wall_clock(&mut self) -> anyhow::Result<wasi_clocks::WallClock> {
// Create a new handle to the default wall clock.
let new = self.clocks.default_wall_clock.dup();
Ok(self.table_mut().push(Box::new(new))?)
}

async fn default_wall_clock(&mut self) -> anyhow::Result<wasi_clocks::WallClock> {
Ok(self.clocks.default_wall)
async fn default_monotonic_clock(&mut self) -> anyhow::Result<wasi_clocks::MonotonicClock> {
// Create a new handle to the default monotonic clock.
let new = self.clocks.default_monotonic_clock.dup();
Ok(self.table_mut().push(Box::new(new))?)
}
}

#[async_trait::async_trait]
impl wasi_clocks::WasiClocks for WasiCtx {
async fn subscribe_wall_clock(
&mut self,
when: wasi_clocks::Datetime,
absolute: bool,
) -> anyhow::Result<wasi_clocks::WasiFuture> {
drop((when, absolute));
todo!()
}

async fn subscribe_monotonic_clock(
&mut self,
when: wasi_clocks::Instant,
absolute: bool,
) -> anyhow::Result<wasi_clocks::WasiFuture> {
drop((when, absolute));
todo!()
}

async fn monotonic_clock_now(
&mut self,
fd: wasi_clocks::MonotonicClock,
) -> anyhow::Result<wasi_clocks::Instant> {
let clock = self.table.get::<MonotonicClock>(fd)?;
let now = clock.now(self.clocks.monotonic.as_ref());
Ok(now
.as_nanos()
.try_into()
.context("converting monotonic time to nanos u64")?)
Ok(self.table().get_monotonic_clock(fd)?.now())
}

async fn monotonic_clock_resolution(
&mut self,
fd: wasi_clocks::MonotonicClock,
) -> anyhow::Result<wasi_clocks::Instant> {
self.table.get::<MonotonicClock>(fd)?;
let res = self.clocks.monotonic.resolution();
Ok(res
.as_nanos()
.try_into()
.context("converting monotonic resolution to nanos u64")?)
}

async fn monotonic_clock_new_timer(
&mut self,
fd: wasi_clocks::MonotonicClock,
initial: wasi_clocks::Instant,
) -> anyhow::Result<wasi_clocks::MonotonicTimer> {
let clock = self.table.get::<MonotonicClock>(fd)?;
let timer = clock.new_timer(std::time::Duration::from_micros(initial));
drop(clock);
let timer_fd = self.table.push(Box::new(timer))?;
Ok(timer_fd)
Ok(self.table().get_monotonic_clock(fd)?.now())
}

async fn wall_clock_now(
&mut self,
fd: wasi_clocks::WallClock,
) -> anyhow::Result<wasi_clocks::Datetime> {
let clock = self.table.get::<WallClock>(fd)?;
Ok(clock.now(self.clocks.system.as_ref()).try_into()?)
let clock = self.table().get_wall_clock(fd)?;
let now = clock.now();
Ok(wasi_clocks::Datetime {
seconds: now.as_secs(),
nanoseconds: now.subsec_nanos(),
})
}

async fn wall_clock_resolution(
&mut self,
fd: wasi_clocks::WallClock,
) -> anyhow::Result<wasi_clocks::Datetime> {
self.table.get::<WallClock>(fd)?;
let nanos = self.clocks.system.resolution().as_nanos();
let clock = self.table().get_wall_clock(fd)?;
let res = clock.resolution();
Ok(wasi_clocks::Datetime {
seconds: (nanos / 1_000_000_000_u128)
.try_into()
.context("converting wall clock resolution to seconds u64")?,
nanoseconds: (nanos % 1_000_000_000_u128).try_into().unwrap(),
seconds: res.as_secs(),
nanoseconds: res.subsec_nanos(),
})
}

async fn monotonic_timer_current(
&mut self,
fd: wasi_clocks::MonotonicTimer,
) -> anyhow::Result<wasi_clocks::Instant> {
let timer = self.table.get::<MonotonicTimer>(fd)?;
Ok(timer
.current(self.clocks.monotonic.as_ref())
.as_nanos()
.try_into()
.context("converting monotonic timer to nanos u64")?)
}
}
Loading

0 comments on commit 106d19a

Please sign in to comment.