@@ -4,18 +4,78 @@ use std::str;
44use std:: time:: { SystemTime , UNIX_EPOCH } ;
55
66use gabagool:: {
7- CompositeType , ExecutionState , ExternalValue , FunctionInstance , ImportDescription , Instance ,
8- Module , RawValue , Store ,
7+ CompositeType , ExecutionState , ExternalValue , FunctionInstance , GuestMemory , ImportDescription ,
8+ Instance , Module , RawValue , Store ,
99} ;
1010
11- use crate :: { Errno , FdEntry , FdFlags , FdKind , FdTable , FileType , Rights } ;
11+ struct MemCursor < ' a > {
12+ mem : & ' a mut GuestMemory ,
13+ pos : usize ,
14+ }
15+
16+ impl < ' a > MemCursor < ' a > {
17+ const fn new ( mem : & ' a mut GuestMemory , pos : usize ) -> Self {
18+ Self { mem, pos }
19+ }
20+
21+ const fn align ( & mut self , n : usize ) {
22+ self . pos = ( self . pos + n - 1 ) & !( n - 1 ) ;
23+ }
24+
25+ fn read_u8 ( & mut self ) -> u8 {
26+ let v = self . mem . read_u8 ( self . pos ) ;
27+ self . pos += 1 ;
28+
29+ v
30+ }
31+
32+ fn read_u16 ( & mut self ) -> u16 {
33+ let v = self . mem . read_u16 ( self . pos ) ;
34+ self . pos += 2 ;
35+
36+ v
37+ }
38+
39+ fn read_u32 ( & mut self ) -> u32 {
40+ let v = self . mem . read_u32 ( self . pos ) ;
41+ self . pos += 4 ;
42+
43+ v
44+ }
45+
46+ fn read_u64 ( & mut self ) -> u64 {
47+ let v = self . mem . read_u64 ( self . pos ) ;
48+ self . pos += 8 ;
49+
50+ v
51+ }
52+
53+ fn write_u8 ( & mut self , val : u8 ) {
54+ self . mem . write_u8 ( self . pos , val) ;
55+ self . pos += 1 ;
56+ }
57+
58+ fn write_u16 ( & mut self , val : u16 ) {
59+ self . mem . write_u16 ( self . pos , val) ;
60+ self . pos += 2 ;
61+ }
62+
63+ fn write_u64 ( & mut self , val : u64 ) {
64+ self . mem . write_u64 ( self . pos , val) ;
65+ self . pos += 8 ;
66+ }
67+ }
68+
69+ use crate :: {
70+ Errno , FdEntry , FdFlags , FdKind , FdTable , FileType , Rights , EVENT_SIZE , SUBSCRIPTION_SIZE ,
71+ } ;
1272
1373pub enum DispatchResult {
1474 Values ( Vec < RawValue > ) ,
1575 Exit ( u32 ) ,
1676}
1777
18- #[ derive( Debug , Default ) ]
78+ #[ derive( Debug ) ]
1979pub struct WasiCtx {
2080 pub fd_table : FdTable ,
2181 pub args : Vec < String > ,
@@ -24,6 +84,25 @@ pub struct WasiCtx {
2484 pub stdin_buf : Vec < u8 > ,
2585 pub stdout_buf : Vec < u8 > ,
2686 pub stderr_buf : Vec < u8 > ,
87+ pub clock_nanos : u64 ,
88+ }
89+
90+ impl Default for WasiCtx {
91+ fn default ( ) -> Self {
92+ Self {
93+ fd_table : FdTable :: default ( ) ,
94+ args : Vec :: new ( ) ,
95+ environ : Vec :: new ( ) ,
96+ exit_code : None ,
97+ stdin_buf : Vec :: new ( ) ,
98+ stdout_buf : Vec :: new ( ) ,
99+ stderr_buf : Vec :: new ( ) ,
100+ clock_nanos : SystemTime :: now ( )
101+ . duration_since ( UNIX_EPOCH )
102+ . unwrap_or_default ( )
103+ . as_nanos ( ) as u64 ,
104+ }
105+ }
27106}
28107
29108impl WasiCtx {
@@ -172,6 +251,7 @@ impl WasiCtx {
172251 "clock_time_get" => self . clock_time_get ( store, args) ,
173252 "clock_res_get" => self . clock_res_get ( store, args) ,
174253 "random_get" => self . random_get ( store, args) ,
254+ "poll_oneoff" => self . poll_oneoff ( store, args) ,
175255 "sched_yield" => Errno :: Success ,
176256 "proc_raise" => Errno :: NoSys ,
177257 "sock_accept" => Errno :: NoSys ,
@@ -650,12 +730,7 @@ impl WasiCtx {
650730 let timestamp_ptr = args[ 2 ] . as_i32 ( ) as usize ;
651731
652732 let nanos = match clock_id {
653- 0 | 1 => {
654- let duration = SystemTime :: now ( )
655- . duration_since ( UNIX_EPOCH )
656- . unwrap_or_default ( ) ;
657- duration. as_nanos ( ) as u64
658- }
733+ 0 | 1 => self . clock_nanos ,
659734 _ => return Errno :: Inval ,
660735 } ;
661736
@@ -681,6 +756,68 @@ impl WasiCtx {
681756 Errno :: Success
682757 }
683758
759+ fn poll_oneoff ( & mut self , store : & mut Store , args : & [ RawValue ] ) -> Errno {
760+ let in_ptr = args[ 0 ] . as_i32 ( ) as usize ;
761+ let out_ptr = args[ 1 ] . as_i32 ( ) as usize ;
762+ let nsubscriptions = args[ 2 ] . as_i32 ( ) as u32 ;
763+ let nevents_ptr = args[ 3 ] . as_i32 ( ) as usize ;
764+
765+ let mem = & mut store. memories [ 0 ] . data ;
766+ let mut nevents = 0u32 ;
767+
768+ for i in 0 ..nsubscriptions {
769+ let sub_base = in_ptr + ( i * SUBSCRIPTION_SIZE ) as usize ;
770+
771+ let mut r = MemCursor :: new ( mem, sub_base) ;
772+
773+ let userdata = r. read_u64 ( ) ;
774+ let tag = r. read_u8 ( ) ;
775+ r. align ( 8 ) ;
776+ let _clock_id = r. read_u32 ( ) ;
777+ r. align ( 8 ) ;
778+ let timeout = r. read_u64 ( ) ;
779+ let _precision = r. read_u64 ( ) ;
780+ let flags = r. read_u16 ( ) ;
781+
782+ let evt_base = out_ptr + ( nevents * EVENT_SIZE ) as usize ;
783+ let mut w = MemCursor :: new ( mem, evt_base) ;
784+
785+ match tag {
786+ 0 => {
787+ if flags & 1 == 0 {
788+ self . clock_nanos += timeout;
789+ } else if timeout > self . clock_nanos {
790+ self . clock_nanos = timeout;
791+ }
792+
793+ w. write_u64 ( userdata) ;
794+ w. write_u16 ( 0 ) ;
795+ w. write_u8 ( 0 ) ;
796+ nevents += 1 ;
797+ }
798+ 1 | 2 => {
799+ w. write_u64 ( userdata) ;
800+ w. write_u16 ( 0 ) ;
801+ w. write_u8 ( tag) ;
802+ w. align ( 8 ) ;
803+ w. write_u64 ( 0 ) ;
804+ w. write_u16 ( 0 ) ;
805+ nevents += 1 ;
806+ }
807+ _ => {
808+ w. write_u64 ( userdata) ;
809+ w. write_u16 ( Errno :: Inval as u16 ) ;
810+ w. write_u8 ( tag) ;
811+ nevents += 1 ;
812+ }
813+ }
814+ }
815+
816+ store. memories [ 0 ] . data . write_u32 ( nevents_ptr, nevents) ;
817+
818+ Errno :: Success
819+ }
820+
684821 fn random_get ( & self , store : & mut Store , args : & [ RawValue ] ) -> Errno {
685822 let buf_ptr = args[ 0 ] . as_i32 ( ) as usize ;
686823 let buf_len = args[ 1 ] . as_i32 ( ) as usize ;
@@ -1277,6 +1414,23 @@ mod tests {
12771414 assert_eq ! ( on_disk, "howdy from file" ) ;
12781415 }
12791416
1417+ #[ test]
1418+ fn sleep ( ) {
1419+ let wasm = std:: fs:: read ( "../programs-wasi/sleep.wasm" ) . unwrap ( ) ;
1420+ let module = Module :: new ( & wasm) . unwrap ( ) ;
1421+ let mut store = Store :: new ( ) ;
1422+ let mut wasi = WasiCtx :: new ( ) ;
1423+
1424+ let before = wasi. clock_nanos ;
1425+ let imports = wasi. imports ( & mut store, & module) ;
1426+ let instance = store. instantiate ( & module, imports) . unwrap ( ) ;
1427+ let exit_code = wasi. run ( & mut store, instance) . unwrap ( ) ;
1428+
1429+ assert_eq ! ( exit_code, 0 ) ;
1430+ assert_eq ! ( & wasi. stdout_buf, b"slept ok\n " ) ;
1431+ assert ! ( wasi. clock_nanos >= before + 100_000_000 ) ;
1432+ }
1433+
12801434 #[ test]
12811435 fn snapshot_howdy ( ) {
12821436 use gabagool:: snapshot:: Snapshot ;
0 commit comments