NotifiedTcs::Single(tcs) => Some(tcs),
NotifiedTcs::All { .. } => None
};
- usercalls::send(EV_UNPARK, target_tcs).unwrap();
+ rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
}
}
///
/// This function does not return until this thread has been awoken.
pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
+ // very unsafe: check requirements of UnsafeList::push
unsafe {
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
tcs: thread::current(),
let entry = guard.queue.inner.push(&mut entry);
drop(guard);
while !entry.lock().wake {
- assert_eq!(
- usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK,
- EV_UNPARK
- );
+ // 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);
}
}
}
// ,-------> /---------\ next ---,
// | |head_tail| |
// `--- prev \---------/ <-------`
- assert_eq!(self.head_tail.as_ref().prev, first);
+ rtassert!(self.head_tail.as_ref().prev == first);
true
} else {
false
/// # Safety
///
/// The entry must remain allocated until the entry is removed from the
- /// list AND the caller who popped is done using the entry.
+ /// list AND the caller who popped is done using the entry. Special
+ /// care must be taken in the caller of `push` to ensure unwinding does
+ /// not destroy the stack frame containing the entry.
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
self.init();
entry.as_mut().prev = prev_tail;
entry.as_mut().next = self.head_tail;
prev_tail.as_mut().next = entry;
+ // unwrap ok: always `Some` on non-dummy entries
(*entry.as_ptr()).value.as_ref().unwrap()
}
second.as_mut().prev = self.head_tail;
first.as_mut().next = NonNull::dangling();
first.as_mut().prev = NonNull::dangling();
+ // unwrap ok: always `Some` on non-dummy entries
Some((*first.as_ptr()).value.as_ref().unwrap())
}
}