1use crate::file::TableFileExt;
2use crate::sched::{
3 Poll, Userdata,
4 subscription::{RwEventFlags, SubscriptionResult},
5};
6use crate::snapshots::preview_1::types as snapshot1_types;
7use crate::snapshots::preview_1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;
8use crate::{ErrorExt, WasiCtx};
9use cap_std::time::Duration;
10use std::collections::HashSet;
11use wiggle::{GuestMemory, GuestPtr};
12
13wiggle::from_witx!({
14 witx: ["witx/preview0/wasi_unstable.witx"],
15 errors: { errno => trappable Error },
16 async: *,
17 wasmtime: false,
18});
19
20use types::Error;
21
22impl ErrorExt for Error {
23 fn not_found() -> Self {
24 types::Errno::Noent.into()
25 }
26 fn too_big() -> Self {
27 types::Errno::TooBig.into()
28 }
29 fn badf() -> Self {
30 types::Errno::Badf.into()
31 }
32 fn exist() -> Self {
33 types::Errno::Exist.into()
34 }
35 fn illegal_byte_sequence() -> Self {
36 types::Errno::Ilseq.into()
37 }
38 fn invalid_argument() -> Self {
39 types::Errno::Inval.into()
40 }
41 fn io() -> Self {
42 types::Errno::Io.into()
43 }
44 fn name_too_long() -> Self {
45 types::Errno::Nametoolong.into()
46 }
47 fn not_dir() -> Self {
48 types::Errno::Notdir.into()
49 }
50 fn not_supported() -> Self {
51 types::Errno::Notsup.into()
52 }
53 fn overflow() -> Self {
54 types::Errno::Overflow.into()
55 }
56 fn range() -> Self {
57 types::Errno::Range.into()
58 }
59 fn seek_pipe() -> Self {
60 types::Errno::Spipe.into()
61 }
62 fn perm() -> Self {
63 types::Errno::Perm.into()
64 }
65}
66
67impl wiggle::GuestErrorType for types::Errno {
68 fn success() -> Self {
69 Self::Success
70 }
71}
72
73impl From<wiggle::GuestError> for Error {
74 fn from(err: wiggle::GuestError) -> Error {
75 snapshot1_types::Error::from(err).into()
76 }
77}
78
79impl From<snapshot1_types::Error> for Error {
80 fn from(error: snapshot1_types::Error) -> Error {
81 match error.downcast() {
82 Ok(errno) => Error::from(types::Errno::from(errno)),
83 Err(trap) => Error::trap(trap),
84 }
85 }
86}
87
88impl From<std::num::TryFromIntError> for Error {
89 fn from(_err: std::num::TryFromIntError) -> Error {
90 types::Errno::Overflow.into()
91 }
92}
93
94impl From<types::Fd> for snapshot1_types::Fd {
102 fn from(fd: types::Fd) -> snapshot1_types::Fd {
103 u32::from(fd).into()
104 }
105}
106impl From<snapshot1_types::Fd> for types::Fd {
108 fn from(fd: snapshot1_types::Fd) -> types::Fd {
109 u32::from(fd).into()
110 }
111}
112
113macro_rules! convert_enum {
119 ($from:ty, $to:ty, $($var:ident),+) => {
120 impl From<$from> for $to {
121 fn from(e: $from) -> $to {
122 match e {
123 $( <$from>::$var => <$to>::$var, )+
124 }
125 }
126 }
127 }
128}
129convert_enum!(
130 snapshot1_types::Errno,
131 types::Errno,
132 Success,
133 TooBig,
134 Acces,
135 Addrinuse,
136 Addrnotavail,
137 Afnosupport,
138 Again,
139 Already,
140 Badf,
141 Badmsg,
142 Busy,
143 Canceled,
144 Child,
145 Connaborted,
146 Connrefused,
147 Connreset,
148 Deadlk,
149 Destaddrreq,
150 Dom,
151 Dquot,
152 Exist,
153 Fault,
154 Fbig,
155 Hostunreach,
156 Idrm,
157 Ilseq,
158 Inprogress,
159 Intr,
160 Inval,
161 Io,
162 Isconn,
163 Isdir,
164 Loop,
165 Mfile,
166 Mlink,
167 Msgsize,
168 Multihop,
169 Nametoolong,
170 Netdown,
171 Netreset,
172 Netunreach,
173 Nfile,
174 Nobufs,
175 Nodev,
176 Noent,
177 Noexec,
178 Nolck,
179 Nolink,
180 Nomem,
181 Nomsg,
182 Noprotoopt,
183 Nospc,
184 Nosys,
185 Notconn,
186 Notdir,
187 Notempty,
188 Notrecoverable,
189 Notsock,
190 Notsup,
191 Notty,
192 Nxio,
193 Overflow,
194 Ownerdead,
195 Perm,
196 Pipe,
197 Proto,
198 Protonosupport,
199 Prototype,
200 Range,
201 Rofs,
202 Spipe,
203 Srch,
204 Stale,
205 Timedout,
206 Txtbsy,
207 Xdev,
208 Notcapable
209);
210convert_enum!(
211 types::Clockid,
212 snapshot1_types::Clockid,
213 Realtime,
214 Monotonic,
215 ProcessCputimeId,
216 ThreadCputimeId
217);
218
219convert_enum!(
220 types::Advice,
221 snapshot1_types::Advice,
222 Normal,
223 Sequential,
224 Random,
225 Willneed,
226 Dontneed,
227 Noreuse
228);
229convert_enum!(
230 snapshot1_types::Filetype,
231 types::Filetype,
232 Directory,
233 BlockDevice,
234 CharacterDevice,
235 RegularFile,
236 SocketDgram,
237 SocketStream,
238 SymbolicLink,
239 Unknown
240);
241convert_enum!(types::Whence, snapshot1_types::Whence, Cur, End, Set);
242
243impl From<snapshot1_types::Prestat> for types::Prestat {
246 fn from(p: snapshot1_types::Prestat) -> types::Prestat {
247 match p {
248 snapshot1_types::Prestat::Dir(d) => types::Prestat::Dir(d.into()),
249 }
250 }
251}
252
253macro_rules! convert_struct {
256 ($from:ty, $to:path, $($field:ident),+) => {
257 impl From<$from> for $to {
258 fn from(e: $from) -> $to {
259 $to {
260 $( $field: e.$field.into(), )+
261 }
262 }
263 }
264 }
265}
266
267convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);
268convert_struct!(
269 snapshot1_types::Fdstat,
270 types::Fdstat,
271 fs_filetype,
272 fs_rights_base,
273 fs_rights_inheriting,
274 fs_flags
275);
276
277impl From<snapshot1_types::Filestat> for types::Filestat {
281 fn from(f: snapshot1_types::Filestat) -> types::Filestat {
282 types::Filestat {
283 dev: f.dev,
284 ino: f.ino,
285 filetype: f.filetype.into(),
286 nlink: f.nlink.try_into().unwrap_or(u32::MAX),
287 size: f.size,
288 atim: f.atim,
289 mtim: f.mtim,
290 ctim: f.ctim,
291 }
292 }
293}
294
295macro_rules! convert_flags {
297 ($from:ty, $to:ty, $($flag:ident),+) => {
298 impl From<$from> for $to {
299 fn from(f: $from) -> $to {
300 let mut out = <$to>::empty();
301 $(
302 if f.contains(<$from>::$flag) {
303 out |= <$to>::$flag;
304 }
305 )+
306 out
307 }
308 }
309 }
310}
311
312macro_rules! convert_flags_bidirectional {
314 ($from:ty, $to:ty, $($flag:tt)*) => {
315 convert_flags!($from, $to, $($flag)*);
316 convert_flags!($to, $from, $($flag)*);
317 }
318}
319
320convert_flags_bidirectional!(
321 snapshot1_types::Fdflags,
322 types::Fdflags,
323 APPEND,
324 DSYNC,
325 NONBLOCK,
326 RSYNC,
327 SYNC
328);
329convert_flags!(
330 types::Lookupflags,
331 snapshot1_types::Lookupflags,
332 SYMLINK_FOLLOW
333);
334convert_flags!(
335 types::Fstflags,
336 snapshot1_types::Fstflags,
337 ATIM,
338 ATIM_NOW,
339 MTIM,
340 MTIM_NOW
341);
342convert_flags!(
343 types::Oflags,
344 snapshot1_types::Oflags,
345 CREAT,
346 DIRECTORY,
347 EXCL,
348 TRUNC
349);
350convert_flags_bidirectional!(
351 types::Rights,
352 snapshot1_types::Rights,
353 FD_DATASYNC,
354 FD_READ,
355 FD_SEEK,
356 FD_FDSTAT_SET_FLAGS,
357 FD_SYNC,
358 FD_TELL,
359 FD_WRITE,
360 FD_ADVISE,
361 FD_ALLOCATE,
362 PATH_CREATE_DIRECTORY,
363 PATH_CREATE_FILE,
364 PATH_LINK_SOURCE,
365 PATH_LINK_TARGET,
366 PATH_OPEN,
367 FD_READDIR,
368 PATH_READLINK,
369 PATH_RENAME_SOURCE,
370 PATH_RENAME_TARGET,
371 PATH_FILESTAT_GET,
372 PATH_FILESTAT_SET_SIZE,
373 PATH_FILESTAT_SET_TIMES,
374 FD_FILESTAT_GET,
375 FD_FILESTAT_SET_SIZE,
376 FD_FILESTAT_SET_TIMES,
377 PATH_SYMLINK,
378 PATH_REMOVE_DIRECTORY,
379 PATH_UNLINK_FILE,
380 POLL_FD_READWRITE,
381 SOCK_SHUTDOWN
382);
383
384impl wasi_unstable::WasiUnstable for WasiCtx {
387 async fn args_get(
388 &mut self,
389 memory: &mut GuestMemory<'_>,
390 argv: GuestPtr<GuestPtr<u8>>,
391 argv_buf: GuestPtr<u8>,
392 ) -> Result<(), Error> {
393 Snapshot1::args_get(self, memory, argv, argv_buf).await?;
394 Ok(())
395 }
396
397 async fn args_sizes_get(
398 &mut self,
399 memory: &mut GuestMemory<'_>,
400 ) -> Result<(types::Size, types::Size), Error> {
401 let s = Snapshot1::args_sizes_get(self, memory).await?;
402 Ok(s)
403 }
404
405 async fn environ_get(
406 &mut self,
407 memory: &mut GuestMemory<'_>,
408 environ: GuestPtr<GuestPtr<u8>>,
409 environ_buf: GuestPtr<u8>,
410 ) -> Result<(), Error> {
411 Snapshot1::environ_get(self, memory, environ, environ_buf).await?;
412 Ok(())
413 }
414
415 async fn environ_sizes_get(
416 &mut self,
417 memory: &mut GuestMemory<'_>,
418 ) -> Result<(types::Size, types::Size), Error> {
419 let s = Snapshot1::environ_sizes_get(self, memory).await?;
420 Ok(s)
421 }
422
423 async fn clock_res_get(
424 &mut self,
425 memory: &mut GuestMemory<'_>,
426 id: types::Clockid,
427 ) -> Result<types::Timestamp, Error> {
428 let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;
429 Ok(t)
430 }
431
432 async fn clock_time_get(
433 &mut self,
434 memory: &mut GuestMemory<'_>,
435 id: types::Clockid,
436 precision: types::Timestamp,
437 ) -> Result<types::Timestamp, Error> {
438 let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;
439 Ok(t)
440 }
441
442 async fn fd_advise(
443 &mut self,
444 memory: &mut GuestMemory<'_>,
445 fd: types::Fd,
446 offset: types::Filesize,
447 len: types::Filesize,
448 advice: types::Advice,
449 ) -> Result<(), Error> {
450 Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
451 Ok(())
452 }
453
454 async fn fd_allocate(
455 &mut self,
456 memory: &mut GuestMemory<'_>,
457 fd: types::Fd,
458 offset: types::Filesize,
459 len: types::Filesize,
460 ) -> Result<(), Error> {
461 Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;
462 Ok(())
463 }
464
465 async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
466 Snapshot1::fd_close(self, memory, fd.into()).await?;
467 Ok(())
468 }
469
470 async fn fd_datasync(
471 &mut self,
472 memory: &mut GuestMemory<'_>,
473 fd: types::Fd,
474 ) -> Result<(), Error> {
475 Snapshot1::fd_datasync(self, memory, fd.into()).await?;
476 Ok(())
477 }
478
479 async fn fd_fdstat_get(
480 &mut self,
481 memory: &mut GuestMemory<'_>,
482 fd: types::Fd,
483 ) -> Result<types::Fdstat, Error> {
484 Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
485 .await?
486 .into())
487 }
488
489 async fn fd_fdstat_set_flags(
490 &mut self,
491 memory: &mut GuestMemory<'_>,
492 fd: types::Fd,
493 flags: types::Fdflags,
494 ) -> Result<(), Error> {
495 Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;
496 Ok(())
497 }
498
499 async fn fd_fdstat_set_rights(
500 &mut self,
501 memory: &mut GuestMemory<'_>,
502 fd: types::Fd,
503 fs_rights_base: types::Rights,
504 fs_rights_inheriting: types::Rights,
505 ) -> Result<(), Error> {
506 Snapshot1::fd_fdstat_set_rights(
507 self,
508 memory,
509 fd.into(),
510 fs_rights_base.into(),
511 fs_rights_inheriting.into(),
512 )
513 .await?;
514 Ok(())
515 }
516
517 async fn fd_filestat_get(
518 &mut self,
519 memory: &mut GuestMemory<'_>,
520 fd: types::Fd,
521 ) -> Result<types::Filestat, Error> {
522 Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
523 .await?
524 .into())
525 }
526
527 async fn fd_filestat_set_size(
528 &mut self,
529 memory: &mut GuestMemory<'_>,
530 fd: types::Fd,
531 size: types::Filesize,
532 ) -> Result<(), Error> {
533 Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
534 Ok(())
535 }
536
537 async fn fd_filestat_set_times(
538 &mut self,
539 memory: &mut GuestMemory<'_>,
540 fd: types::Fd,
541 atim: types::Timestamp,
542 mtim: types::Timestamp,
543 fst_flags: types::Fstflags,
544 ) -> Result<(), Error> {
545 Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
546 .await?;
547 Ok(())
548 }
549
550 async fn fd_read(
556 &mut self,
557 memory: &mut GuestMemory<'_>,
558 fd: types::Fd,
559 iovs: types::IovecArray,
560 ) -> Result<types::Size, Error> {
561 Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)
562 }
563
564 async fn fd_pread(
565 &mut self,
566 memory: &mut GuestMemory<'_>,
567 fd: types::Fd,
568 iovs: types::IovecArray,
569 offset: types::Filesize,
570 ) -> Result<types::Size, Error> {
571 Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)
572 }
573
574 async fn fd_write(
575 &mut self,
576 memory: &mut GuestMemory<'_>,
577 fd: types::Fd,
578 ciovs: types::CiovecArray,
579 ) -> Result<types::Size, Error> {
580 Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)
581 }
582
583 async fn fd_pwrite(
584 &mut self,
585 memory: &mut GuestMemory<'_>,
586 fd: types::Fd,
587 ciovs: types::CiovecArray,
588 offset: types::Filesize,
589 ) -> Result<types::Size, Error> {
590 Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)
591 }
592
593 async fn fd_prestat_get(
594 &mut self,
595 memory: &mut GuestMemory<'_>,
596 fd: types::Fd,
597 ) -> Result<types::Prestat, Error> {
598 Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())
599 .await?
600 .into())
601 }
602
603 async fn fd_prestat_dir_name(
604 &mut self,
605 memory: &mut GuestMemory<'_>,
606 fd: types::Fd,
607 path: GuestPtr<u8>,
608 path_max_len: types::Size,
609 ) -> Result<(), Error> {
610 Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;
611 Ok(())
612 }
613
614 async fn fd_renumber(
615 &mut self,
616 memory: &mut GuestMemory<'_>,
617 from: types::Fd,
618 to: types::Fd,
619 ) -> Result<(), Error> {
620 Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;
621 Ok(())
622 }
623
624 async fn fd_seek(
625 &mut self,
626 memory: &mut GuestMemory<'_>,
627 fd: types::Fd,
628 offset: types::Filedelta,
629 whence: types::Whence,
630 ) -> Result<types::Filesize, Error> {
631 Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
632 }
633
634 async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
635 Snapshot1::fd_sync(self, memory, fd.into()).await?;
636 Ok(())
637 }
638
639 async fn fd_tell(
640 &mut self,
641 memory: &mut GuestMemory<'_>,
642 fd: types::Fd,
643 ) -> Result<types::Filesize, Error> {
644 Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)
645 }
646
647 async fn fd_readdir(
648 &mut self,
649 memory: &mut GuestMemory<'_>,
650 fd: types::Fd,
651 buf: GuestPtr<u8>,
652 buf_len: types::Size,
653 cookie: types::Dircookie,
654 ) -> Result<types::Size, Error> {
655 Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
656 }
657
658 async fn path_create_directory(
659 &mut self,
660 memory: &mut GuestMemory<'_>,
661 dirfd: types::Fd,
662 path: GuestPtr<str>,
663 ) -> Result<(), Error> {
664 Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
665 Ok(())
666 }
667
668 async fn path_filestat_get(
669 &mut self,
670 memory: &mut GuestMemory<'_>,
671 dirfd: types::Fd,
672 flags: types::Lookupflags,
673 path: GuestPtr<str>,
674 ) -> Result<types::Filestat, Error> {
675 Ok(
676 Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
677 .await?
678 .into(),
679 )
680 }
681
682 async fn path_filestat_set_times(
683 &mut self,
684 memory: &mut GuestMemory<'_>,
685 dirfd: types::Fd,
686 flags: types::Lookupflags,
687 path: GuestPtr<str>,
688 atim: types::Timestamp,
689 mtim: types::Timestamp,
690 fst_flags: types::Fstflags,
691 ) -> Result<(), Error> {
692 Snapshot1::path_filestat_set_times(
693 self,
694 memory,
695 dirfd.into(),
696 flags.into(),
697 path,
698 atim,
699 mtim,
700 fst_flags.into(),
701 )
702 .await?;
703 Ok(())
704 }
705
706 async fn path_link(
707 &mut self,
708 memory: &mut GuestMemory<'_>,
709 src_fd: types::Fd,
710 src_flags: types::Lookupflags,
711 src_path: GuestPtr<str>,
712 target_fd: types::Fd,
713 target_path: GuestPtr<str>,
714 ) -> Result<(), Error> {
715 Snapshot1::path_link(
716 self,
717 memory,
718 src_fd.into(),
719 src_flags.into(),
720 src_path,
721 target_fd.into(),
722 target_path,
723 )
724 .await?;
725 Ok(())
726 }
727
728 async fn path_open(
729 &mut self,
730 memory: &mut GuestMemory<'_>,
731 dirfd: types::Fd,
732 dirflags: types::Lookupflags,
733 path: GuestPtr<str>,
734 oflags: types::Oflags,
735 fs_rights_base: types::Rights,
736 fs_rights_inheriting: types::Rights,
737 fdflags: types::Fdflags,
738 ) -> Result<types::Fd, Error> {
739 Ok(Snapshot1::path_open(
740 self,
741 memory,
742 dirfd.into(),
743 dirflags.into(),
744 path,
745 oflags.into(),
746 fs_rights_base.into(),
747 fs_rights_inheriting.into(),
748 fdflags.into(),
749 )
750 .await?
751 .into())
752 }
753
754 async fn path_readlink(
755 &mut self,
756 memory: &mut GuestMemory<'_>,
757 dirfd: types::Fd,
758 path: GuestPtr<str>,
759 buf: GuestPtr<u8>,
760 buf_len: types::Size,
761 ) -> Result<types::Size, Error> {
762 Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
763 }
764
765 async fn path_remove_directory(
766 &mut self,
767 memory: &mut GuestMemory<'_>,
768 dirfd: types::Fd,
769 path: GuestPtr<str>,
770 ) -> Result<(), Error> {
771 Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
772 Ok(())
773 }
774
775 async fn path_rename(
776 &mut self,
777 memory: &mut GuestMemory<'_>,
778 src_fd: types::Fd,
779 src_path: GuestPtr<str>,
780 dest_fd: types::Fd,
781 dest_path: GuestPtr<str>,
782 ) -> Result<(), Error> {
783 Snapshot1::path_rename(
784 self,
785 memory,
786 src_fd.into(),
787 src_path,
788 dest_fd.into(),
789 dest_path,
790 )
791 .await?;
792 Ok(())
793 }
794
795 async fn path_symlink(
796 &mut self,
797 memory: &mut GuestMemory<'_>,
798 src_path: GuestPtr<str>,
799 dirfd: types::Fd,
800 dest_path: GuestPtr<str>,
801 ) -> Result<(), Error> {
802 Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
803 Ok(())
804 }
805
806 async fn path_unlink_file(
807 &mut self,
808 memory: &mut GuestMemory<'_>,
809 dirfd: types::Fd,
810 path: GuestPtr<str>,
811 ) -> Result<(), Error> {
812 Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
813 Ok(())
814 }
815
816 async fn poll_oneoff(
824 &mut self,
825 memory: &mut GuestMemory<'_>,
826 subs: GuestPtr<types::Subscription>,
827 events: GuestPtr<types::Event>,
828 nsubscriptions: types::Size,
829 ) -> Result<types::Size, Error> {
830 if nsubscriptions == 0 {
831 return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
832 }
833
834 if nsubscriptions == 1 {
839 let sub = memory.read(subs)?;
840 if let types::SubscriptionU::Clock(clocksub) = sub.u {
841 if !clocksub
842 .flags
843 .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
844 {
845 self.sched
846 .sleep(Duration::from_nanos(clocksub.timeout))
847 .await?;
848 memory.write(
849 events,
850 types::Event {
851 userdata: sub.userdata,
852 error: types::Errno::Success,
853 type_: types::Eventtype::Clock,
854 fd_readwrite: fd_readwrite_empty(),
855 },
856 )?;
857 return Ok(1);
858 }
859 }
860 }
861
862 let table = &self.table;
863 let mut sub_fds: HashSet<types::Fd> = HashSet::new();
864 let mut reads: Vec<(u32, Userdata)> = Vec::new();
866 let mut writes: Vec<(u32, Userdata)> = Vec::new();
867 let mut poll = Poll::new();
868
869 let subs = subs.as_array(nsubscriptions);
870 for sub_elem in subs.iter() {
871 let sub_ptr = sub_elem?;
872 let sub = memory.read(sub_ptr)?;
873 match sub.u {
874 types::SubscriptionU::Clock(clocksub) => match clocksub.id {
875 types::Clockid::Monotonic => {
876 let clock = self.clocks.monotonic()?;
877 let precision = Duration::from_nanos(clocksub.precision);
878 let duration = Duration::from_nanos(clocksub.timeout);
879 let start = if clocksub
880 .flags
881 .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
882 {
883 clock.creation_time
884 } else {
885 clock.abs_clock.now(precision)
886 };
887 let deadline = start
888 .checked_add(duration)
889 .ok_or_else(|| Error::overflow().context("deadline"))?;
890 poll.subscribe_monotonic_clock(
891 &*clock.abs_clock,
892 deadline,
893 precision,
894 sub.userdata.into(),
895 )
896 }
897 _ => Err(Error::invalid_argument()
898 .context("timer subscriptions only support monotonic timer"))?,
899 },
900 types::SubscriptionU::FdRead(readsub) => {
901 let fd = readsub.file_descriptor;
902 if sub_fds.contains(&fd) {
903 return Err(Error::invalid_argument()
904 .context("Fd can be subscribed to at most once per poll"));
905 } else {
906 sub_fds.insert(fd);
907 }
908 table.get_file(u32::from(fd))?;
909 reads.push((u32::from(fd), sub.userdata.into()));
910 }
911 types::SubscriptionU::FdWrite(writesub) => {
912 let fd = writesub.file_descriptor;
913 if sub_fds.contains(&fd) {
914 return Err(Error::invalid_argument()
915 .context("Fd can be subscribed to at most once per poll"));
916 } else {
917 sub_fds.insert(fd);
918 }
919 table.get_file(u32::from(fd))?;
920 writes.push((u32::from(fd), sub.userdata.into()));
921 }
922 }
923 }
924
925 self.sched.poll_oneoff(&mut poll).await?;
926
927 let results = poll.results();
928 let num_results = results.len();
929 assert!(
930 num_results <= nsubscriptions as usize,
931 "results exceeds subscriptions"
932 );
933 let events = events.as_array(
934 num_results
935 .try_into()
936 .expect("not greater than nsubscriptions"),
937 );
938 for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {
939 let event_ptr = event_elem?;
940 let userdata: types::Userdata = userdata.into();
941 memory.write(
942 event_ptr,
943 match result {
944 SubscriptionResult::Read(r) => {
945 let type_ = types::Eventtype::FdRead;
946 match r {
947 Ok((nbytes, flags)) => types::Event {
948 userdata,
949 error: types::Errno::Success,
950 type_,
951 fd_readwrite: types::EventFdReadwrite {
952 nbytes,
953 flags: types::Eventrwflags::from(&flags),
954 },
955 },
956 Err(e) => types::Event {
957 userdata,
958 error: types::Errno::from(e.downcast().map_err(Error::trap)?),
959 type_,
960 fd_readwrite: fd_readwrite_empty(),
961 },
962 }
963 }
964 SubscriptionResult::Write(r) => {
965 let type_ = types::Eventtype::FdWrite;
966 match r {
967 Ok((nbytes, flags)) => types::Event {
968 userdata,
969 error: types::Errno::Success,
970 type_,
971 fd_readwrite: types::EventFdReadwrite {
972 nbytes,
973 flags: types::Eventrwflags::from(&flags),
974 },
975 },
976 Err(e) => types::Event {
977 userdata,
978 error: types::Errno::from(e.downcast().map_err(Error::trap)?),
979 type_,
980 fd_readwrite: fd_readwrite_empty(),
981 },
982 }
983 }
984 SubscriptionResult::MonotonicClock(r) => {
985 let type_ = types::Eventtype::Clock;
986 types::Event {
987 userdata,
988 error: match r {
989 Ok(()) => types::Errno::Success,
990 Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),
991 },
992 type_,
993 fd_readwrite: fd_readwrite_empty(),
994 }
995 }
996 },
997 )?;
998 }
999
1000 Ok(num_results.try_into().expect("results fit into memory"))
1001 }
1002
1003 async fn proc_exit(
1004 &mut self,
1005 memory: &mut GuestMemory<'_>,
1006 status: types::Exitcode,
1007 ) -> anyhow::Error {
1008 Snapshot1::proc_exit(self, memory, status).await
1009 }
1010
1011 async fn proc_raise(
1012 &mut self,
1013 _memory: &mut GuestMemory<'_>,
1014 _sig: types::Signal,
1015 ) -> Result<(), Error> {
1016 Err(Error::trap(anyhow::Error::msg("proc_raise unsupported")))
1017 }
1018
1019 async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
1020 Snapshot1::sched_yield(self, memory).await?;
1021 Ok(())
1022 }
1023
1024 async fn random_get(
1025 &mut self,
1026 memory: &mut GuestMemory<'_>,
1027 buf: GuestPtr<u8>,
1028 buf_len: types::Size,
1029 ) -> Result<(), Error> {
1030 Snapshot1::random_get(self, memory, buf, buf_len).await?;
1031 Ok(())
1032 }
1033
1034 async 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> {
1041 Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))
1042 }
1043
1044 async 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> {
1051 Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))
1052 }
1053
1054 async fn sock_shutdown(
1055 &mut self,
1056 _memory: &mut GuestMemory<'_>,
1057 _fd: types::Fd,
1058 _how: types::Sdflags,
1059 ) -> Result<(), Error> {
1060 Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))
1061 }
1062}
1063
1064impl From<&RwEventFlags> for types::Eventrwflags {
1065 fn from(flags: &RwEventFlags) -> types::Eventrwflags {
1066 let mut out = types::Eventrwflags::empty();
1067 if flags.contains(RwEventFlags::HANGUP) {
1068 out = out | types::Eventrwflags::FD_READWRITE_HANGUP;
1069 }
1070 out
1071 }
1072}
1073
1074fn fd_readwrite_empty() -> types::EventFdReadwrite {
1075 types::EventFdReadwrite {
1076 nbytes: 0,
1077 flags: types::Eventrwflags::empty(),
1078 }
1079}