diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 18bcea2ee2..e153f10c01 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -564,6 +564,17 @@ void dump_thread_list(bool with_stack_traces) thread.times_scheduled()); break; } + if (thread.state() == Thread::State::Blocked && thread.blocking_mutex()) { + dmesgln(" Blocking on Mutex {:#x} ({})", thread.blocking_mutex(), thread.blocking_mutex()->name()); + } + if (thread.state() == Thread::State::Blocked && thread.blocker()) { + dmesgln(" Blocking on Blocker {:#x}", thread.blocker()); + } +#if LOCK_DEBUG + thread.for_each_held_lock([](auto const& entry) { + dmesgln(" Holding lock {:#x} ({}) at {}", entry.lock, entry.lock->name(), entry.lock_location); + }); +#endif if (with_stack_traces) { auto trace_or_error = thread.backtrace(); if (!trace_or_error.is_error()) { diff --git a/Kernel/Thread.h b/Kernel/Thread.h index f533237451..a6e22826f5 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -1154,6 +1154,22 @@ public: ErrorOr> backtrace(); + Blocker const* blocker() const { return m_blocker; }; + Kernel::Mutex const* blocking_mutex() const { return m_blocking_mutex; } + +#if LOCK_DEBUG + struct HoldingLockInfo { + Mutex* lock; + LockLocation lock_location; + unsigned count; + }; + + template Callback> + void for_each_held_lock(Callback); + template Callback> + void for_each_held_lock(Callback); +#endif + private: Thread(NonnullLockRefPtr, NonnullOwnPtr, NonnullLockRefPtr, NonnullOwnPtr); @@ -1266,11 +1282,6 @@ private: IntrusiveListNode m_big_lock_blocked_threads_list_node; #if LOCK_DEBUG - struct HoldingLockInfo { - Mutex* lock; - LockLocation lock_location; - unsigned count; - }; Atomic m_holding_locks { 0 }; Spinlock m_holding_locks_lock { LockRank::None }; Vector m_holding_locks_list; @@ -1386,6 +1397,28 @@ inline IterationDecision Thread::for_each_in_state(State state, Callback callbac }); } +#if LOCK_DEBUG +template Callback> +inline void Thread::for_each_held_lock(Callback callback) +{ + SpinlockLocker list_lock(m_holding_locks_lock); + + for (auto const& lock_info : m_holding_locks_list) { + if (callback(lock_info) == IterationDecision::Break) + break; + } +} + +template Callback> +inline void Thread::for_each_held_lock(Callback callback) +{ + for_each_held_lock([&](auto const& lock_info) { + callback(lock_info); + return IterationDecision::Continue; + }); +} +#endif + } template<>