Support "sleep" forms of poll_oneoff.
Add support for `poll_oneoff` calls which just sleep on a relative timeout. This fixes a bug handling code compiled with WASI libc's `sleep` family of functions, which call `poll_oneoff` with a `CLOCK_REALTIME` timer, which wasn't previously implemented.
This commit is contained in:
@@ -26,9 +26,10 @@ unsafe fn test_empty_poll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn test_timeout() {
|
unsafe fn test_timeout() {
|
||||||
|
let timeout = 5_000_000u64; // 5 milliseconds
|
||||||
let clock = wasi::SubscriptionClock {
|
let clock = wasi::SubscriptionClock {
|
||||||
id: wasi::CLOCKID_MONOTONIC,
|
id: wasi::CLOCKID_MONOTONIC,
|
||||||
timeout: 5_000_000u64, // 5 milliseconds
|
timeout,
|
||||||
precision: 0,
|
precision: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
};
|
};
|
||||||
@@ -39,7 +40,9 @@ unsafe fn test_timeout() {
|
|||||||
u: wasi::SubscriptionUU { clock },
|
u: wasi::SubscriptionUU { clock },
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
let before = wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 0).unwrap();
|
||||||
let out = poll_oneoff_impl(&r#in).unwrap();
|
let out = poll_oneoff_impl(&r#in).unwrap();
|
||||||
|
let after = wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 0).unwrap();
|
||||||
assert_eq!(out.len(), 1, "should return 1 event");
|
assert_eq!(out.len(), 1, "should return 1 event");
|
||||||
let event = &out[0];
|
let event = &out[0];
|
||||||
assert_errno!(event.error, wasi::ERRNO_SUCCESS);
|
assert_errno!(event.error, wasi::ERRNO_SUCCESS);
|
||||||
@@ -52,6 +55,42 @@ unsafe fn test_timeout() {
|
|||||||
event.userdata, CLOCK_ID,
|
event.userdata, CLOCK_ID,
|
||||||
"the event.userdata should contain clock_id specified by the user"
|
"the event.userdata should contain clock_id specified by the user"
|
||||||
);
|
);
|
||||||
|
assert!(after - before >= timeout, "poll_oneoff should sleep for the specified interval");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like test_timeout, but uses `CLOCKID_REALTIME`, as WASI libc's sleep
|
||||||
|
// functions do.
|
||||||
|
unsafe fn test_sleep() {
|
||||||
|
let timeout = 5_000_000u64; // 5 milliseconds
|
||||||
|
let clock = wasi::SubscriptionClock {
|
||||||
|
id: wasi::CLOCKID_REALTIME,
|
||||||
|
timeout,
|
||||||
|
precision: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
let r#in = [wasi::Subscription {
|
||||||
|
userdata: CLOCK_ID,
|
||||||
|
u: wasi::SubscriptionU {
|
||||||
|
tag: wasi::EVENTTYPE_CLOCK,
|
||||||
|
u: wasi::SubscriptionUU { clock },
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
let before = wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 0).unwrap();
|
||||||
|
let out = poll_oneoff_impl(&r#in).unwrap();
|
||||||
|
let after = wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 0).unwrap();
|
||||||
|
assert_eq!(out.len(), 1, "should return 1 event");
|
||||||
|
let event = &out[0];
|
||||||
|
assert_errno!(event.error, wasi::ERRNO_SUCCESS);
|
||||||
|
assert_eq!(
|
||||||
|
event.r#type,
|
||||||
|
wasi::EVENTTYPE_CLOCK,
|
||||||
|
"the event.type should equal clock"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
event.userdata, CLOCK_ID,
|
||||||
|
"the event.userdata should contain clock_id specified by the user"
|
||||||
|
);
|
||||||
|
assert!(after - before >= timeout, "poll_oneoff should sleep for the specified interval");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn test_fd_readwrite(fd: wasi::Fd, error_code: wasi::Errno) {
|
unsafe fn test_fd_readwrite(fd: wasi::Fd, error_code: wasi::Errno) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use std::cell::{Ref, RefMut};
|
|||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::io::{IoSlice, IoSliceMut};
|
use std::io::{IoSlice, IoSliceMut};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::thread;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use wiggle::GuestPtr;
|
use wiggle::GuestPtr;
|
||||||
|
|
||||||
@@ -909,6 +910,30 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
|
return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special-case a `poll_oneoff` which is just sleeping on a single
|
||||||
|
// relative timer event, such as what WASI libc uses to implement sleep
|
||||||
|
// functions. This supports all clock IDs, because POSIX says that
|
||||||
|
// `clock_settime` doesn't effect relative sleeps.
|
||||||
|
if nsubscriptions == 1 {
|
||||||
|
let sub = subs.read()?;
|
||||||
|
if let types::SubscriptionU::Clock(clocksub) = sub.u {
|
||||||
|
if !clocksub
|
||||||
|
.flags
|
||||||
|
.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
|
||||||
|
{
|
||||||
|
thread::sleep(Duration::from_nanos(clocksub.timeout));
|
||||||
|
|
||||||
|
events.write(types::Event {
|
||||||
|
userdata: sub.userdata,
|
||||||
|
error: types::Errno::Success,
|
||||||
|
type_: types::Eventtype::Clock,
|
||||||
|
fd_readwrite: fd_readwrite_empty(),
|
||||||
|
})?;
|
||||||
|
return Ok(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let table = self.table();
|
let table = self.table();
|
||||||
let mut poll = Poll::new();
|
let mut poll = Poll::new();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user