1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:48:11 +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 (;;) {
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;
}

View file

@ -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; }

View file

@ -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();
}

View file

@ -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);