Skip to content

Commit 9a5443f

Browse files
committed
waitqueue clarifications for SGX platform
1 parent 5082281 commit 9a5443f

File tree

1 file changed

+12
-4
lines changed
  • library/std/src/sys/sgx/waitqueue

1 file changed

+12
-4
lines changed

library/std/src/sys/sgx/waitqueue/mod.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ impl WaitQueue {
148148
/// until a wakeup event.
149149
///
150150
/// This function does not return until this thread has been awoken.
151+
///
152+
/// Safety: `before_wait` must not panic
151153
pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
152154
// very unsafe: check requirements of UnsafeList::push
153155
unsafe {
@@ -159,6 +161,9 @@ impl WaitQueue {
159161
drop(guard);
160162
before_wait();
161163
while !entry.lock().wake {
164+
// `entry.wake` is only set in `notify_one` and `notify_all` functions. Both ensure
165+
// the entry is removed from the queue _before_ setting this bool. There are no
166+
// other references to `entry`.
162167
// don't panic, this would invalidate `entry` during unwinding
163168
let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
164169
rtassert!(eventset & EV_UNPARK == EV_UNPARK);
@@ -169,6 +174,7 @@ impl WaitQueue {
169174
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
170175
/// until a wakeup event or timeout. If event was observed, returns true.
171176
/// If not, it will remove the calling thread from the wait queue.
177+
/// Safety: `before_wait` must not panic
172178
pub fn wait_timeout<T, F: FnOnce()>(
173179
lock: &SpinMutex<WaitVariable<T>>,
174180
timeout: Duration,
@@ -183,7 +189,9 @@ impl WaitQueue {
183189
let entry_lock = lock.lock().queue.inner.push(&mut entry);
184190
before_wait();
185191
usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
186-
// acquire the wait queue's lock first to avoid deadlock.
192+
// acquire the wait queue's lock first to avoid deadlock
193+
// and ensure no other function can simultaneously access the list
194+
// (e.g., `notify_one` or `notify_all`)
187195
let mut guard = lock.lock();
188196
let success = entry_lock.lock().wake;
189197
if !success {
@@ -204,8 +212,8 @@ impl WaitQueue {
204212
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
205213
// SAFETY: lifetime of the pop() return value is limited to the map
206214
// closure (The closure return value is 'static). The underlying
207-
// stack frame won't be freed until after the WaitGuard created below
208-
// is dropped.
215+
// stack frame won't be freed until after the lock on the queue is released
216+
// (i.e., `guard` is dropped).
209217
unsafe {
210218
let tcs = guard.queue.inner.pop().map(|entry| -> Tcs {
211219
let mut entry_guard = entry.lock();
@@ -231,7 +239,7 @@ impl WaitQueue {
231239
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
232240
// SAFETY: lifetime of the pop() return values are limited to the
233241
// while loop body. The underlying stack frames won't be freed until
234-
// after the WaitGuard created below is dropped.
242+
// after the lock on the queue is released (i.e., `guard` is dropped).
235243
unsafe {
236244
let mut count = 0;
237245
while let Some(entry) = guard.queue.inner.pop() {

0 commit comments

Comments
 (0)