kernel/condition_variable: Unblock after unset, if possible.
The previous round of this code unblocked after unset universally, but that was incorrect in the case where the thread was not in the "waiting" state before we unset. Yesterday I changed that to just unblock before unset universally. It seems, however, that thread_unblock is so time-consuming that the other thread will wake up and begin doing things before unblock returns for us, and then it will hit the timeout before we have a chance to unset. So, now we unblock later if it is possible to do so. It seems very strange, though, that thread_unblock will not return in a small but significant number of cases before the unblocked thread actually starts running (note that we are in interrupts-disabled mode here, so that is not the problem.) That sounds like a problem for another day. Should fix #17455, possibly in tandem with the previous commit.
This commit is contained in:
parent
145526308a
commit
7959ac39f1
@ -398,17 +398,27 @@ ConditionVariable::_NotifyLocked(bool all, status_t result)
|
||||
panic("entries count was not decremented for a long time!");
|
||||
}
|
||||
} else {
|
||||
const status_t waitStatus = atomic_get_and_set(&entry->fWaitStatus, result);
|
||||
status_t waitStatus = atomic_get_and_set(&entry->fWaitStatus, result);
|
||||
|
||||
// We need not waste time trying to unblock the thread if it already unblocked.
|
||||
if (waitStatus == STATUS_WAITING && thread_is_blocked(thread))
|
||||
thread_unblock(thread, result);
|
||||
SpinLocker threadLocker(thread->scheduler_lock);
|
||||
if (waitStatus == STATUS_WAITING && thread->state != B_THREAD_WAITING) {
|
||||
// The thread is not in B_THREAD_WAITING state, so we must unblock it early,
|
||||
// in case it tries to re-block itself immediately after we unset fVariable.
|
||||
thread_unblock_locked(thread, result);
|
||||
waitStatus = result;
|
||||
}
|
||||
|
||||
// No matter what the thread is doing, as we were the ones to clear its
|
||||
// fThread, so we are the ones responsible for decrementing fEntriesCount.
|
||||
// (We may not validly access the entry once we unset its fVariable.)
|
||||
atomic_pointer_set(&entry->fVariable, (ConditionVariable*)NULL);
|
||||
atomic_add(&fEntriesCount, -1);
|
||||
|
||||
// If the thread was in B_THREAD_WAITING state, we unblock it after unsetting
|
||||
// fVariable, because otherwise it will wake up before thread_unblock returns
|
||||
// and spin while waiting for us to do so.
|
||||
if (waitStatus == STATUS_WAITING)
|
||||
thread_unblock_locked(thread, result);
|
||||
}
|
||||
|
||||
if (!all)
|
||||
|
Loading…
x
Reference in New Issue
Block a user