diff options
| author | bors <bors@rust-lang.org> | 2023-10-06 11:12:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-10-06 11:12:13 +0000 |
| commit | 6683f13fa1ba91ab84dd5bc5bc21965a1b0530e1 (patch) | |
| tree | 4002fd03f839243b70a6355674d26c8880fdf9dc /library/std/src/sys | |
| parent | d4ba2b4c7c938cf90c03a265cb31356537f608ad (diff) | |
| parent | 9baab45e2f2bc3218737613bda074e5b04d2034b (diff) | |
| download | rust-6683f13fa1ba91ab84dd5bc5bc21965a1b0530e1.tar.gz rust-6683f13fa1ba91ab84dd5bc5bc21965a1b0530e1.zip | |
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`
Diffstat (limited to 'library/std/src/sys')
| -rw-r--r-- | library/std/src/sys/sgx/waitqueue/mod.rs | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/library/std/src/sys/sgx/waitqueue/mod.rs b/library/std/src/sys/sgx/waitqueue/mod.rs index 5e1d859ee99..25eca61d67b 100644 --- a/library/std/src/sys/sgx/waitqueue/mod.rs +++ b/library/std/src/sys/sgx/waitqueue/mod.rs @@ -18,6 +18,7 @@ mod unsafe_list; use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; +use crate::panic::{self, AssertUnwindSafe}; use crate::time::Duration; use super::abi::thread; @@ -147,7 +148,8 @@ impl WaitQueue { /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait /// 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) { // very unsafe: check requirements of UnsafeList::push unsafe { @@ -157,8 +159,13 @@ impl WaitQueue { })); let entry = guard.queue.inner.push(&mut entry); 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 { + // `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 let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE)); rtassert!(eventset & EV_UNPARK == EV_UNPARK); @@ -169,6 +176,7 @@ impl WaitQueue { /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait /// until a wakeup event or timeout. If event was observed, returns true. /// 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()>( lock: &SpinMutex<WaitVariable<T>>, timeout: Duration, @@ -181,9 +189,13 @@ impl WaitQueue { wake: false, })); 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); - // 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 success = entry_lock.lock().wake; if !success { @@ -204,8 +216,8 @@ impl WaitQueue { ) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> { // SAFETY: lifetime of the pop() return value is limited to the map // closure (The closure return value is 'static). The underlying - // stack frame won't be freed until after the WaitGuard created below - // is dropped. + // stack frame won't be freed until after the lock on the queue is released + // (i.e., `guard` is dropped). unsafe { let tcs = guard.queue.inner.pop().map(|entry| -> Tcs { let mut entry_guard = entry.lock(); @@ -231,7 +243,7 @@ impl WaitQueue { ) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> { // SAFETY: lifetime of the pop() return values are limited to the // 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 { let mut count = 0; while let Some(entry) = guard.queue.inner.pop() { |
