Skip to content

Commit 357c770

Browse files
write poll_oneoff
1 parent 59317f8 commit 357c770

4 files changed

Lines changed: 181 additions & 10 deletions

File tree

gabagool-wasip1/src/ctx.rs

Lines changed: 164 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,78 @@ use std::str;
44
use std::time::{SystemTime, UNIX_EPOCH};
55

66
use 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

1373
pub enum DispatchResult {
1474
Values(Vec<RawValue>),
1575
Exit(u32),
1676
}
1777

18-
#[derive(Debug, Default)]
78+
#[derive(Debug)]
1979
pub 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

29108
impl 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;

gabagool-wasip1/src/snapshot.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ impl Snapshot for WasiCtx {
146146
self.stdin_buf.encode(buf);
147147
self.stdout_buf.encode(buf);
148148
self.stderr_buf.encode(buf);
149+
self.clock_nanos.encode(buf);
149150
}
150151
fn decode(buf: &mut &[u8]) -> Self {
151152
let fd_table = FdTable::decode(buf);
@@ -161,6 +162,7 @@ impl Snapshot for WasiCtx {
161162
let stdin_buf = Vec::<u8>::decode(buf);
162163
let stdout_buf = Vec::<u8>::decode(buf);
163164
let stderr_buf = Vec::<u8>::decode(buf);
165+
let clock_nanos = u64::decode(buf);
164166

165167
let mut ctx = Self {
166168
fd_table,
@@ -170,6 +172,7 @@ impl Snapshot for WasiCtx {
170172
stdin_buf,
171173
stdout_buf,
172174
stderr_buf,
175+
clock_nanos,
173176
};
174177

175178
ctx.reopen_files();

programs-wasi/sleep.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::time::{Duration, Instant};
2+
3+
fn main() {
4+
let before = Instant::now();
5+
std::thread::sleep(Duration::from_millis(100));
6+
let elapsed = before.elapsed();
7+
8+
if elapsed >= Duration::from_millis(100) {
9+
println!("slept ok");
10+
} else {
11+
eprintln!("sleep too short: {:?}", elapsed);
12+
std::process::exit(1);
13+
}
14+
}

programs-wasi/sleep.wasm

1.74 MB
Binary file not shown.

0 commit comments

Comments
 (0)