// 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, `woken_up` will be used to determine whether or
-// not the event was spurious.
-//
-// FIXME: note these caveats in documentation of all public types that use this
-// function in their execution path.
-pub fn wait_timeout_sgx<F>(event_mask: u64, duration: crate::time::Duration, woken_up: F)
+// 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,
{
if event_mask == 0 {
rtabort!("expected usercalls::wait() to return Err, found Ok.");
}
- rtassert!(eventset & event_mask == event_mask);
+ // A matching event is one whose bits are equal to or a subset
+ // of `event_mask`.
+ rtassert!(eventset & !event_mask == 0);
true
}
Err(e) => {
}
match wait_checked(event_mask, Some(duration)) {
- false => return, // timed out
- true if woken_up() => return, // woken up
- true => {} // spurious event
+ 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 woken_up() => return, // woken up
- true => {} // spurious event
+ false => break, // no more cached events
+ true if should_wake_up() => return, // woken up
+ true => {} // spurious event
}
}
let mut remaining = duration;
loop {
match wait_checked(event_mask, Some(remaining)) {
- false => return, // timed out
- true if woken_up() => return, // woken up
- true => {} // spurious event
+ 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,
#![cfg_attr(test, allow(dead_code))] // why is this necessary?
-
use crate::ffi::CStr;
use crate::io;
-use crate::sys::wait_timeout_sgx;
+use crate::sys::usercall_wait_timeout;
use crate::time::Duration;
use super::abi::usercalls;
}
pub fn sleep(dur: Duration) {
- wait_timeout_sgx(0, dur, || true);
+ usercall_wait_timeout(0, dur, || true);
}
pub fn join(self) {
-/// A simple queue implementation for synchronization primitives.
-///
-/// This queue is used to implement condition variable and mutexes.
-///
-/// Users of this API are expected to use the `WaitVariable<T>` type. Since
-/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
-/// allow shared access.
-///
-/// Since userspace may send spurious wake-ups, the wakeup event state is
-/// recorded in the enclave. The wakeup event state is protected by a spinlock.
-/// The queue and associated wait state are stored in a `WaitVariable`.
+//! A simple queue implementation for synchronization primitives.
+//!
+//! This queue is used to implement condition variable and mutexes.
+//!
+//! Users of this API are expected to use the `WaitVariable<T>` type. Since
+//! that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
+//! allow shared access.
+//!
+//! Since userspace may send spurious wake-ups, the wakeup event state is
+//! recorded in the enclave. The wakeup event state is protected by a spinlock.
+//! The queue and associated wait state are stored in a `WaitVariable`.
use crate::num::NonZeroUsize;
use crate::ops::{Deref, DerefMut};
-use crate::sys::wait_timeout_sgx;
+use crate::sys::usercall_wait_timeout;
use crate::time::Duration;
use super::abi::thread;
}));
let entry_lock = lock.lock().queue.inner.push(&mut entry);
before_wait();
- // don't panic, this would invalidate `entry` during unwinding
- wait_timeout_sgx(EV_UNPARK, timeout, || entry_lock.lock().wake);
+ usercall_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 entry_guard = entry_lock.lock();
- let success = entry_guard.wake;
+ let success = entry_lock.lock().wake;
if !success {
- // nobody is waking us up, so remove the entry from the wait queue.
- drop(entry_guard);
+ // nobody is waking us up, so remove our entry from the wait queue.
guard.queue.inner.remove(&mut entry);
}
success
///
/// # Safety
///
- /// The caller must ensure that entry has been pushed prior to this
- /// call and has not moved since push.
+ /// The caller must ensure that `entry` has been pushed onto `self`
+ /// prior to this call and has not moved since then.
pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
rtassert!(!self.is_empty());
// BEFORE:
fn wait(self) {
self.shared.fetch_add(1, Ordering::SeqCst);
while self.shared.load(Ordering::SeqCst) != self.count {
+ #[cfg(target_env = "sgx")]
thread::yield_now();
}
}