Auto merge of #111595 - fortanix:raoul/waitqueue_clarifications, r=workingjubilee
`waitqueue` clarifications for SGX platform The documentation of `waitqueue` functions on the `x86_64-fortanix-unknown-sgx` platform is incorrect at some places and on others missing. This PR improves upon this. cc: `@jethrogb`
This commit is contained in:
commit
6683f13fa1
1 changed files with 19 additions and 7 deletions
|
@ -18,6 +18,7 @@ mod unsafe_list;
|
||||||
|
|
||||||
use crate::num::NonZeroUsize;
|
use crate::num::NonZeroUsize;
|
||||||
use crate::ops::{Deref, DerefMut};
|
use crate::ops::{Deref, DerefMut};
|
||||||
|
use crate::panic::{self, AssertUnwindSafe};
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
|
|
||||||
use super::abi::thread;
|
use super::abi::thread;
|
||||||
|
@ -147,7 +148,8 @@ impl WaitQueue {
|
||||||
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
|
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
|
||||||
/// until a wakeup event.
|
/// until a wakeup event.
|
||||||
///
|
///
|
||||||
/// This function does not return until this thread has been awoken.
|
/// This function does not return until this thread has been awoken. When `before_wait` panics,
|
||||||
|
/// this function will abort.
|
||||||
pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
|
pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
|
||||||
// very unsafe: check requirements of UnsafeList::push
|
// very unsafe: check requirements of UnsafeList::push
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -157,8 +159,13 @@ impl WaitQueue {
|
||||||
}));
|
}));
|
||||||
let entry = guard.queue.inner.push(&mut entry);
|
let entry = guard.queue.inner.push(&mut entry);
|
||||||
drop(guard);
|
drop(guard);
|
||||||
before_wait();
|
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
|
||||||
|
rtabort!("Panic before wait on wakeup event")
|
||||||
|
}
|
||||||
while !entry.lock().wake {
|
while !entry.lock().wake {
|
||||||
|
// `entry.wake` is only set in `notify_one` and `notify_all` functions. Both ensure
|
||||||
|
// the entry is removed from the queue _before_ setting this bool. There are no
|
||||||
|
// other references to `entry`.
|
||||||
// don't panic, this would invalidate `entry` during unwinding
|
// don't panic, this would invalidate `entry` during unwinding
|
||||||
let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
|
let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
|
||||||
rtassert!(eventset & EV_UNPARK == EV_UNPARK);
|
rtassert!(eventset & EV_UNPARK == EV_UNPARK);
|
||||||
|
@ -169,6 +176,7 @@ impl WaitQueue {
|
||||||
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
|
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
|
||||||
/// until a wakeup event or timeout. If event was observed, returns true.
|
/// until a wakeup event or timeout. If event was observed, returns true.
|
||||||
/// If not, it will remove the calling thread from the wait queue.
|
/// If not, it will remove the calling thread from the wait queue.
|
||||||
|
/// When `before_wait` panics, this function will abort.
|
||||||
pub fn wait_timeout<T, F: FnOnce()>(
|
pub fn wait_timeout<T, F: FnOnce()>(
|
||||||
lock: &SpinMutex<WaitVariable<T>>,
|
lock: &SpinMutex<WaitVariable<T>>,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
|
@ -181,9 +189,13 @@ impl WaitQueue {
|
||||||
wake: false,
|
wake: false,
|
||||||
}));
|
}));
|
||||||
let entry_lock = lock.lock().queue.inner.push(&mut entry);
|
let entry_lock = lock.lock().queue.inner.push(&mut entry);
|
||||||
before_wait();
|
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
|
||||||
|
rtabort!("Panic before wait on wakeup event or timeout")
|
||||||
|
}
|
||||||
usercalls::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.
|
// acquire the wait queue's lock first to avoid deadlock
|
||||||
|
// and ensure no other function can simultaneously access the list
|
||||||
|
// (e.g., `notify_one` or `notify_all`)
|
||||||
let mut guard = lock.lock();
|
let mut guard = lock.lock();
|
||||||
let success = entry_lock.lock().wake;
|
let success = entry_lock.lock().wake;
|
||||||
if !success {
|
if !success {
|
||||||
|
@ -204,8 +216,8 @@ impl WaitQueue {
|
||||||
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
|
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
|
||||||
// SAFETY: lifetime of the pop() return value is limited to the map
|
// SAFETY: lifetime of the pop() return value is limited to the map
|
||||||
// closure (The closure return value is 'static). The underlying
|
// closure (The closure return value is 'static). The underlying
|
||||||
// stack frame won't be freed until after the WaitGuard created below
|
// stack frame won't be freed until after the lock on the queue is released
|
||||||
// is dropped.
|
// (i.e., `guard` is dropped).
|
||||||
unsafe {
|
unsafe {
|
||||||
let tcs = guard.queue.inner.pop().map(|entry| -> Tcs {
|
let tcs = guard.queue.inner.pop().map(|entry| -> Tcs {
|
||||||
let mut entry_guard = entry.lock();
|
let mut entry_guard = entry.lock();
|
||||||
|
@ -231,7 +243,7 @@ impl WaitQueue {
|
||||||
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
|
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
|
||||||
// SAFETY: lifetime of the pop() return values are limited to the
|
// SAFETY: lifetime of the pop() return values are limited to the
|
||||||
// while loop body. The underlying stack frames won't be freed until
|
// while loop body. The underlying stack frames won't be freed until
|
||||||
// after the WaitGuard created below is dropped.
|
// after the lock on the queue is released (i.e., `guard` is dropped).
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while let Some(entry) = guard.queue.inner.pop() {
|
while let Some(entry) = guard.queue.inner.pop() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue