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:
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 (;;) {
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue