1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:35:07 +00:00

Kernel: Fix a few deadlocks with Thread::m_lock and g_scheduler_lock

g_scheduler_lock cannot safely be acquired after Thread::m_lock
because another processor may already hold g_scheduler_lock and wait
for the same Thread::m_lock.
This commit is contained in:
Tom 2020-10-25 20:22:59 -06:00 committed by Andreas Kling
parent 8c764319ad
commit 1e2e3eed62
6 changed files with 55 additions and 37 deletions

View file

@ -119,6 +119,7 @@ Thread::~Thread()
void Thread::unblock()
{
ASSERT(g_scheduler_lock.own_lock());
ASSERT(m_lock.own_lock());
m_blocker = nullptr;
if (Thread::current() == this) {
@ -288,14 +289,19 @@ void Thread::finalize()
ASSERT(Thread::current() == g_finalizer);
ASSERT(Thread::current() != this);
#ifdef THREAD_DEBUG
dbg() << "Finalizing thread " << *this;
#endif
set_state(Thread::State::Dead);
ASSERT(!m_lock.own_lock());
if (auto* joiner = m_joiner.exchange(nullptr, AK::memory_order_acq_rel)) {
// Notify joiner that we exited
static_cast<JoinBlocker*>(joiner->m_blocker)->joinee_exited(m_exit_value);
{
ScopedSpinLock lock(g_scheduler_lock);
#ifdef THREAD_DEBUG
dbg() << "Finalizing thread " << *this;
#endif
set_state(Thread::State::Dead);
if (auto* joiner = m_joiner.exchange(nullptr, AK::memory_order_acq_rel)) {
// Notify joiner that we exited
static_cast<JoinBlocker*>(joiner->m_blocker)->joinee_exited(m_exit_value);
}
}
if (m_dump_backtrace_on_finalization)
@ -522,6 +528,7 @@ void Thread::resume_from_stopped()
{
ASSERT(is_stopped());
ASSERT(m_stop_state != State::Invalid);
ASSERT(g_scheduler_lock.own_lock());
set_state(m_stop_state);
m_stop_state = State::Invalid;
// make sure SemiPermanentBlocker is unblocked
@ -788,7 +795,7 @@ RefPtr<Thread> Thread::clone(Process& process)
void Thread::set_state(State new_state)
{
ScopedSpinLock lock(g_scheduler_lock);
ASSERT(g_scheduler_lock.own_lock());
if (new_state == m_state)
return;