1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 06:47:40 +00:00

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.
This commit is contained in:
Andreas Kling 2020-01-12 22:53:20 +01:00
parent 2a8de4cdec
commit 65cb406327
4 changed files with 18 additions and 33 deletions

View file

@ -44,30 +44,15 @@ void Lock::unlock()
} }
} }
bool Lock::unlock_if_locked() bool Lock::force_unlock_if_locked()
{ {
for (;;) { InterruptDisabler disabler;
bool expected = false; if (m_holder != current)
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; return false;
} ASSERT(m_level == 1);
if (m_holder != current) { ASSERT(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_holder = nullptr;
m_queue.wake_one(&m_lock); --m_level;
m_queue.wake_one();
return true; return true;
}
// I don't know *who* is using "m_lock", so just yield.
Scheduler::yield();
}
} }

View file

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

View file

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

View file

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