Browse Source

Kernel: Allow unlocking a held Lock with interrupts disabled

This is needed to eliminate a race in Thread::wait_on() where we'd
otherwise have to wait until after unlocking the process lock before
we can disable interrupts.
Andreas Kling 5 năm trước cách đây
mục cha
commit
65cb406327
4 tập tin đã thay đổi với 18 bổ sung33 xóa
  1. 10 25
      Kernel/Lock.cpp
  2. 1 1
      Kernel/Lock.h
  3. 2 2
      Kernel/Process.cpp
  4. 5 5
      Kernel/Thread.cpp

+ 10 - 25
Kernel/Lock.cpp

@@ -44,30 +44,15 @@ void Lock::unlock()
     }
 }
 
-bool Lock::unlock_if_locked()
+bool Lock::force_unlock_if_locked()
 {
-    for (;;) {
-        bool expected = false;
-        if (m_lock.compare_exchange_strong(expected, true, AK::memory_order_acq_rel)) {
-            if (m_level == 0) {
-                m_lock.store(false, AK::memory_order_release);
-                return false;
-            }
-            if (m_holder != current) {
-                m_lock.store(false, AK::memory_order_release);
-                return false;
-            }
-            ASSERT(m_level);
-            --m_level;
-            if (m_level) {
-                m_lock.store(false, AK::memory_order_release);
-                return false;
-            }
-            m_holder = nullptr;
-            m_queue.wake_one(&m_lock);
-            return true;
-        }
-        // I don't know *who* is using "m_lock", so just yield.
-        Scheduler::yield();
-    }
+    InterruptDisabler disabler;
+    if (m_holder != current)
+        return false;
+    ASSERT(m_level == 1);
+    ASSERT(m_holder == current);
+    m_holder = nullptr;
+    --m_level;
+    m_queue.wake_one();
+    return true;
 }

+ 1 - 1
Kernel/Lock.h

@@ -21,7 +21,7 @@ public:
 
     void lock();
     void unlock();
-    bool unlock_if_locked();
+    bool force_unlock_if_locked();
     bool is_locked() const { return m_holder; }
 
     const char* name() const { return m_name; }

+ 2 - 2
Kernel/Process.cpp

@@ -888,7 +888,7 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
 #endif
 
     new_main_thread->set_state(Thread::State::Skip1SchedulerPass);
-    big_lock().unlock_if_locked();
+    big_lock().force_unlock_if_locked();
     return 0;
 }
 
@@ -3622,7 +3622,7 @@ void Process::sys$exit_thread(void* exit_value)
     cli();
     current->m_exit_value = exit_value;
     current->set_should_die();
-    big_lock().unlock_if_locked();
+    big_lock().force_unlock_if_locked();
     current->die_if_needed();
     ASSERT_NOT_REACHED();
 }

+ 5 - 5
Kernel/Thread.cpp

@@ -174,7 +174,7 @@ void Thread::die_if_needed()
     if (!m_should_die)
         return;
 
-    m_process.big_lock().unlock_if_locked();
+    unlock_process_if_locked();
 
     InterruptDisabler disabler;
     set_state(Thread::State::Dying);
@@ -185,15 +185,15 @@ void Thread::die_if_needed()
 
 void Thread::yield_without_holding_big_lock()
 {
-    bool did_unlock = process().big_lock().unlock_if_locked();
+    bool did_unlock = unlock_process_if_locked();
     Scheduler::yield();
     if (did_unlock)
-        process().big_lock().lock();
+        relock_process();
 }
 
 bool Thread::unlock_process_if_locked()
 {
-    return process().big_lock().unlock_if_locked();
+    return process().big_lock().force_unlock_if_locked();
 }
 
 void Thread::relock_process()
@@ -785,8 +785,8 @@ const LogStream& operator<<(const LogStream& stream, const Thread& value)
 
 void Thread::wait_on(WaitQueue& queue, Atomic<bool>* lock, Thread* beneficiary, const char* reason)
 {
-    bool did_unlock = unlock_process_if_locked();
     cli();
+    bool did_unlock = unlock_process_if_locked();
     if (lock)
         *lock = false;
     set_state(State::Queued);