From 858210daf4391df773d8ec47adc17caa77d363bd Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 6 Dec 2021 13:11:28 -0500 Subject: [PATCH] kernel/condition_variable: Acquire thread->scheduler_lock before unsetting fVariable. This fixes a race condition as described in the inline comment. Hopefully fixes #17444. --- src/system/kernel/condition_variable.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/system/kernel/condition_variable.cpp b/src/system/kernel/condition_variable.cpp index acd3be3d67..def1472bfb 100644 --- a/src/system/kernel/condition_variable.cpp +++ b/src/system/kernel/condition_variable.cpp @@ -400,6 +400,10 @@ ConditionVariable::_NotifyLocked(bool all, status_t result) } else { const status_t waitStatus = atomic_get_and_set(&entry->fWaitStatus, result); + // Prevent the thread from changing status after we unset its fVariable, + // as otherwise it could re-block itself before we call thread_unblock. + SpinLocker threadLocker(thread->scheduler_lock); + // 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.) @@ -409,7 +413,7 @@ ConditionVariable::_NotifyLocked(bool all, status_t result) // Do this after unsetting fVariable, as in case the entry wakes up // and tries to remove itself, it need not not have to wait for us. if (waitStatus == STATUS_WAITING) - thread_unblock(thread, result); + thread_unblock_locked(thread, result); } if (!all)