Path: blob/main/crates/wasi-common/src/snapshots/preview_0.rs
3137 views
use crate::file::TableFileExt;1use crate::sched::{2Poll, Userdata,3subscription::{RwEventFlags, SubscriptionResult},4};5use crate::snapshots::preview_1::types as snapshot1_types;6use crate::snapshots::preview_1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;7use crate::{EnvError, ErrorExt, WasiCtx};8use cap_std::time::Duration;9use std::collections::HashSet;10use wiggle::{GuestMemory, GuestPtr};1112wiggle::from_witx!({13witx: ["witx/preview0/wasi_unstable.witx"],14errors: { errno => trappable Error },15async: *,16wasmtime: false,17});1819use types::Error;2021impl ErrorExt for Error {22fn not_found() -> Self {23types::Errno::Noent.into()24}25fn too_big() -> Self {26types::Errno::TooBig.into()27}28fn badf() -> Self {29types::Errno::Badf.into()30}31fn exist() -> Self {32types::Errno::Exist.into()33}34fn illegal_byte_sequence() -> Self {35types::Errno::Ilseq.into()36}37fn invalid_argument() -> Self {38types::Errno::Inval.into()39}40fn io() -> Self {41types::Errno::Io.into()42}43fn name_too_long() -> Self {44types::Errno::Nametoolong.into()45}46fn not_dir() -> Self {47types::Errno::Notdir.into()48}49fn not_supported() -> Self {50types::Errno::Notsup.into()51}52fn overflow() -> Self {53types::Errno::Overflow.into()54}55fn range() -> Self {56types::Errno::Range.into()57}58fn seek_pipe() -> Self {59types::Errno::Spipe.into()60}61fn perm() -> Self {62types::Errno::Perm.into()63}64}6566impl wiggle::GuestErrorType for types::Errno {67fn success() -> Self {68Self::Success69}70}7172impl From<wiggle::GuestError> for Error {73fn from(err: wiggle::GuestError) -> Error {74snapshot1_types::Error::from(err).into()75}76}7778impl From<snapshot1_types::Error> for Error {79fn from(error: snapshot1_types::Error) -> Error {80match error.downcast() {81Ok(errno) => Error::from(types::Errno::from(errno)),82Err(trap) => Error::trap(trap),83}84}85}8687impl From<std::num::TryFromIntError> for Error {88fn from(_err: std::num::TryFromIntError) -> Error {89types::Errno::Overflow.into()90}91}9293// Type conversions94// The vast majority of the types defined in `types` and `snapshot1_types` are identical. However,95// since they are defined in separate places for mechanical (wiggle) reasons, we need to manually96// define conversion functions between them.97// Below we have defined these functions as they are needed.9899/// Fd is a newtype wrapper around u32. Unwrap and wrap it.100impl From<types::Fd> for snapshot1_types::Fd {101fn from(fd: types::Fd) -> snapshot1_types::Fd {102u32::from(fd).into()103}104}105/// Fd is a newtype wrapper around u32. Unwrap and wrap it.106impl From<snapshot1_types::Fd> for types::Fd {107fn from(fd: snapshot1_types::Fd) -> types::Fd {108u32::from(fd).into()109}110}111112/// Trivial conversion between two c-style enums that have the exact same set of variants.113/// Could we do something unsafe and not list all these variants out? Probably, but doing114/// it this way doesn't bother me much. I copy-pasted the list of variants out of the115/// rendered rustdocs.116/// LLVM ought to compile these From impls into no-ops, inshallah117macro_rules! convert_enum {118($from:ty, $to:ty, $($var:ident),+) => {119impl From<$from> for $to {120fn from(e: $from) -> $to {121match e {122$( <$from>::$var => <$to>::$var, )+123}124}125}126}127}128convert_enum!(129snapshot1_types::Errno,130types::Errno,131Success,132TooBig,133Acces,134Addrinuse,135Addrnotavail,136Afnosupport,137Again,138Already,139Badf,140Badmsg,141Busy,142Canceled,143Child,144Connaborted,145Connrefused,146Connreset,147Deadlk,148Destaddrreq,149Dom,150Dquot,151Exist,152Fault,153Fbig,154Hostunreach,155Idrm,156Ilseq,157Inprogress,158Intr,159Inval,160Io,161Isconn,162Isdir,163Loop,164Mfile,165Mlink,166Msgsize,167Multihop,168Nametoolong,169Netdown,170Netreset,171Netunreach,172Nfile,173Nobufs,174Nodev,175Noent,176Noexec,177Nolck,178Nolink,179Nomem,180Nomsg,181Noprotoopt,182Nospc,183Nosys,184Notconn,185Notdir,186Notempty,187Notrecoverable,188Notsock,189Notsup,190Notty,191Nxio,192Overflow,193Ownerdead,194Perm,195Pipe,196Proto,197Protonosupport,198Prototype,199Range,200Rofs,201Spipe,202Srch,203Stale,204Timedout,205Txtbsy,206Xdev,207Notcapable208);209convert_enum!(210types::Clockid,211snapshot1_types::Clockid,212Realtime,213Monotonic,214ProcessCputimeId,215ThreadCputimeId216);217218convert_enum!(219types::Advice,220snapshot1_types::Advice,221Normal,222Sequential,223Random,224Willneed,225Dontneed,226Noreuse227);228convert_enum!(229snapshot1_types::Filetype,230types::Filetype,231Directory,232BlockDevice,233CharacterDevice,234RegularFile,235SocketDgram,236SocketStream,237SymbolicLink,238Unknown239);240convert_enum!(types::Whence, snapshot1_types::Whence, Cur, End, Set);241242/// Prestat isn't a c-style enum, its a union where the variant has a payload. Its the only one of243/// those we need to convert, so write it by hand.244impl From<snapshot1_types::Prestat> for types::Prestat {245fn from(p: snapshot1_types::Prestat) -> types::Prestat {246match p {247snapshot1_types::Prestat::Dir(d) => types::Prestat::Dir(d.into()),248}249}250}251252/// Trivial conversion between two structs that have the exact same set of fields,253/// with recursive descent into the field types.254macro_rules! convert_struct {255($from:ty, $to:path, $($field:ident),+) => {256impl From<$from> for $to {257fn from(e: $from) -> $to {258$to {259$( $field: e.$field.into(), )+260}261}262}263}264}265266convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);267convert_struct!(268snapshot1_types::Fdstat,269types::Fdstat,270fs_filetype,271fs_rights_base,272fs_rights_inheriting,273fs_flags274);275276/// Snapshot1 Filestat is incompatible with Snapshot0 Filestat - the nlink277/// field is u32 on this Filestat, and u64 on theirs. If you've got more than278/// 2^32 links I don't know what to tell you279impl From<snapshot1_types::Filestat> for types::Filestat {280fn from(f: snapshot1_types::Filestat) -> types::Filestat {281types::Filestat {282dev: f.dev,283ino: f.ino,284filetype: f.filetype.into(),285nlink: f.nlink.try_into().unwrap_or(u32::MAX),286size: f.size,287atim: f.atim,288mtim: f.mtim,289ctim: f.ctim,290}291}292}293294/// Trivial conversion between two bitflags that have the exact same set of flags.295macro_rules! convert_flags {296($from:ty, $to:ty, $($flag:ident),+) => {297impl From<$from> for $to {298fn from(f: $from) -> $to {299let mut out = <$to>::empty();300$(301if f.contains(<$from>::$flag) {302out |= <$to>::$flag;303}304)+305out306}307}308}309}310311/// Need to convert in both directions? This saves listing out the flags twice312macro_rules! convert_flags_bidirectional {313($from:ty, $to:ty, $($flag:tt)*) => {314convert_flags!($from, $to, $($flag)*);315convert_flags!($to, $from, $($flag)*);316}317}318319convert_flags_bidirectional!(320snapshot1_types::Fdflags,321types::Fdflags,322APPEND,323DSYNC,324NONBLOCK,325RSYNC,326SYNC327);328convert_flags!(329types::Lookupflags,330snapshot1_types::Lookupflags,331SYMLINK_FOLLOW332);333convert_flags!(334types::Fstflags,335snapshot1_types::Fstflags,336ATIM,337ATIM_NOW,338MTIM,339MTIM_NOW340);341convert_flags!(342types::Oflags,343snapshot1_types::Oflags,344CREAT,345DIRECTORY,346EXCL,347TRUNC348);349convert_flags_bidirectional!(350types::Rights,351snapshot1_types::Rights,352FD_DATASYNC,353FD_READ,354FD_SEEK,355FD_FDSTAT_SET_FLAGS,356FD_SYNC,357FD_TELL,358FD_WRITE,359FD_ADVISE,360FD_ALLOCATE,361PATH_CREATE_DIRECTORY,362PATH_CREATE_FILE,363PATH_LINK_SOURCE,364PATH_LINK_TARGET,365PATH_OPEN,366FD_READDIR,367PATH_READLINK,368PATH_RENAME_SOURCE,369PATH_RENAME_TARGET,370PATH_FILESTAT_GET,371PATH_FILESTAT_SET_SIZE,372PATH_FILESTAT_SET_TIMES,373FD_FILESTAT_GET,374FD_FILESTAT_SET_SIZE,375FD_FILESTAT_SET_TIMES,376PATH_SYMLINK,377PATH_REMOVE_DIRECTORY,378PATH_UNLINK_FILE,379POLL_FD_READWRITE,380SOCK_SHUTDOWN381);382383// This implementation, wherever possible, delegates directly to the Snapshot1 implementation,384// performing the no-op type conversions along the way.385impl wasi_unstable::WasiUnstable for WasiCtx {386async fn args_get(387&mut self,388memory: &mut GuestMemory<'_>,389argv: GuestPtr<GuestPtr<u8>>,390argv_buf: GuestPtr<u8>,391) -> Result<(), Error> {392Snapshot1::args_get(self, memory, argv, argv_buf).await?;393Ok(())394}395396async fn args_sizes_get(397&mut self,398memory: &mut GuestMemory<'_>,399) -> Result<(types::Size, types::Size), Error> {400let s = Snapshot1::args_sizes_get(self, memory).await?;401Ok(s)402}403404async fn environ_get(405&mut self,406memory: &mut GuestMemory<'_>,407environ: GuestPtr<GuestPtr<u8>>,408environ_buf: GuestPtr<u8>,409) -> Result<(), Error> {410Snapshot1::environ_get(self, memory, environ, environ_buf).await?;411Ok(())412}413414async fn environ_sizes_get(415&mut self,416memory: &mut GuestMemory<'_>,417) -> Result<(types::Size, types::Size), Error> {418let s = Snapshot1::environ_sizes_get(self, memory).await?;419Ok(s)420}421422async fn clock_res_get(423&mut self,424memory: &mut GuestMemory<'_>,425id: types::Clockid,426) -> Result<types::Timestamp, Error> {427let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;428Ok(t)429}430431async fn clock_time_get(432&mut self,433memory: &mut GuestMemory<'_>,434id: types::Clockid,435precision: types::Timestamp,436) -> Result<types::Timestamp, Error> {437let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;438Ok(t)439}440441async fn fd_advise(442&mut self,443memory: &mut GuestMemory<'_>,444fd: types::Fd,445offset: types::Filesize,446len: types::Filesize,447advice: types::Advice,448) -> Result<(), Error> {449Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;450Ok(())451}452453async fn fd_allocate(454&mut self,455memory: &mut GuestMemory<'_>,456fd: types::Fd,457offset: types::Filesize,458len: types::Filesize,459) -> Result<(), Error> {460Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;461Ok(())462}463464async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {465Snapshot1::fd_close(self, memory, fd.into()).await?;466Ok(())467}468469async fn fd_datasync(470&mut self,471memory: &mut GuestMemory<'_>,472fd: types::Fd,473) -> Result<(), Error> {474Snapshot1::fd_datasync(self, memory, fd.into()).await?;475Ok(())476}477478async fn fd_fdstat_get(479&mut self,480memory: &mut GuestMemory<'_>,481fd: types::Fd,482) -> Result<types::Fdstat, Error> {483Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())484.await?485.into())486}487488async fn fd_fdstat_set_flags(489&mut self,490memory: &mut GuestMemory<'_>,491fd: types::Fd,492flags: types::Fdflags,493) -> Result<(), Error> {494Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;495Ok(())496}497498async fn fd_fdstat_set_rights(499&mut self,500memory: &mut GuestMemory<'_>,501fd: types::Fd,502fs_rights_base: types::Rights,503fs_rights_inheriting: types::Rights,504) -> Result<(), Error> {505Snapshot1::fd_fdstat_set_rights(506self,507memory,508fd.into(),509fs_rights_base.into(),510fs_rights_inheriting.into(),511)512.await?;513Ok(())514}515516async fn fd_filestat_get(517&mut self,518memory: &mut GuestMemory<'_>,519fd: types::Fd,520) -> Result<types::Filestat, Error> {521Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())522.await?523.into())524}525526async fn fd_filestat_set_size(527&mut self,528memory: &mut GuestMemory<'_>,529fd: types::Fd,530size: types::Filesize,531) -> Result<(), Error> {532Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;533Ok(())534}535536async fn fd_filestat_set_times(537&mut self,538memory: &mut GuestMemory<'_>,539fd: types::Fd,540atim: types::Timestamp,541mtim: types::Timestamp,542fst_flags: types::Fstflags,543) -> Result<(), Error> {544Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())545.await?;546Ok(())547}548549// NOTE on fd_read, fd_pread, fd_write, fd_pwrite implementations:550// these cast their pointers from preview0 vectors to preview1 vectors and551// this only works because the representation didn't change between preview0552// and preview1.553554async fn fd_read(555&mut self,556memory: &mut GuestMemory<'_>,557fd: types::Fd,558iovs: types::IovecArray,559) -> Result<types::Size, Error> {560Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)561}562563async fn fd_pread(564&mut self,565memory: &mut GuestMemory<'_>,566fd: types::Fd,567iovs: types::IovecArray,568offset: types::Filesize,569) -> Result<types::Size, Error> {570Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)571}572573async fn fd_write(574&mut self,575memory: &mut GuestMemory<'_>,576fd: types::Fd,577ciovs: types::CiovecArray,578) -> Result<types::Size, Error> {579Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)580}581582async fn fd_pwrite(583&mut self,584memory: &mut GuestMemory<'_>,585fd: types::Fd,586ciovs: types::CiovecArray,587offset: types::Filesize,588) -> Result<types::Size, Error> {589Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)590}591592async fn fd_prestat_get(593&mut self,594memory: &mut GuestMemory<'_>,595fd: types::Fd,596) -> Result<types::Prestat, Error> {597Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())598.await?599.into())600}601602async fn fd_prestat_dir_name(603&mut self,604memory: &mut GuestMemory<'_>,605fd: types::Fd,606path: GuestPtr<u8>,607path_max_len: types::Size,608) -> Result<(), Error> {609Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;610Ok(())611}612613async fn fd_renumber(614&mut self,615memory: &mut GuestMemory<'_>,616from: types::Fd,617to: types::Fd,618) -> Result<(), Error> {619Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;620Ok(())621}622623async fn fd_seek(624&mut self,625memory: &mut GuestMemory<'_>,626fd: types::Fd,627offset: types::Filedelta,628whence: types::Whence,629) -> Result<types::Filesize, Error> {630Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)631}632633async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {634Snapshot1::fd_sync(self, memory, fd.into()).await?;635Ok(())636}637638async fn fd_tell(639&mut self,640memory: &mut GuestMemory<'_>,641fd: types::Fd,642) -> Result<types::Filesize, Error> {643Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)644}645646async fn fd_readdir(647&mut self,648memory: &mut GuestMemory<'_>,649fd: types::Fd,650buf: GuestPtr<u8>,651buf_len: types::Size,652cookie: types::Dircookie,653) -> Result<types::Size, Error> {654Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)655}656657async fn path_create_directory(658&mut self,659memory: &mut GuestMemory<'_>,660dirfd: types::Fd,661path: GuestPtr<str>,662) -> Result<(), Error> {663Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;664Ok(())665}666667async fn path_filestat_get(668&mut self,669memory: &mut GuestMemory<'_>,670dirfd: types::Fd,671flags: types::Lookupflags,672path: GuestPtr<str>,673) -> Result<types::Filestat, Error> {674Ok(675Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)676.await?677.into(),678)679}680681async fn path_filestat_set_times(682&mut self,683memory: &mut GuestMemory<'_>,684dirfd: types::Fd,685flags: types::Lookupflags,686path: GuestPtr<str>,687atim: types::Timestamp,688mtim: types::Timestamp,689fst_flags: types::Fstflags,690) -> Result<(), Error> {691Snapshot1::path_filestat_set_times(692self,693memory,694dirfd.into(),695flags.into(),696path,697atim,698mtim,699fst_flags.into(),700)701.await?;702Ok(())703}704705async fn path_link(706&mut self,707memory: &mut GuestMemory<'_>,708src_fd: types::Fd,709src_flags: types::Lookupflags,710src_path: GuestPtr<str>,711target_fd: types::Fd,712target_path: GuestPtr<str>,713) -> Result<(), Error> {714Snapshot1::path_link(715self,716memory,717src_fd.into(),718src_flags.into(),719src_path,720target_fd.into(),721target_path,722)723.await?;724Ok(())725}726727async fn path_open(728&mut self,729memory: &mut GuestMemory<'_>,730dirfd: types::Fd,731dirflags: types::Lookupflags,732path: GuestPtr<str>,733oflags: types::Oflags,734fs_rights_base: types::Rights,735fs_rights_inheriting: types::Rights,736fdflags: types::Fdflags,737) -> Result<types::Fd, Error> {738Ok(Snapshot1::path_open(739self,740memory,741dirfd.into(),742dirflags.into(),743path,744oflags.into(),745fs_rights_base.into(),746fs_rights_inheriting.into(),747fdflags.into(),748)749.await?750.into())751}752753async fn path_readlink(754&mut self,755memory: &mut GuestMemory<'_>,756dirfd: types::Fd,757path: GuestPtr<str>,758buf: GuestPtr<u8>,759buf_len: types::Size,760) -> Result<types::Size, Error> {761Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)762}763764async fn path_remove_directory(765&mut self,766memory: &mut GuestMemory<'_>,767dirfd: types::Fd,768path: GuestPtr<str>,769) -> Result<(), Error> {770Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;771Ok(())772}773774async fn path_rename(775&mut self,776memory: &mut GuestMemory<'_>,777src_fd: types::Fd,778src_path: GuestPtr<str>,779dest_fd: types::Fd,780dest_path: GuestPtr<str>,781) -> Result<(), Error> {782Snapshot1::path_rename(783self,784memory,785src_fd.into(),786src_path,787dest_fd.into(),788dest_path,789)790.await?;791Ok(())792}793794async fn path_symlink(795&mut self,796memory: &mut GuestMemory<'_>,797src_path: GuestPtr<str>,798dirfd: types::Fd,799dest_path: GuestPtr<str>,800) -> Result<(), Error> {801Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;802Ok(())803}804805async fn path_unlink_file(806&mut self,807memory: &mut GuestMemory<'_>,808dirfd: types::Fd,809path: GuestPtr<str>,810) -> Result<(), Error> {811Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;812Ok(())813}814815// NOTE on poll_oneoff implementation:816// Like fd_write and friends, the arguments and return values are behind GuestPtrs,817// so they are not values we can convert and pass to the poll_oneoff in Snapshot1.818// Instead, we have copied the implementation of these functions from the Snapshot1 code.819// The implementations are identical, but the `types::` in scope locally is different.820// The bodies of these functions is mostly about converting the GuestPtr and types::-based821// representation to use the Poll abstraction.822async fn poll_oneoff(823&mut self,824memory: &mut GuestMemory<'_>,825subs: GuestPtr<types::Subscription>,826events: GuestPtr<types::Event>,827nsubscriptions: types::Size,828) -> Result<types::Size, Error> {829if nsubscriptions == 0 {830return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));831}832833// Special-case a `poll_oneoff` which is just sleeping on a single834// relative timer event, such as what WASI libc uses to implement sleep835// functions. This supports all clock IDs, because POSIX says that836// `clock_settime` doesn't effect relative sleeps.837if nsubscriptions == 1 {838let sub = memory.read(subs)?;839if let types::SubscriptionU::Clock(clocksub) = sub.u {840if !clocksub841.flags842.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)843{844self.sched845.sleep(Duration::from_nanos(clocksub.timeout))846.await?;847memory.write(848events,849types::Event {850userdata: sub.userdata,851error: types::Errno::Success,852type_: types::Eventtype::Clock,853fd_readwrite: fd_readwrite_empty(),854},855)?;856return Ok(1);857}858}859}860861let table = &self.table;862let mut sub_fds: HashSet<types::Fd> = HashSet::new();863// We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside864let mut reads: Vec<(u32, Userdata)> = Vec::new();865let mut writes: Vec<(u32, Userdata)> = Vec::new();866let mut poll = Poll::new();867868let subs = subs.as_array(nsubscriptions);869for sub_elem in subs.iter() {870let sub_ptr = sub_elem?;871let sub = memory.read(sub_ptr)?;872match sub.u {873types::SubscriptionU::Clock(clocksub) => match clocksub.id {874types::Clockid::Monotonic => {875let clock = self.clocks.monotonic()?;876let precision = Duration::from_nanos(clocksub.precision);877let duration = Duration::from_nanos(clocksub.timeout);878let start = if clocksub879.flags880.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)881{882clock.creation_time883} else {884clock.abs_clock.now(precision)885};886let deadline = start887.checked_add(duration)888.ok_or_else(|| Error::overflow().context("deadline"))?;889poll.subscribe_monotonic_clock(890&*clock.abs_clock,891deadline,892precision,893sub.userdata.into(),894)895}896_ => Err(Error::invalid_argument()897.context("timer subscriptions only support monotonic timer"))?,898},899types::SubscriptionU::FdRead(readsub) => {900let fd = readsub.file_descriptor;901if sub_fds.contains(&fd) {902return Err(Error::invalid_argument()903.context("Fd can be subscribed to at most once per poll"));904} else {905sub_fds.insert(fd);906}907table.get_file(u32::from(fd))?;908reads.push((u32::from(fd), sub.userdata.into()));909}910types::SubscriptionU::FdWrite(writesub) => {911let fd = writesub.file_descriptor;912if sub_fds.contains(&fd) {913return Err(Error::invalid_argument()914.context("Fd can be subscribed to at most once per poll"));915} else {916sub_fds.insert(fd);917}918table.get_file(u32::from(fd))?;919writes.push((u32::from(fd), sub.userdata.into()));920}921}922}923924self.sched.poll_oneoff(&mut poll).await?;925926let results = poll.results();927let num_results = results.len();928assert!(929num_results <= nsubscriptions as usize,930"results exceeds subscriptions"931);932let events = events.as_array(933num_results934.try_into()935.expect("not greater than nsubscriptions"),936);937for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {938let event_ptr = event_elem?;939let userdata: types::Userdata = userdata.into();940memory.write(941event_ptr,942match result {943SubscriptionResult::Read(r) => {944let type_ = types::Eventtype::FdRead;945match r {946Ok((nbytes, flags)) => types::Event {947userdata,948error: types::Errno::Success,949type_,950fd_readwrite: types::EventFdReadwrite {951nbytes,952flags: types::Eventrwflags::from(&flags),953},954},955Err(e) => types::Event {956userdata,957error: types::Errno::from(e.downcast().map_err(Error::trap)?),958type_,959fd_readwrite: fd_readwrite_empty(),960},961}962}963SubscriptionResult::Write(r) => {964let type_ = types::Eventtype::FdWrite;965match r {966Ok((nbytes, flags)) => types::Event {967userdata,968error: types::Errno::Success,969type_,970fd_readwrite: types::EventFdReadwrite {971nbytes,972flags: types::Eventrwflags::from(&flags),973},974},975Err(e) => types::Event {976userdata,977error: types::Errno::from(e.downcast().map_err(Error::trap)?),978type_,979fd_readwrite: fd_readwrite_empty(),980},981}982}983SubscriptionResult::MonotonicClock(r) => {984let type_ = types::Eventtype::Clock;985types::Event {986userdata,987error: match r {988Ok(()) => types::Errno::Success,989Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),990},991type_,992fd_readwrite: fd_readwrite_empty(),993}994}995},996)?;997}998999Ok(num_results.try_into().expect("results fit into memory"))1000}10011002async fn proc_exit(1003&mut self,1004memory: &mut GuestMemory<'_>,1005status: types::Exitcode,1006) -> EnvError {1007Snapshot1::proc_exit(self, memory, status).await1008}10091010async fn proc_raise(1011&mut self,1012_memory: &mut GuestMemory<'_>,1013_sig: types::Signal,1014) -> Result<(), Error> {1015Err(Error::trap(EnvError::msg("proc_raise unsupported")))1016}10171018async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {1019Snapshot1::sched_yield(self, memory).await?;1020Ok(())1021}10221023async fn random_get(1024&mut self,1025memory: &mut GuestMemory<'_>,1026buf: GuestPtr<u8>,1027buf_len: types::Size,1028) -> Result<(), Error> {1029Snapshot1::random_get(self, memory, buf, buf_len).await?;1030Ok(())1031}10321033async fn sock_recv(1034&mut self,1035_memory: &mut GuestMemory<'_>,1036_fd: types::Fd,1037_ri_data: types::IovecArray,1038_ri_flags: types::Riflags,1039) -> Result<(types::Size, types::Roflags), Error> {1040Err(Error::trap(EnvError::msg("sock_recv unsupported")))1041}10421043async fn sock_send(1044&mut self,1045_memory: &mut GuestMemory<'_>,1046_fd: types::Fd,1047_si_data: types::CiovecArray,1048_si_flags: types::Siflags,1049) -> Result<types::Size, Error> {1050Err(Error::trap(EnvError::msg("sock_send unsupported")))1051}10521053async fn sock_shutdown(1054&mut self,1055_memory: &mut GuestMemory<'_>,1056_fd: types::Fd,1057_how: types::Sdflags,1058) -> Result<(), Error> {1059Err(Error::trap(EnvError::msg("sock_shutdown unsupported")))1060}1061}10621063impl From<&RwEventFlags> for types::Eventrwflags {1064fn from(flags: &RwEventFlags) -> types::Eventrwflags {1065let mut out = types::Eventrwflags::empty();1066if flags.contains(RwEventFlags::HANGUP) {1067out = out | types::Eventrwflags::FD_READWRITE_HANGUP;1068}1069out1070}1071}10721073fn fd_readwrite_empty() -> types::EventFdReadwrite {1074types::EventFdReadwrite {1075nbytes: 0,1076flags: types::Eventrwflags::empty(),1077}1078}107910801081