1use crate::file::TableFileExt;
2use crate::sched::{
3 subscription::{RwEventFlags, SubscriptionResult},
4 Poll, Userdata,
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: ["$CARGO_MANIFEST_DIR/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.into(),
284 ino: f.ino.into(),
285 filetype: f.filetype.into(),
286 nlink: f.nlink.try_into().unwrap_or(u32::MAX),
287 size: f.size.into(),
288 atim: f.atim.into(),
289 mtim: f.mtim.into(),
290 ctim: f.ctim.into(),
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
384#[wiggle::async_trait]
387impl wasi_unstable::WasiUnstable for WasiCtx {
388 async fn args_get(
389 &mut self,
390 memory: &mut GuestMemory<'_>,
391 argv: GuestPtr<GuestPtr<u8>>,
392 argv_buf: GuestPtr<u8>,
393 ) -> Result<(), Error> {
394 Snapshot1::args_get(self, memory, argv, argv_buf).await?;
395 Ok(())
396 }
397
398 async fn args_sizes_get(
399 &mut self,
400 memory: &mut GuestMemory<'_>,
401 ) -> Result<(types::Size, types::Size), Error> {
402 let s = Snapshot1::args_sizes_get(self, memory).await?;
403 Ok(s)
404 }
405
406 async fn environ_get(
407 &mut self,
408 memory: &mut GuestMemory<'_>,
409 environ: GuestPtr<GuestPtr<u8>>,
410 environ_buf: GuestPtr<u8>,
411 ) -> Result<(), Error> {
412 Snapshot1::environ_get(self, memory, environ, environ_buf).await?;
413 Ok(())
414 }
415
416 async fn environ_sizes_get(
417 &mut self,
418 memory: &mut GuestMemory<'_>,
419 ) -> Result<(types::Size, types::Size), Error> {
420 let s = Snapshot1::environ_sizes_get(self, memory).await?;
421 Ok(s)
422 }
423
424 async fn clock_res_get(
425 &mut self,
426 memory: &mut GuestMemory<'_>,
427 id: types::Clockid,
428 ) -> Result<types::Timestamp, Error> {
429 let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;
430 Ok(t)
431 }
432
433 async fn clock_time_get(
434 &mut self,
435 memory: &mut GuestMemory<'_>,
436 id: types::Clockid,
437 precision: types::Timestamp,
438 ) -> Result<types::Timestamp, Error> {
439 let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;
440 Ok(t)
441 }
442
443 async fn fd_advise(
444 &mut self,
445 memory: &mut GuestMemory<'_>,
446 fd: types::Fd,
447 offset: types::Filesize,
448 len: types::Filesize,
449 advice: types::Advice,
450 ) -> Result<(), Error> {
451 Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
452 Ok(())
453 }
454
455 async fn fd_allocate(
456 &mut self,
457 memory: &mut GuestMemory<'_>,
458 fd: types::Fd,
459 offset: types::Filesize,
460 len: types::Filesize,
461 ) -> Result<(), Error> {
462 Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;
463 Ok(())
464 }
465
466 async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
467 Snapshot1::fd_close(self, memory, fd.into()).await?;
468 Ok(())
469 }
470
471 async fn fd_datasync(
472 &mut self,
473 memory: &mut GuestMemory<'_>,
474 fd: types::Fd,
475 ) -> Result<(), Error> {
476 Snapshot1::fd_datasync(self, memory, fd.into()).await?;
477 Ok(())
478 }
479
480 async fn fd_fdstat_get(
481 &mut self,
482 memory: &mut GuestMemory<'_>,
483 fd: types::Fd,
484 ) -> Result<types::Fdstat, Error> {
485 Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
486 .await?
487 .into())
488 }
489
490 async fn fd_fdstat_set_flags(
491 &mut self,
492 memory: &mut GuestMemory<'_>,
493 fd: types::Fd,
494 flags: types::Fdflags,
495 ) -> Result<(), Error> {
496 Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;
497 Ok(())
498 }
499
500 async fn fd_fdstat_set_rights(
501 &mut self,
502 memory: &mut GuestMemory<'_>,
503 fd: types::Fd,
504 fs_rights_base: types::Rights,
505 fs_rights_inheriting: types::Rights,
506 ) -> Result<(), Error> {
507 Snapshot1::fd_fdstat_set_rights(
508 self,
509 memory,
510 fd.into(),
511 fs_rights_base.into(),
512 fs_rights_inheriting.into(),
513 )
514 .await?;
515 Ok(())
516 }
517
518 async fn fd_filestat_get(
519 &mut self,
520 memory: &mut GuestMemory<'_>,
521 fd: types::Fd,
522 ) -> Result<types::Filestat, Error> {
523 Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
524 .await?
525 .into())
526 }
527
528 async fn fd_filestat_set_size(
529 &mut self,
530 memory: &mut GuestMemory<'_>,
531 fd: types::Fd,
532 size: types::Filesize,
533 ) -> Result<(), Error> {
534 Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
535 Ok(())
536 }
537
538 async fn fd_filestat_set_times(
539 &mut self,
540 memory: &mut GuestMemory<'_>,
541 fd: types::Fd,
542 atim: types::Timestamp,
543 mtim: types::Timestamp,
544 fst_flags: types::Fstflags,
545 ) -> Result<(), Error> {
546 Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
547 .await?;
548 Ok(())
549 }
550
551 async fn fd_read(
557 &mut self,
558 memory: &mut GuestMemory<'_>,
559 fd: types::Fd,
560 iovs: types::IovecArray,
561 ) -> Result<types::Size, Error> {
562 Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)
563 }
564
565 async fn fd_pread(
566 &mut self,
567 memory: &mut GuestMemory<'_>,
568 fd: types::Fd,
569 iovs: types::IovecArray,
570 offset: types::Filesize,
571 ) -> Result<types::Size, Error> {
572 Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)
573 }
574
575 async fn fd_write(
576 &mut self,
577 memory: &mut GuestMemory<'_>,
578 fd: types::Fd,
579 ciovs: types::CiovecArray,
580 ) -> Result<types::Size, Error> {
581 Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)
582 }
583
584 async fn fd_pwrite(
585 &mut self,
586 memory: &mut GuestMemory<'_>,
587 fd: types::Fd,
588 ciovs: types::CiovecArray,
589 offset: types::Filesize,
590 ) -> Result<types::Size, Error> {
591 Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)
592 }
593
594 async fn fd_prestat_get(
595 &mut self,
596 memory: &mut GuestMemory<'_>,
597 fd: types::Fd,
598 ) -> Result<types::Prestat, Error> {
599 Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())
600 .await?
601 .into())
602 }
603
604 async fn fd_prestat_dir_name(
605 &mut self,
606 memory: &mut GuestMemory<'_>,
607 fd: types::Fd,
608 path: GuestPtr<u8>,
609 path_max_len: types::Size,
610 ) -> Result<(), Error> {
611 Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;
612 Ok(())
613 }
614
615 async fn fd_renumber(
616 &mut self,
617 memory: &mut GuestMemory<'_>,
618 from: types::Fd,
619 to: types::Fd,
620 ) -> Result<(), Error> {
621 Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;
622 Ok(())
623 }
624
625 async fn fd_seek(
626 &mut self,
627 memory: &mut GuestMemory<'_>,
628 fd: types::Fd,
629 offset: types::Filedelta,
630 whence: types::Whence,
631 ) -> Result<types::Filesize, Error> {
632 Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
633 }
634
635 async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
636 Snapshot1::fd_sync(self, memory, fd.into()).await?;
637 Ok(())
638 }
639
640 async fn fd_tell(
641 &mut self,
642 memory: &mut GuestMemory<'_>,
643 fd: types::Fd,
644 ) -> Result<types::Filesize, Error> {
645 Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)
646 }
647
648 async fn fd_readdir(
649 &mut self,
650 memory: &mut GuestMemory<'_>,
651 fd: types::Fd,
652 buf: GuestPtr<u8>,
653 buf_len: types::Size,
654 cookie: types::Dircookie,
655 ) -> Result<types::Size, Error> {
656 Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
657 }
658
659 async fn path_create_directory(
660 &mut self,
661 memory: &mut GuestMemory<'_>,
662 dirfd: types::Fd,
663 path: GuestPtr<str>,
664 ) -> Result<(), Error> {
665 Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
666 Ok(())
667 }
668
669 async fn path_filestat_get(
670 &mut self,
671 memory: &mut GuestMemory<'_>,
672 dirfd: types::Fd,
673 flags: types::Lookupflags,
674 path: GuestPtr<str>,
675 ) -> Result<types::Filestat, Error> {
676 Ok(
677 Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
678 .await?
679 .into(),
680 )
681 }
682
683 async fn path_filestat_set_times(
684 &mut self,
685 memory: &mut GuestMemory<'_>,
686 dirfd: types::Fd,
687 flags: types::Lookupflags,
688 path: GuestPtr<str>,
689 atim: types::Timestamp,
690 mtim: types::Timestamp,
691 fst_flags: types::Fstflags,
692 ) -> Result<(), Error> {
693 Snapshot1::path_filestat_set_times(
694 self,
695 memory,
696 dirfd.into(),
697 flags.into(),
698 path,
699 atim,
700 mtim,
701 fst_flags.into(),
702 )
703 .await?;
704 Ok(())
705 }
706
707 async fn path_link(
708 &mut self,
709 memory: &mut GuestMemory<'_>,
710 src_fd: types::Fd,
711 src_flags: types::Lookupflags,
712 src_path: GuestPtr<str>,
713 target_fd: types::Fd,
714 target_path: GuestPtr<str>,
715 ) -> Result<(), Error> {
716 Snapshot1::path_link(
717 self,
718 memory,
719 src_fd.into(),
720 src_flags.into(),
721 src_path,
722 target_fd.into(),
723 target_path,
724 )
725 .await?;
726 Ok(())
727 }
728
729 async fn path_open(
730 &mut self,
731 memory: &mut GuestMemory<'_>,
732 dirfd: types::Fd,
733 dirflags: types::Lookupflags,
734 path: GuestPtr<str>,
735 oflags: types::Oflags,
736 fs_rights_base: types::Rights,
737 fs_rights_inheriting: types::Rights,
738 fdflags: types::Fdflags,
739 ) -> Result<types::Fd, Error> {
740 Ok(Snapshot1::path_open(
741 self,
742 memory,
743 dirfd.into(),
744 dirflags.into(),
745 path,
746 oflags.into(),
747 fs_rights_base.into(),
748 fs_rights_inheriting.into(),
749 fdflags.into(),
750 )
751 .await?
752 .into())
753 }
754
755 async fn path_readlink(
756 &mut self,
757 memory: &mut GuestMemory<'_>,
758 dirfd: types::Fd,
759 path: GuestPtr<str>,
760 buf: GuestPtr<u8>,
761 buf_len: types::Size,
762 ) -> Result<types::Size, Error> {
763 Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
764 }
765
766 async fn path_remove_directory(
767 &mut self,
768 memory: &mut GuestMemory<'_>,
769 dirfd: types::Fd,
770 path: GuestPtr<str>,
771 ) -> Result<(), Error> {
772 Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
773 Ok(())
774 }
775
776 async fn path_rename(
777 &mut self,
778 memory: &mut GuestMemory<'_>,
779 src_fd: types::Fd,
780 src_path: GuestPtr<str>,
781 dest_fd: types::Fd,
782 dest_path: GuestPtr<str>,
783 ) -> Result<(), Error> {
784 Snapshot1::path_rename(
785 self,
786 memory,
787 src_fd.into(),
788 src_path,
789 dest_fd.into(),
790 dest_path,
791 )
792 .await?;
793 Ok(())
794 }
795
796 async fn path_symlink(
797 &mut self,
798 memory: &mut GuestMemory<'_>,
799 src_path: GuestPtr<str>,
800 dirfd: types::Fd,
801 dest_path: GuestPtr<str>,
802 ) -> Result<(), Error> {
803 Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
804 Ok(())
805 }
806
807 async fn path_unlink_file(
808 &mut self,
809 memory: &mut GuestMemory<'_>,
810 dirfd: types::Fd,
811 path: GuestPtr<str>,
812 ) -> Result<(), Error> {
813 Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
814 Ok(())
815 }
816
817 async fn poll_oneoff(
825 &mut self,
826 memory: &mut GuestMemory<'_>,
827 subs: GuestPtr<types::Subscription>,
828 events: GuestPtr<types::Event>,
829 nsubscriptions: types::Size,
830 ) -> Result<types::Size, Error> {
831 if nsubscriptions == 0 {
832 return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
833 }
834
835 if nsubscriptions == 1 {
840 let sub = memory.read(subs)?;
841 if let types::SubscriptionU::Clock(clocksub) = sub.u {
842 if !clocksub
843 .flags
844 .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
845 {
846 self.sched
847 .sleep(Duration::from_nanos(clocksub.timeout))
848 .await?;
849 memory.write(
850 events,
851 types::Event {
852 userdata: sub.userdata,
853 error: types::Errno::Success,
854 type_: types::Eventtype::Clock,
855 fd_readwrite: fd_readwrite_empty(),
856 },
857 )?;
858 return Ok(1);
859 }
860 }
861 }
862
863 let table = &self.table;
864 let mut sub_fds: HashSet<types::Fd> = HashSet::new();
865 let mut reads: Vec<(u32, Userdata)> = Vec::new();
867 let mut writes: Vec<(u32, Userdata)> = Vec::new();
868 let mut poll = Poll::new();
869
870 let subs = subs.as_array(nsubscriptions);
871 for sub_elem in subs.iter() {
872 let sub_ptr = sub_elem?;
873 let sub = memory.read(sub_ptr)?;
874 match sub.u {
875 types::SubscriptionU::Clock(clocksub) => match clocksub.id {
876 types::Clockid::Monotonic => {
877 let clock = self.clocks.monotonic()?;
878 let precision = Duration::from_nanos(clocksub.precision);
879 let duration = Duration::from_nanos(clocksub.timeout);
880 let start = if clocksub
881 .flags
882 .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
883 {
884 clock.creation_time
885 } else {
886 clock.abs_clock.now(precision)
887 };
888 let deadline = start
889 .checked_add(duration)
890 .ok_or_else(|| Error::overflow().context("deadline"))?;
891 poll.subscribe_monotonic_clock(
892 &*clock.abs_clock,
893 deadline,
894 precision,
895 sub.userdata.into(),
896 )
897 }
898 _ => Err(Error::invalid_argument()
899 .context("timer subscriptions only support monotonic timer"))?,
900 },
901 types::SubscriptionU::FdRead(readsub) => {
902 let fd = readsub.file_descriptor;
903 if sub_fds.contains(&fd) {
904 return Err(Error::invalid_argument()
905 .context("Fd can be subscribed to at most once per poll"));
906 } else {
907 sub_fds.insert(fd);
908 }
909 table.get_file(u32::from(fd))?;
910 reads.push((u32::from(fd), sub.userdata.into()));
911 }
912 types::SubscriptionU::FdWrite(writesub) => {
913 let fd = writesub.file_descriptor;
914 if sub_fds.contains(&fd) {
915 return Err(Error::invalid_argument()
916 .context("Fd can be subscribed to at most once per poll"));
917 } else {
918 sub_fds.insert(fd);
919 }
920 table.get_file(u32::from(fd))?;
921 writes.push((u32::from(fd), sub.userdata.into()));
922 }
923 }
924 }
925
926 self.sched.poll_oneoff(&mut poll).await?;
927
928 let results = poll.results();
929 let num_results = results.len();
930 assert!(
931 num_results <= nsubscriptions as usize,
932 "results exceeds subscriptions"
933 );
934 let events = events.as_array(
935 num_results
936 .try_into()
937 .expect("not greater than nsubscriptions"),
938 );
939 for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {
940 let event_ptr = event_elem?;
941 let userdata: types::Userdata = userdata.into();
942 memory.write(
943 event_ptr,
944 match result {
945 SubscriptionResult::Read(r) => {
946 let type_ = types::Eventtype::FdRead;
947 match r {
948 Ok((nbytes, flags)) => types::Event {
949 userdata,
950 error: types::Errno::Success,
951 type_,
952 fd_readwrite: types::EventFdReadwrite {
953 nbytes,
954 flags: types::Eventrwflags::from(&flags),
955 },
956 },
957 Err(e) => types::Event {
958 userdata,
959 error: types::Errno::from(e.downcast().map_err(Error::trap)?),
960 type_,
961 fd_readwrite: fd_readwrite_empty(),
962 },
963 }
964 }
965 SubscriptionResult::Write(r) => {
966 let type_ = types::Eventtype::FdWrite;
967 match r {
968 Ok((nbytes, flags)) => types::Event {
969 userdata,
970 error: types::Errno::Success,
971 type_,
972 fd_readwrite: types::EventFdReadwrite {
973 nbytes,
974 flags: types::Eventrwflags::from(&flags),
975 },
976 },
977 Err(e) => types::Event {
978 userdata,
979 error: types::Errno::from(e.downcast().map_err(Error::trap)?),
980 type_,
981 fd_readwrite: fd_readwrite_empty(),
982 },
983 }
984 }
985 SubscriptionResult::MonotonicClock(r) => {
986 let type_ = types::Eventtype::Clock;
987 types::Event {
988 userdata,
989 error: match r {
990 Ok(()) => types::Errno::Success,
991 Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),
992 },
993 type_,
994 fd_readwrite: fd_readwrite_empty(),
995 }
996 }
997 },
998 )?;
999 }
1000
1001 Ok(num_results.try_into().expect("results fit into memory"))
1002 }
1003
1004 async fn proc_exit(
1005 &mut self,
1006 memory: &mut GuestMemory<'_>,
1007 status: types::Exitcode,
1008 ) -> anyhow::Error {
1009 Snapshot1::proc_exit(self, memory, status).await
1010 }
1011
1012 async fn proc_raise(
1013 &mut self,
1014 _memory: &mut GuestMemory<'_>,
1015 _sig: types::Signal,
1016 ) -> Result<(), Error> {
1017 Err(Error::trap(anyhow::Error::msg("proc_raise unsupported")))
1018 }
1019
1020 async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
1021 Snapshot1::sched_yield(self, memory).await?;
1022 Ok(())
1023 }
1024
1025 async fn random_get(
1026 &mut self,
1027 memory: &mut GuestMemory<'_>,
1028 buf: GuestPtr<u8>,
1029 buf_len: types::Size,
1030 ) -> Result<(), Error> {
1031 Snapshot1::random_get(self, memory, buf, buf_len).await?;
1032 Ok(())
1033 }
1034
1035 async fn sock_recv(
1036 &mut self,
1037 _memory: &mut GuestMemory<'_>,
1038 _fd: types::Fd,
1039 _ri_data: types::IovecArray,
1040 _ri_flags: types::Riflags,
1041 ) -> Result<(types::Size, types::Roflags), Error> {
1042 Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))
1043 }
1044
1045 async fn sock_send(
1046 &mut self,
1047 _memory: &mut GuestMemory<'_>,
1048 _fd: types::Fd,
1049 _si_data: types::CiovecArray,
1050 _si_flags: types::Siflags,
1051 ) -> Result<types::Size, Error> {
1052 Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))
1053 }
1054
1055 async fn sock_shutdown(
1056 &mut self,
1057 _memory: &mut GuestMemory<'_>,
1058 _fd: types::Fd,
1059 _how: types::Sdflags,
1060 ) -> Result<(), Error> {
1061 Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))
1062 }
1063}
1064
1065impl From<&RwEventFlags> for types::Eventrwflags {
1066 fn from(flags: &RwEventFlags) -> types::Eventrwflags {
1067 let mut out = types::Eventrwflags::empty();
1068 if flags.contains(RwEventFlags::HANGUP) {
1069 out = out | types::Eventrwflags::FD_READWRITE_HANGUP;
1070 }
1071 out
1072 }
1073}
1074
1075fn fd_readwrite_empty() -> types::EventFdReadwrite {
1076 types::EventFdReadwrite {
1077 nbytes: 0,
1078 flags: types::Eventrwflags::empty(),
1079 }
1080}