Explorar o código

Kernel: Release big lock when blocking on another lock

When blocking on a Lock other than the big lock and we're holding the
big lock, we need to release the big lock first. This fixes some
deadlocks where a thread blocks while holding the big lock, preventing
other threads from getting the big lock in order to unblock the waiting
thread.
Tom %!s(int64=4) %!d(string=hai) anos
pai
achega
0536a4ff41
Modificáronse 1 ficheiros con 8 adicións e 1 borrados
  1. 8 1
      Kernel/Thread.cpp

+ 8 - 1
Kernel/Thread.cpp

@@ -211,11 +211,18 @@ void Thread::block(Kernel::Lock& lock, ScopedSpinLock<SpinLock<u8>>& lock_lock,
 
 
     dbgln_if(THREAD_DEBUG, "Thread {} blocking on Lock {}", *this, &lock);
     dbgln_if(THREAD_DEBUG, "Thread {} blocking on Lock {}", *this, &lock);
 
 
+    auto& big_lock = process().big_lock();
     for (;;) {
     for (;;) {
         // Yield to the scheduler, and wait for us to resume unblocked.
         // Yield to the scheduler, and wait for us to resume unblocked.
         VERIFY(!g_scheduler_lock.own_lock());
         VERIFY(!g_scheduler_lock.own_lock());
         VERIFY(Processor::current().in_critical());
         VERIFY(Processor::current().in_critical());
-        yield_while_not_holding_big_lock(); // We might hold the big lock though!
+        if (&lock != &big_lock && big_lock.own_lock()) {
+            // We're locking another lock and already hold the big lock...
+            // We need to release the big lock
+            yield_without_holding_big_lock();
+        } else {
+            yield_while_not_holding_big_lock();
+        }
         VERIFY(Processor::current().in_critical());
         VERIFY(Processor::current().in_critical());
 
 
         ScopedSpinLock block_lock2(m_block_lock);
         ScopedSpinLock block_lock2(m_block_lock);