mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 03:58:12 +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:
parent
2a8de4cdec
commit
65cb406327
4 changed files with 18 additions and 33 deletions
|
@ -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);
|
||||
InterruptDisabler disabler;
|
||||
if (m_holder != current)
|
||||
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;
|
||||
}
|
||||
ASSERT(m_level == 1);
|
||||
ASSERT(m_holder == current);
|
||||
m_holder = nullptr;
|
||||
m_queue.wake_one(&m_lock);
|
||||
--m_level;
|
||||
m_queue.wake_one();
|
||||
return true;
|
||||
}
|
||||
// I don't know *who* is using "m_lock", so just yield.
|
||||
Scheduler::yield();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue