Path: blob/main/crates/wasi-common/src/snapshots/preview_0.rs
1692 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::{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.385#[wiggle::async_trait]386impl wasi_unstable::WasiUnstable for WasiCtx {387async fn args_get(388&mut self,389memory: &mut GuestMemory<'_>,390argv: GuestPtr<GuestPtr<u8>>,391argv_buf: GuestPtr<u8>,392) -> Result<(), Error> {393Snapshot1::args_get(self, memory, argv, argv_buf).await?;394Ok(())395}396397async fn args_sizes_get(398&mut self,399memory: &mut GuestMemory<'_>,400) -> Result<(types::Size, types::Size), Error> {401let s = Snapshot1::args_sizes_get(self, memory).await?;402Ok(s)403}404405async fn environ_get(406&mut self,407memory: &mut GuestMemory<'_>,408environ: GuestPtr<GuestPtr<u8>>,409environ_buf: GuestPtr<u8>,410) -> Result<(), Error> {411Snapshot1::environ_get(self, memory, environ, environ_buf).await?;412Ok(())413}414415async fn environ_sizes_get(416&mut self,417memory: &mut GuestMemory<'_>,418) -> Result<(types::Size, types::Size), Error> {419let s = Snapshot1::environ_sizes_get(self, memory).await?;420Ok(s)421}422423async fn clock_res_get(424&mut self,425memory: &mut GuestMemory<'_>,426id: types::Clockid,427) -> Result<types::Timestamp, Error> {428let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;429Ok(t)430}431432async fn clock_time_get(433&mut self,434memory: &mut GuestMemory<'_>,435id: types::Clockid,436precision: types::Timestamp,437) -> Result<types::Timestamp, Error> {438let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;439Ok(t)440}441442async fn fd_advise(443&mut self,444memory: &mut GuestMemory<'_>,445fd: types::Fd,446offset: types::Filesize,447len: types::Filesize,448advice: types::Advice,449) -> Result<(), Error> {450Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;451Ok(())452}453454async fn fd_allocate(455&mut self,456memory: &mut GuestMemory<'_>,457fd: types::Fd,458offset: types::Filesize,459len: types::Filesize,460) -> Result<(), Error> {461Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;462Ok(())463}464465async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {466Snapshot1::fd_close(self, memory, fd.into()).await?;467Ok(())468}469470async fn fd_datasync(471&mut self,472memory: &mut GuestMemory<'_>,473fd: types::Fd,474) -> Result<(), Error> {475Snapshot1::fd_datasync(self, memory, fd.into()).await?;476Ok(())477}478479async fn fd_fdstat_get(480&mut self,481memory: &mut GuestMemory<'_>,482fd: types::Fd,483) -> Result<types::Fdstat, Error> {484Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())485.await?486.into())487}488489async fn fd_fdstat_set_flags(490&mut self,491memory: &mut GuestMemory<'_>,492fd: types::Fd,493flags: types::Fdflags,494) -> Result<(), Error> {495Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;496Ok(())497}498499async fn fd_fdstat_set_rights(500&mut self,501memory: &mut GuestMemory<'_>,502fd: types::Fd,503fs_rights_base: types::Rights,504fs_rights_inheriting: types::Rights,505) -> Result<(), Error> {506Snapshot1::fd_fdstat_set_rights(507self,508memory,509fd.into(),510fs_rights_base.into(),511fs_rights_inheriting.into(),512)513.await?;514Ok(())515}516517async fn fd_filestat_get(518&mut self,519memory: &mut GuestMemory<'_>,520fd: types::Fd,521) -> Result<types::Filestat, Error> {522Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())523.await?524.into())525}526527async fn fd_filestat_set_size(528&mut self,529memory: &mut GuestMemory<'_>,530fd: types::Fd,531size: types::Filesize,532) -> Result<(), Error> {533Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;534Ok(())535}536537async fn fd_filestat_set_times(538&mut self,539memory: &mut GuestMemory<'_>,540fd: types::Fd,541atim: types::Timestamp,542mtim: types::Timestamp,543fst_flags: types::Fstflags,544) -> Result<(), Error> {545Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())546.await?;547Ok(())548}549550// NOTE on fd_read, fd_pread, fd_write, fd_pwrite implementations:551// these cast their pointers from preview0 vectors to preview1 vectors and552// this only works because the representation didn't change between preview0553// and preview1.554555async fn fd_read(556&mut self,557memory: &mut GuestMemory<'_>,558fd: types::Fd,559iovs: types::IovecArray,560) -> Result<types::Size, Error> {561Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)562}563564async fn fd_pread(565&mut self,566memory: &mut GuestMemory<'_>,567fd: types::Fd,568iovs: types::IovecArray,569offset: types::Filesize,570) -> Result<types::Size, Error> {571Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)572}573574async fn fd_write(575&mut self,576memory: &mut GuestMemory<'_>,577fd: types::Fd,578ciovs: types::CiovecArray,579) -> Result<types::Size, Error> {580Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)581}582583async fn fd_pwrite(584&mut self,585memory: &mut GuestMemory<'_>,586fd: types::Fd,587ciovs: types::CiovecArray,588offset: types::Filesize,589) -> Result<types::Size, Error> {590Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)591}592593async fn fd_prestat_get(594&mut self,595memory: &mut GuestMemory<'_>,596fd: types::Fd,597) -> Result<types::Prestat, Error> {598Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())599.await?600.into())601}602603async fn fd_prestat_dir_name(604&mut self,605memory: &mut GuestMemory<'_>,606fd: types::Fd,607path: GuestPtr<u8>,608path_max_len: types::Size,609) -> Result<(), Error> {610Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;611Ok(())612}613614async fn fd_renumber(615&mut self,616memory: &mut GuestMemory<'_>,617from: types::Fd,618to: types::Fd,619) -> Result<(), Error> {620Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;621Ok(())622}623624async fn fd_seek(625&mut self,626memory: &mut GuestMemory<'_>,627fd: types::Fd,628offset: types::Filedelta,629whence: types::Whence,630) -> Result<types::Filesize, Error> {631Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)632}633634async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {635Snapshot1::fd_sync(self, memory, fd.into()).await?;636Ok(())637}638639async fn fd_tell(640&mut self,641memory: &mut GuestMemory<'_>,642fd: types::Fd,643) -> Result<types::Filesize, Error> {644Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)645}646647async fn fd_readdir(648&mut self,649memory: &mut GuestMemory<'_>,650fd: types::Fd,651buf: GuestPtr<u8>,652buf_len: types::Size,653cookie: types::Dircookie,654) -> Result<types::Size, Error> {655Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)656}657658async fn path_create_directory(659&mut self,660memory: &mut GuestMemory<'_>,661dirfd: types::Fd,662path: GuestPtr<str>,663) -> Result<(), Error> {664Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;665Ok(())666}667668async fn path_filestat_get(669&mut self,670memory: &mut GuestMemory<'_>,671dirfd: types::Fd,672flags: types::Lookupflags,673path: GuestPtr<str>,674) -> Result<types::Filestat, Error> {675Ok(676Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)677.await?678.into(),679)680}681682async fn path_filestat_set_times(683&mut self,684memory: &mut GuestMemory<'_>,685dirfd: types::Fd,686flags: types::Lookupflags,687path: GuestPtr<str>,688atim: types::Timestamp,689mtim: types::Timestamp,690fst_flags: types::Fstflags,691) -> Result<(), Error> {692Snapshot1::path_filestat_set_times(693self,694memory,695dirfd.into(),696flags.into(),697path,698atim,699mtim,700fst_flags.into(),701)702.await?;703Ok(())704}705706async fn path_link(707&mut self,708memory: &mut GuestMemory<'_>,709src_fd: types::Fd,710src_flags: types::Lookupflags,711src_path: GuestPtr<str>,712target_fd: types::Fd,713target_path: GuestPtr<str>,714) -> Result<(), Error> {715Snapshot1::path_link(716self,717memory,718src_fd.into(),719src_flags.into(),720src_path,721target_fd.into(),722target_path,723)724.await?;725Ok(())726}727728async fn path_open(729&mut self,730memory: &mut GuestMemory<'_>,731dirfd: types::Fd,732dirflags: types::Lookupflags,733path: GuestPtr<str>,734oflags: types::Oflags,735fs_rights_base: types::Rights,736fs_rights_inheriting: types::Rights,737fdflags: types::Fdflags,738) -> Result<types::Fd, Error> {739Ok(Snapshot1::path_open(740self,741memory,742dirfd.into(),743dirflags.into(),744path,745oflags.into(),746fs_rights_base.into(),747fs_rights_inheriting.into(),748fdflags.into(),749)750.await?751.into())752}753754async fn path_readlink(755&mut self,756memory: &mut GuestMemory<'_>,757dirfd: types::Fd,758path: GuestPtr<str>,759buf: GuestPtr<u8>,760buf_len: types::Size,761) -> Result<types::Size, Error> {762Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)763}764765async fn path_remove_directory(766&mut self,767memory: &mut GuestMemory<'_>,768dirfd: types::Fd,769path: GuestPtr<str>,770) -> Result<(), Error> {771Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;772Ok(())773}774775async fn path_rename(776&mut self,777memory: &mut GuestMemory<'_>,778src_fd: types::Fd,779src_path: GuestPtr<str>,780dest_fd: types::Fd,781dest_path: GuestPtr<str>,782) -> Result<(), Error> {783Snapshot1::path_rename(784self,785memory,786src_fd.into(),787src_path,788dest_fd.into(),789dest_path,790)791.await?;792Ok(())793}794795async fn path_symlink(796&mut self,797memory: &mut GuestMemory<'_>,798src_path: GuestPtr<str>,799dirfd: types::Fd,800dest_path: GuestPtr<str>,801) -> Result<(), Error> {802Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;803Ok(())804}805806async fn path_unlink_file(807&mut self,808memory: &mut GuestMemory<'_>,809dirfd: types::Fd,810path: GuestPtr<str>,811) -> Result<(), Error> {812Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;813Ok(())814}815816// NOTE on poll_oneoff implementation:817// Like fd_write and friends, the arguments and return values are behind GuestPtrs,818// so they are not values we can convert and pass to the poll_oneoff in Snapshot1.819// Instead, we have copied the implementation of these functions from the Snapshot1 code.820// The implementations are identical, but the `types::` in scope locally is different.821// The bodies of these functions is mostly about converting the GuestPtr and types::-based822// representation to use the Poll abstraction.823async fn poll_oneoff(824&mut self,825memory: &mut GuestMemory<'_>,826subs: GuestPtr<types::Subscription>,827events: GuestPtr<types::Event>,828nsubscriptions: types::Size,829) -> Result<types::Size, Error> {830if nsubscriptions == 0 {831return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));832}833834// Special-case a `poll_oneoff` which is just sleeping on a single835// relative timer event, such as what WASI libc uses to implement sleep836// functions. This supports all clock IDs, because POSIX says that837// `clock_settime` doesn't effect relative sleeps.838if nsubscriptions == 1 {839let sub = memory.read(subs)?;840if let types::SubscriptionU::Clock(clocksub) = sub.u {841if !clocksub842.flags843.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)844{845self.sched846.sleep(Duration::from_nanos(clocksub.timeout))847.await?;848memory.write(849events,850types::Event {851userdata: sub.userdata,852error: types::Errno::Success,853type_: types::Eventtype::Clock,854fd_readwrite: fd_readwrite_empty(),855},856)?;857return Ok(1);858}859}860}861862let table = &self.table;863let mut sub_fds: HashSet<types::Fd> = HashSet::new();864// We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside865let mut reads: Vec<(u32, Userdata)> = Vec::new();866let mut writes: Vec<(u32, Userdata)> = Vec::new();867let mut poll = Poll::new();868869let subs = subs.as_array(nsubscriptions);870for sub_elem in subs.iter() {871let sub_ptr = sub_elem?;872let sub = memory.read(sub_ptr)?;873match sub.u {874types::SubscriptionU::Clock(clocksub) => match clocksub.id {875types::Clockid::Monotonic => {876let clock = self.clocks.monotonic()?;877let precision = Duration::from_nanos(clocksub.precision);878let duration = Duration::from_nanos(clocksub.timeout);879let start = if clocksub880.flags881.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)882{883clock.creation_time884} else {885clock.abs_clock.now(precision)886};887let deadline = start888.checked_add(duration)889.ok_or_else(|| Error::overflow().context("deadline"))?;890poll.subscribe_monotonic_clock(891&*clock.abs_clock,892deadline,893precision,894sub.userdata.into(),895)896}897_ => Err(Error::invalid_argument()898.context("timer subscriptions only support monotonic timer"))?,899},900types::SubscriptionU::FdRead(readsub) => {901let fd = readsub.file_descriptor;902if sub_fds.contains(&fd) {903return Err(Error::invalid_argument()904.context("Fd can be subscribed to at most once per poll"));905} else {906sub_fds.insert(fd);907}908table.get_file(u32::from(fd))?;909reads.push((u32::from(fd), sub.userdata.into()));910}911types::SubscriptionU::FdWrite(writesub) => {912let fd = writesub.file_descriptor;913if sub_fds.contains(&fd) {914return Err(Error::invalid_argument()915.context("Fd can be subscribed to at most once per poll"));916} else {917sub_fds.insert(fd);918}919table.get_file(u32::from(fd))?;920writes.push((u32::from(fd), sub.userdata.into()));921}922}923}924925self.sched.poll_oneoff(&mut poll).await?;926927let results = poll.results();928let num_results = results.len();929assert!(930num_results <= nsubscriptions as usize,931"results exceeds subscriptions"932);933let events = events.as_array(934num_results935.try_into()936.expect("not greater than nsubscriptions"),937);938for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {939let event_ptr = event_elem?;940let userdata: types::Userdata = userdata.into();941memory.write(942event_ptr,943match result {944SubscriptionResult::Read(r) => {945let type_ = types::Eventtype::FdRead;946match r {947Ok((nbytes, flags)) => types::Event {948userdata,949error: types::Errno::Success,950type_,951fd_readwrite: types::EventFdReadwrite {952nbytes,953flags: types::Eventrwflags::from(&flags),954},955},956Err(e) => types::Event {957userdata,958error: types::Errno::from(e.downcast().map_err(Error::trap)?),959type_,960fd_readwrite: fd_readwrite_empty(),961},962}963}964SubscriptionResult::Write(r) => {965let type_ = types::Eventtype::FdWrite;966match r {967Ok((nbytes, flags)) => types::Event {968userdata,969error: types::Errno::Success,970type_,971fd_readwrite: types::EventFdReadwrite {972nbytes,973flags: types::Eventrwflags::from(&flags),974},975},976Err(e) => types::Event {977userdata,978error: types::Errno::from(e.downcast().map_err(Error::trap)?),979type_,980fd_readwrite: fd_readwrite_empty(),981},982}983}984SubscriptionResult::MonotonicClock(r) => {985let type_ = types::Eventtype::Clock;986types::Event {987userdata,988error: match r {989Ok(()) => types::Errno::Success,990Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),991},992type_,993fd_readwrite: fd_readwrite_empty(),994}995}996},997)?;998}9991000Ok(num_results.try_into().expect("results fit into memory"))1001}10021003async fn proc_exit(1004&mut self,1005memory: &mut GuestMemory<'_>,1006status: types::Exitcode,1007) -> anyhow::Error {1008Snapshot1::proc_exit(self, memory, status).await1009}10101011async fn proc_raise(1012&mut self,1013_memory: &mut GuestMemory<'_>,1014_sig: types::Signal,1015) -> Result<(), Error> {1016Err(Error::trap(anyhow::Error::msg("proc_raise unsupported")))1017}10181019async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {1020Snapshot1::sched_yield(self, memory).await?;1021Ok(())1022}10231024async fn random_get(1025&mut self,1026memory: &mut GuestMemory<'_>,1027buf: GuestPtr<u8>,1028buf_len: types::Size,1029) -> Result<(), Error> {1030Snapshot1::random_get(self, memory, buf, buf_len).await?;1031Ok(())1032}10331034async fn sock_recv(1035&mut self,1036_memory: &mut GuestMemory<'_>,1037_fd: types::Fd,1038_ri_data: types::IovecArray,1039_ri_flags: types::Riflags,1040) -> Result<(types::Size, types::Roflags), Error> {1041Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))1042}10431044async fn sock_send(1045&mut self,1046_memory: &mut GuestMemory<'_>,1047_fd: types::Fd,1048_si_data: types::CiovecArray,1049_si_flags: types::Siflags,1050) -> Result<types::Size, Error> {1051Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))1052}10531054async fn sock_shutdown(1055&mut self,1056_memory: &mut GuestMemory<'_>,1057_fd: types::Fd,1058_how: types::Sdflags,1059) -> Result<(), Error> {1060Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))1061}1062}10631064impl From<&RwEventFlags> for types::Eventrwflags {1065fn from(flags: &RwEventFlags) -> types::Eventrwflags {1066let mut out = types::Eventrwflags::empty();1067if flags.contains(RwEventFlags::HANGUP) {1068out = out | types::Eventrwflags::FD_READWRITE_HANGUP;1069}1070out1071}1072}10731074fn fd_readwrite_empty() -> types::EventFdReadwrite {1075types::EventFdReadwrite {1076nbytes: 0,1077flags: types::Eventrwflags::empty(),1078}1079}108010811082