1 #![expect(unsafe_op_in_unsafe_fn, reason = "old code, not worth updating yet")] 2 3 use std::collections::HashMap; 4 use std::mem::MaybeUninit; 5 use test_programs::preview1::{STDERR_FD, STDIN_FD, STDOUT_FD, assert_errno}; 6 7 const TIMEOUT: u64 = 200_000_000u64; // 200 milliseconds, required to satisfy slow execution in CI 8 const CLOCK_ID: wasip1::Userdata = 0x0123_45678; 9 const STDIN_ID: wasip1::Userdata = 0x8765_43210; 10 11 unsafe fn poll_oneoff_impl( 12 r#in: &[wasip1::Subscription], 13 ) -> Result<Vec<wasip1::Event>, wasip1::Errno> { 14 let mut out: Vec<wasip1::Event> = Vec::new(); 15 out.resize_with(r#in.len(), || { 16 MaybeUninit::<wasip1::Event>::zeroed().assume_init() 17 }); 18 let size = wasip1::poll_oneoff(r#in.as_ptr(), out.as_mut_ptr(), r#in.len())?; 19 out.truncate(size); 20 Ok(out) 21 } 22 23 unsafe fn test_stdin_read() { 24 let clock = wasip1::SubscriptionClock { 25 id: wasip1::CLOCKID_MONOTONIC, 26 timeout: TIMEOUT, 27 precision: 0, 28 flags: 0, 29 }; 30 let fd_readwrite = wasip1::SubscriptionFdReadwrite { 31 file_descriptor: STDIN_FD, 32 }; 33 // Either stdin can be ready for reading, or this poll can timeout. 34 let r#in = [ 35 wasip1::Subscription { 36 userdata: CLOCK_ID, 37 u: wasip1::SubscriptionU { 38 tag: wasip1::EVENTTYPE_CLOCK.raw(), 39 u: wasip1::SubscriptionUU { clock }, 40 }, 41 }, 42 wasip1::Subscription { 43 userdata: STDIN_ID, 44 u: wasip1::SubscriptionU { 45 tag: wasip1::EVENTTYPE_FD_READ.raw(), 46 u: wasip1::SubscriptionUU { 47 fd_read: fd_readwrite, 48 }, 49 }, 50 }, 51 ]; 52 let out = poll_oneoff_impl(&r#in).unwrap(); 53 // The result should be either a timeout, or that stdin is ready for reading. 54 // Both are valid behaviors that depend on the test environment. 55 assert!(out.len() >= 1, "stdin read should return at least 1 event"); 56 for event in out { 57 if event.type_ == wasip1::EVENTTYPE_CLOCK { 58 assert_errno!(event.error, wasip1::ERRNO_SUCCESS); 59 assert_eq!( 60 event.userdata, CLOCK_ID, 61 "the event.userdata should contain CLOCK_ID", 62 ); 63 } else if event.type_ == wasip1::EVENTTYPE_FD_READ { 64 assert_errno!(event.error, wasip1::ERRNO_SUCCESS); 65 assert_eq!( 66 event.userdata, STDIN_ID, 67 "the event.userdata should contain STDIN_ID", 68 ); 69 } else { 70 panic!("unexpected event type {}", event.type_.raw()); 71 } 72 } 73 } 74 75 fn writable_subs(h: &HashMap<u64, wasip1::Fd>) -> Vec<wasip1::Subscription> { 76 h.iter() 77 .map(|(ud, fd)| wasip1::Subscription { 78 userdata: *ud, 79 u: wasip1::SubscriptionU { 80 tag: wasip1::EVENTTYPE_FD_WRITE.raw(), 81 u: wasip1::SubscriptionUU { 82 fd_write: wasip1::SubscriptionFdReadwrite { 83 file_descriptor: *fd, 84 }, 85 }, 86 }, 87 }) 88 .collect() 89 } 90 91 unsafe fn test_stdout_stderr_write() { 92 let mut writable: HashMap<u64, wasip1::Fd> = 93 [(1, STDOUT_FD), (2, STDERR_FD)].into_iter().collect(); 94 95 let clock = wasip1::Subscription { 96 userdata: CLOCK_ID, 97 u: wasip1::SubscriptionU { 98 tag: wasip1::EVENTTYPE_CLOCK.raw(), 99 u: wasip1::SubscriptionUU { 100 clock: wasip1::SubscriptionClock { 101 id: wasip1::CLOCKID_MONOTONIC, 102 timeout: TIMEOUT, 103 precision: 0, 104 flags: 0, 105 }, 106 }, 107 }, 108 }; 109 let mut timed_out = false; 110 while !writable.is_empty() { 111 if timed_out { 112 panic!("timed out with the following pending subs: {writable:?}") 113 } 114 let mut subs = writable_subs(&writable); 115 subs.push(clock); 116 let out = poll_oneoff_impl(&subs).unwrap(); 117 for event in out { 118 match event.userdata { 119 CLOCK_ID => timed_out = true, 120 ud => { 121 if let Some(_) = writable.remove(&ud) { 122 assert_eq!(event.type_, wasip1::EVENTTYPE_FD_WRITE); 123 assert_errno!(event.error, wasip1::ERRNO_SUCCESS); 124 } else { 125 panic!("Unknown userdata {ud}, pending sub: {writable:?}") 126 } 127 } 128 } 129 } 130 } 131 } 132 133 unsafe fn test_poll_oneoff() { 134 // NB we assume that stdin/stdout/stderr are valid and open 135 // for the duration of the test case 136 test_stdin_read(); 137 test_stdout_stderr_write(); 138 } 139 fn main() { 140 // Run the tests. 141 unsafe { test_poll_oneoff() } 142 } 143