Move usercall_wait_timeout to abi::usercalls::wait_timeout
This commit is contained in:
parent
1466598e19
commit
85c25aed51
4 changed files with 74 additions and 82 deletions
|
|
@ -1,8 +1,8 @@
|
|||
use crate::cmp;
|
||||
use crate::convert::TryFrom;
|
||||
use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
|
||||
use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
|
||||
use crate::sys::rand::rdrand64;
|
||||
use crate::time::Duration;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
pub(crate) mod alloc;
|
||||
#[macro_use]
|
||||
|
|
@ -169,6 +169,76 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
|
|||
unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
|
||||
}
|
||||
|
||||
/// This function makes an effort to wait for a non-spurious event at least as
|
||||
/// long as `duration`. Note that in general there is no guarantee about accuracy
|
||||
/// of time and timeouts in SGX model. The enclave runner serving usercalls may
|
||||
/// lie about current time and/or ignore timeout values.
|
||||
///
|
||||
/// Once the event is observed, `should_wake_up` will be used to determine
|
||||
/// whether or not the event was spurious.
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
|
||||
where
|
||||
F: Fn() -> bool,
|
||||
{
|
||||
// Calls the wait usercall and checks the result. Returns true if event was
|
||||
// returned, and false if WouldBlock/TimedOut was returned.
|
||||
// If duration is None, it will use WAIT_NO.
|
||||
fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
|
||||
let timeout = duration.map_or(raw::WAIT_NO, |duration| {
|
||||
cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
|
||||
});
|
||||
match wait(event_mask, timeout) {
|
||||
Ok(eventset) => {
|
||||
if event_mask == 0 {
|
||||
rtabort!("expected wait() to return Err, found Ok.");
|
||||
}
|
||||
rtassert!(eventset != 0 && eventset & !event_mask == 0);
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match wait_checked(event_mask, Some(duration)) {
|
||||
false => return, // timed out
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
|
||||
// Drain all cached events.
|
||||
// Note that `event_mask != 0` is implied if we get here.
|
||||
loop {
|
||||
match wait_checked(event_mask, None) {
|
||||
false => break, // no more cached events
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
}
|
||||
|
||||
// Continue waiting, but take note of time spent waiting so we don't wait
|
||||
// forever. We intentionally don't call `Instant::now()` before this point
|
||||
// to avoid the cost of the `insecure_time` usercall in case there are no
|
||||
// spurious wakeups.
|
||||
|
||||
let start = Instant::now();
|
||||
let mut remaining = duration;
|
||||
loop {
|
||||
match wait_checked(event_mask, Some(remaining)) {
|
||||
false => return, // timed out
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
remaining = match duration.checked_sub(start.elapsed()) {
|
||||
Some(remaining) => remaining,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Usercall `send`. See the ABI documentation for more information.
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
|
||||
|
|
|
|||
|
|
@ -110,82 +110,6 @@ pub fn decode_error_kind(code: i32) -> ErrorKind {
|
|||
}
|
||||
}
|
||||
|
||||
// This function makes an effort to wait for a non-spurious event at least as
|
||||
// long as `duration`. Note that in general there is no guarantee about accuracy
|
||||
// of time and timeouts in SGX model. The enclave runner serving usercalls may
|
||||
// lie about current time and/or ignore timeout values.
|
||||
//
|
||||
// Once the event is observed, `should_wake_up` will be used to determine
|
||||
// whether or not the event was spurious.
|
||||
pub fn usercall_wait_timeout<F>(event_mask: u64, duration: crate::time::Duration, should_wake_up: F)
|
||||
where
|
||||
F: Fn() -> bool,
|
||||
{
|
||||
use self::abi::usercalls;
|
||||
use crate::cmp;
|
||||
use crate::io::ErrorKind;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
// Calls the wait usercall and checks the result. Returns true if event was
|
||||
// returned, and false if WouldBlock/TimedOut was returned.
|
||||
// If duration is None, it will use WAIT_NO.
|
||||
fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
|
||||
let timeout = duration.map_or(usercalls::raw::WAIT_NO, |duration| {
|
||||
cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
|
||||
});
|
||||
match usercalls::wait(event_mask, timeout) {
|
||||
Ok(eventset) => {
|
||||
if event_mask == 0 {
|
||||
rtabort!("expected usercalls::wait() to return Err, found Ok.");
|
||||
}
|
||||
// A matching event is one whose bits are equal to or a subset
|
||||
// of `event_mask`.
|
||||
rtassert!(eventset & !event_mask == 0);
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match wait_checked(event_mask, Some(duration)) {
|
||||
false => return, // timed out
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
|
||||
// Drain all cached events.
|
||||
// Note that `event_mask != 0` is implied if we get here.
|
||||
loop {
|
||||
match wait_checked(event_mask, None) {
|
||||
false => break, // no more cached events
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
}
|
||||
|
||||
// Continue waiting, but take note of time spent waiting so we don't wait
|
||||
// forever. We intentionally don't call `Instant::now()` before this point
|
||||
// to avoid the cost of the `insecure_time` usercall in case there are no
|
||||
// spurious wakeups.
|
||||
|
||||
let start = Instant::now();
|
||||
let mut remaining = duration;
|
||||
loop {
|
||||
match wait_checked(event_mask, Some(remaining)) {
|
||||
false => return, // timed out
|
||||
true if should_wake_up() => return, // woken up
|
||||
true => {} // spurious event
|
||||
}
|
||||
remaining = match duration.checked_sub(start.elapsed()) {
|
||||
Some(remaining) => remaining,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This enum is used as the storage for a bunch of types which can't actually
|
||||
// exist.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![cfg_attr(test, allow(dead_code))] // why is this necessary?
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::sys::usercall_wait_timeout;
|
||||
use crate::time::Duration;
|
||||
|
||||
use super::abi::usercalls;
|
||||
|
|
@ -75,7 +74,7 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
usercall_wait_timeout(0, dur, || true);
|
||||
usercalls::wait_timeout(0, dur, || true);
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
//! The queue and associated wait state are stored in a `WaitVariable`.
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::sys::usercall_wait_timeout;
|
||||
use crate::time::Duration;
|
||||
|
||||
use super::abi::thread;
|
||||
|
|
@ -176,7 +175,7 @@ impl WaitQueue {
|
|||
}));
|
||||
let entry_lock = lock.lock().queue.inner.push(&mut entry);
|
||||
before_wait();
|
||||
usercall_wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
|
||||
usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
|
||||
// acquire the wait queue's lock first to avoid deadlock.
|
||||
let mut guard = lock.lock();
|
||||
let success = entry_lock.lock().wake;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue