@@ -18,6 +18,7 @@ mod unsafe_list;
1818
1919use crate :: num:: NonZeroUsize ;
2020use crate :: ops:: { Deref , DerefMut } ;
21+ use crate :: panic:: { self , AssertUnwindSafe } ;
2122use crate :: time:: Duration ;
2223
2324use super :: abi:: thread;
@@ -147,7 +148,8 @@ impl WaitQueue {
147148 /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
148149 /// until a wakeup event.
149150 ///
150- /// This function does not return until this thread has been awoken.
151+ /// This function does not return until this thread has been awoken. When `before_wait` panics,
152+ /// this function will abort.
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 {
@@ -157,8 +159,13 @@ impl WaitQueue {
157159 } ) ) ;
158160 let entry = guard. queue . inner . push ( & mut entry) ;
159161 drop ( guard) ;
160- before_wait ( ) ;
162+ if let Err ( _e) = panic:: catch_unwind ( AssertUnwindSafe ( || before_wait ( ) ) ) {
163+ rtabort ! ( "Panic before wait on wakeup event" )
164+ }
161165 while !entry. lock ( ) . wake {
166+ // `entry.wake` is only set in `notify_one` and `notify_all` functions. Both ensure
167+ // the entry is removed from the queue _before_ setting this bool. There are no
168+ // other references to `entry`.
162169 // don't panic, this would invalidate `entry` during unwinding
163170 let eventset = rtunwrap ! ( Ok , usercalls:: wait( EV_UNPARK , WAIT_INDEFINITE ) ) ;
164171 rtassert ! ( eventset & EV_UNPARK == EV_UNPARK ) ;
@@ -169,6 +176,7 @@ impl WaitQueue {
169176 /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
170177 /// until a wakeup event or timeout. If event was observed, returns true.
171178 /// If not, it will remove the calling thread from the wait queue.
179+ /// When `before_wait` panics, this function will abort.
172180 pub fn wait_timeout < T , F : FnOnce ( ) > (
173181 lock : & SpinMutex < WaitVariable < T > > ,
174182 timeout : Duration ,
@@ -181,9 +189,13 @@ impl WaitQueue {
181189 wake : false ,
182190 } ) ) ;
183191 let entry_lock = lock. lock ( ) . queue . inner . push ( & mut entry) ;
184- before_wait ( ) ;
192+ if let Err ( _e) = panic:: catch_unwind ( AssertUnwindSafe ( || before_wait ( ) ) ) {
193+ rtabort ! ( "Panic before wait on wakeup event or timeout" )
194+ }
185195 usercalls:: wait_timeout ( EV_UNPARK , timeout, || entry_lock. lock ( ) . wake ) ;
186- // acquire the wait queue's lock first to avoid deadlock.
196+ // acquire the wait queue's lock first to avoid deadlock
197+ // and ensure no other function can simultaneously access the list
198+ // (e.g., `notify_one` or `notify_all`)
187199 let mut guard = lock. lock ( ) ;
188200 let success = entry_lock. lock ( ) . wake ;
189201 if !success {
@@ -204,8 +216,8 @@ impl WaitQueue {
204216 ) -> Result < WaitGuard < ' _ , T > , SpinMutexGuard < ' _ , WaitVariable < T > > > {
205217 // SAFETY: lifetime of the pop() return value is limited to the map
206218 // 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.
219+ // stack frame won't be freed until after the lock on the queue is released
220+ // (i.e., `guard` is dropped) .
209221 unsafe {
210222 let tcs = guard. queue . inner . pop ( ) . map ( |entry| -> Tcs {
211223 let mut entry_guard = entry. lock ( ) ;
@@ -231,7 +243,7 @@ impl WaitQueue {
231243 ) -> Result < WaitGuard < ' _ , T > , SpinMutexGuard < ' _ , WaitVariable < T > > > {
232244 // SAFETY: lifetime of the pop() return values are limited to the
233245 // while loop body. The underlying stack frames won't be freed until
234- // after the WaitGuard created below is dropped.
246+ // after the lock on the queue is released (i.e., `guard` is dropped) .
235247 unsafe {
236248 let mut count = 0 ;
237249 while let Some ( entry) = guard. queue . inner . pop ( ) {
0 commit comments