pub fn notified_tcs(&self) -> NotifiedTcs {
self.notified_tcs
}
+
+ /// Drop this `WaitGuard`, after dropping another `guard`.
+ pub fn drop_after<U>(self, guard: U) {
+ drop(guard);
+ drop(self);
+ }
}
impl<'a, T> Deref for WaitGuard<'a, T> {
NotifiedTcs::Single(tcs) => Some(tcs),
NotifiedTcs::All { .. } => None
};
- usercalls::send(EV_UNPARK, target_tcs).unwrap();
+ rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
}
}
/// until a wakeup event.
///
/// This function does not return until this thread has been awoken.
- pub fn wait<T>(mut guard: SpinMutexGuard<WaitVariable<T>>) {
+ pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
+ // 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);
+ before_wait();
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);
}
}
}
///
/// If a waiter is found, a `WaitGuard` is returned which will notify the
/// waiter when it is dropped.
- pub fn notify_one<T>(mut guard: SpinMutexGuard<WaitVariable<T>>)
- -> Result<WaitGuard<T>, SpinMutexGuard<WaitVariable<T>>>
+ pub fn notify_one<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>)
+ -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>>
{
unsafe {
if let Some(entry) = guard.queue.inner.pop() {
///
/// If at least one waiter is found, a `WaitGuard` is returned which will
/// notify all waiters when it is dropped.
- pub fn notify_all<T>(mut guard: SpinMutexGuard<WaitVariable<T>>)
- -> Result<WaitGuard<T>, SpinMutexGuard<WaitVariable<T>>>
+ pub fn notify_all<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>)
+ -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>>
{
unsafe {
let mut count = 0;
// ,-------> /---------\ 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())
}
}
}
#[inline(always)]
- pub fn lock(&self) -> SpinMutexGuard<T> {
+ pub fn lock(&self) -> SpinMutexGuard<'_, T> {
loop {
match self.try_lock() {
None => while self.lock.load(Ordering::Relaxed) {
}
#[inline(always)]
- pub fn try_lock(&self) -> Option<SpinMutexGuard<T>> {
+ pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
Some(SpinMutexGuard {
mutex: self,
assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
});
- WaitQueue::wait(locked);
+ WaitQueue::wait(locked, ||{});
t1.join().unwrap();
}