1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 19:17:41 +00:00

Kernel: Protect Mutex's thread lists with a spinlock

This commit is contained in:
Andreas Kling 2022-04-05 14:44:50 +02:00
parent 8296dd9955
commit b28beb691e
2 changed files with 53 additions and 43 deletions

View file

@ -206,16 +206,21 @@ void Mutex::block(Thread& current_thread, Mode mode, SpinlockLocker<Spinlock>& l
{ {
if constexpr (LOCK_IN_CRITICAL_DEBUG) if constexpr (LOCK_IN_CRITICAL_DEBUG)
VERIFY_INTERRUPTS_ENABLED(); VERIFY_INTERRUPTS_ENABLED();
auto& blocked_thread_list = thread_list_for_mode(mode); m_blocked_thread_lists.with([&](auto& lists) {
VERIFY(!blocked_thread_list.contains(current_thread)); auto& list = lists.list_for_mode(mode);
blocked_thread_list.append(current_thread); VERIFY(!list.contains(current_thread));
list.append(current_thread);
});
dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waiting...", this, m_name); dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waiting...", this, m_name);
current_thread.block(*this, lock, requested_locks); current_thread.block(*this, lock, requested_locks);
dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waited", this, m_name); dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waited", this, m_name);
VERIFY(blocked_thread_list.contains(current_thread)); m_blocked_thread_lists.with([&](auto& lists) {
blocked_thread_list.remove(current_thread); auto& list = lists.list_for_mode(mode);
VERIFY(list.contains(current_thread));
list.remove(current_thread);
});
} }
void Mutex::unblock_waiters(Mode previous_mode) void Mutex::unblock_waiters(Mode previous_mode)
@ -223,41 +228,43 @@ void Mutex::unblock_waiters(Mode previous_mode)
VERIFY(m_times_locked == 0); VERIFY(m_times_locked == 0);
VERIFY(m_mode == Mode::Unlocked); VERIFY(m_mode == Mode::Unlocked);
if (m_blocked_threads_list_exclusive.is_empty() && m_blocked_threads_list_shared.is_empty()) m_blocked_thread_lists.with([&](auto& lists) {
return; if (lists.exclusive.is_empty() && lists.shared.is_empty())
return;
auto unblock_shared = [&]() { auto unblock_shared = [&]() {
if (m_blocked_threads_list_shared.is_empty()) if (lists.shared.is_empty())
return false; return false;
m_mode = Mode::Shared; m_mode = Mode::Shared;
for (auto& thread : m_blocked_threads_list_shared) { for (auto& thread : lists.shared) {
auto requested_locks = thread.unblock_from_mutex(*this); auto requested_locks = thread.unblock_from_mutex(*this);
m_shared_holders += requested_locks; m_shared_holders += requested_locks;
#if LOCK_SHARED_UPGRADE_DEBUG #if LOCK_SHARED_UPGRADE_DEBUG
auto set_result = m_shared_holders_map.set(&thread, requested_locks); auto set_result = m_shared_holders_map.set(&thread, requested_locks);
VERIFY(set_result == AK::HashSetResult::InsertedNewEntry); VERIFY(set_result == AK::HashSetResult::InsertedNewEntry);
#endif #endif
m_times_locked += requested_locks; m_times_locked += requested_locks;
} }
return true;
};
auto unblock_exclusive = [&]() {
if (auto* next_exclusive_thread = m_blocked_threads_list_exclusive.first()) {
m_mode = Mode::Exclusive;
m_times_locked = next_exclusive_thread->unblock_from_mutex(*this);
m_holder = next_exclusive_thread;
return true; return true;
} };
return false; auto unblock_exclusive = [&]() {
}; if (auto* next_exclusive_thread = lists.exclusive.first()) {
m_mode = Mode::Exclusive;
m_times_locked = next_exclusive_thread->unblock_from_mutex(*this);
m_holder = next_exclusive_thread;
return true;
}
return false;
};
if (previous_mode == Mode::Exclusive) { if (previous_mode == Mode::Exclusive) {
if (!unblock_shared()) if (!unblock_shared())
unblock_exclusive(); unblock_exclusive();
} else { } else {
if (!unblock_exclusive()) if (!unblock_exclusive())
unblock_shared(); unblock_shared();
} }
});
} }
auto Mutex::force_unlock_exclusive_if_locked(u32& lock_count_to_restore) -> Mode auto Mutex::force_unlock_exclusive_if_locked(u32& lock_count_to_restore) -> Mode

View file

@ -72,12 +72,6 @@ public:
private: private:
using BlockedThreadList = IntrusiveList<&Thread::m_blocked_threads_list_node>; using BlockedThreadList = IntrusiveList<&Thread::m_blocked_threads_list_node>;
ALWAYS_INLINE BlockedThreadList& thread_list_for_mode(Mode mode)
{
VERIFY(mode == Mode::Exclusive || mode == Mode::Shared);
return mode == Mode::Exclusive ? m_blocked_threads_list_exclusive : m_blocked_threads_list_shared;
}
void block(Thread&, Mode, SpinlockLocker<Spinlock>&, u32); void block(Thread&, Mode, SpinlockLocker<Spinlock>&, u32);
void unblock_waiters(Mode); void unblock_waiters(Mode);
@ -96,8 +90,17 @@ private:
RefPtr<Thread> m_holder; RefPtr<Thread> m_holder;
size_t m_shared_holders { 0 }; size_t m_shared_holders { 0 };
BlockedThreadList m_blocked_threads_list_exclusive; struct BlockedThreadLists {
BlockedThreadList m_blocked_threads_list_shared; BlockedThreadList exclusive;
BlockedThreadList shared;
ALWAYS_INLINE BlockedThreadList& list_for_mode(Mode mode)
{
VERIFY(mode == Mode::Exclusive || mode == Mode::Shared);
return mode == Mode::Exclusive ? exclusive : shared;
}
};
SpinlockProtected<BlockedThreadLists> m_blocked_thread_lists;
mutable Spinlock m_lock; mutable Spinlock m_lock;