20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/Spinlock.h"
22#include "pedigree/kernel/debugger/commands/LocksCommand.h"
23#include "pedigree/kernel/linker/KernelElf.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/utilities/demangle.h"
34static bool g_bReady =
false;
36#define ERROR_OR_FATAL(x) \
51 for (
size_t i = 0; i < LOCKS_COMMAND_NUM_CPU; ++i) {
63 output +=
"Sorry, this kernel was not built with TRACK_LOCKS enabled.";
68 output +=
"Lock tracking has not yet been enabled.";
73 pScreen->disableCli();
77 resize(pScreen->
getWidth(), pScreen->getHeight() - 2);
78 setScrollKeys(
'j',
'k');
83 DebuggerIO::White, DebuggerIO::Green);
84 pScreen->
drawString(
"Pedigree debugger - Lock tracker", 0, 0, DebuggerIO::White,
87 pScreen->
drawString(
"backspace: Page up. space: Page down. q: Quit.", pScreen->getHeight() - 1, 0,
88 DebuggerIO::White, DebuggerIO::Green);
89 pScreen->
drawString(
"backspace", pScreen->getHeight() - 1, 0, DebuggerIO::Yellow,
91 pScreen->
drawString(
"space", pScreen->getHeight() - 1, 20, DebuggerIO::Yellow, DebuggerIO::Green);
92 pScreen->
drawString(
"q", pScreen->getHeight() - 1, 38, DebuggerIO::Yellow, DebuggerIO::Green);
101 while (!(in = pScreen->
getChar()))
107 if (
static_cast<ssize_t
>(m_SelectedLine) - 1 >= 0)
113 if (m_SelectedLine + 1 < getLineCount())
119 if (m_SelectedLine + 5 < getLineCount())
122 m_SelectedLine = getLineCount() - 1;
127 if (
static_cast<ssize_t
>(m_SelectedLine) - 5 >= 0)
142 pScreen->
drawString(
" ", 1, 0, DebuggerIO::White, DebuggerIO::Black);
155 LockDescriptor* pD = 0;
156 for (nCpu = 0; nCpu < LOCKS_COMMAND_NUM_CPU; ++nCpu) {
157 if (nLock++ == index) {
166 for (
size_t j = 0; j < MAX_DESCRIPTORS; ++j) {
167 pD = &m_pDescriptors[nCpu][j];
171 }
else if (nLock == index) {
184 if ((nLock - 1) > index) {
198 colour = DebuggerIO::White;
199 if (index == m_SelectedLine)
200 bgColour = DebuggerIO::Blue;
202 bgColour = DebuggerIO::Black;
207const char* LocksCommand::getLine2(
size_t index,
size_t& colOffset,
DebuggerIO::Colour& colour,
215 LockDescriptor* pD = 0;
216 bool doBacktrace =
false;
217 for (nCpu = 0; nCpu < LOCKS_COMMAND_NUM_CPU; ++nCpu) {
222 if (nLock++ == index) {
227 for (
size_t j = 0; j < MAX_DESCRIPTORS; ++j) {
228 pD = &m_pDescriptors[nCpu][j];
233 if (nLock == index) {
250 colOffset = nDepth + 3;
253 Line.append(
reinterpret_cast<uintptr_t
>(pD->pLock), 16);
255 Line += stateName(pD->state);
257 Line.append(pD->pLock->acquisitionAddress(), 16);
260 uintptr_t symStart = 0;
270 Line +=
static_cast<const char*
>(
symbol.name);
275 colour = DebuggerIO::White;
276 if (index == m_SelectedLine)
277 bgColour = DebuggerIO::Blue;
279 bgColour = DebuggerIO::Black;
284size_t LocksCommand::getLineCount() {
286 for (
size_t i = 0; i < LOCKS_COMMAND_NUM_CPU; ++i) {
299void LocksCommand::setReady() {
307void LocksCommand::clearFatal() {
311bool LocksCommand::lockAttempted(
const Spinlock* pLock,
size_t nCpu,
bool intState) {
314 if (pLock->m_bAvoidTracking)
320 if (pos > MAX_DESCRIPTORS) {
321 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" ran out of room for locks [" <<
Dec << pos
326 if (pos && intState) {
328 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" attempted at level " <<
Dec << pos <<
Hex
329 <<
" with interrupts enabled on CPU" <<
Dec << nCpu <<
".");
333 LockDescriptor* pD = &m_pDescriptors[nCpu][pos];
336 ERROR_OR_FATAL(
"LocksCommand tracking state is corrupt.");
349bool LocksCommand::lockAcquired(
const Spinlock* pLock,
size_t nCpu,
bool intState) {
352 if (pLock->m_bAvoidTracking)
358 if (back > MAX_DESCRIPTORS) {
359 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" acquired unexpectedly (no tracked locks).");
363 if (back && intState) {
365 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" acquired at level " <<
Dec << back <<
Hex
366 <<
" with interrupts enabled on CPU" <<
Dec << nCpu <<
".");
370 LockDescriptor* pD = &m_pDescriptors[nCpu][back];
372 if (pD->state !=
Attempted || pD->pLock != pLock) {
373 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" acquired unexpectedly.");
385 if (pLock->m_bAvoidTracking)
394 if (pD->state !=
Acquired || pD->pLock != pLock) {
398 for (
size_t i = 0; i < LOCKS_COMMAND_NUM_CPU; ++i) {
403 if (back < MAX_DESCRIPTORS) {
405 if (pCheckD->state ==
Acquired && pCheckD->pLock == pLock) {
415 ERROR_OR_FATAL(
"Spinlock " <<
Hex << pLock <<
" released out-of-order [expected lock "
416 << (pD ? pD->pLock : 0) << (pD ?
"" :
" (no lock)") <<
", state "
417 << (pD ? stateName(pD->state) :
"(no state)") <<
"].");
439 ERROR_NOLOCK(
"Reschedule retained lock "
440 <<
Hex << retained.pLock <<
" acquired at "
441 << (retained.pLock ? retained.pLock->acquisitionAddress() : 0)
442 <<
", schedule caller "
443 <<
reinterpret_cast<uintptr_t
>(__builtin_return_address(0)));
444 ERROR_OR_FATAL(
"Rescheduling CPU" << nCpu <<
" is not allowed, as there are still " << pos
445 <<
" acquired locks.");
455 if (pLock->m_bAvoidTracking)
463 while (!m_bAcquiring.compareAndSwap(
false,
true))
467 for (
size_t i = 0; i < LOCKS_COMMAND_NUM_CPU; ++i) {
471 bool foundLock =
false;
474 pD = &m_pDescriptors[i][j];
480 if (pD->pLock == pLock && pD->state ==
Acquired) {
486 if (!foundLock || !pD || pD->pLock == pLock) {
501 if (pMyD->pLock == pD->pLock && pMyD->state ==
Acquired) {
504 ERROR_OR_FATAL(
"Detected lock dependency inversion (deadlock) between "
505 <<
Hex << pLock <<
" and " << pD->pLock <<
"!");
513 m_bAcquiring =
false;
virtual void enableCli()=0
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
virtual size_t getWidth()=0
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0
static KernelElf & instance()
uintptr_t globalLookupSymbol(const char *pName)
bool checkState(const Spinlock *pLock, size_t nCpu=~0U)
bool checkSchedule(size_t nCpu=~0U)
Atomic< uint8_t > m_NextPosition[LOCKS_COMMAND_NUM_CPU]
void autocomplete(const HugeStaticString &input, HugeStaticString &output)
@ Inactive
This entry is no longer active.
@ Attempted
The lock is about to be attempted.
@ Acquired
The lock is acquired.
bool lockReleased(const Spinlock *pLock, size_t nCpu=~0U)
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)