/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.scheduler;
import org.jnode.annotation.Inline;
import org.jnode.annotation.KernelSpace;
import org.jnode.annotation.Uninterruptible;
import org.jnode.vm.LoadCompileService;
import org.jnode.vm.Unsafe;
import org.jnode.vm.VmMagic;
import org.jnode.vm.VmStackReader;
/**
* This is the Kernel Debugger (also known as kdb).
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
* @author Fabien DUMINY (fduminy@jnode.org)
*
*/
public class KernelDebugger {
private final VmScheduler vmScheduler;
KernelDebugger(VmScheduler vmScheduler) {
this.vmScheduler = vmScheduler;
}
/**
* Process all waiting KDB commands.
*/
@Uninterruptible
@KernelSpace
@Inline
final void processAllKdbInput() {
int ch;
while ((ch = readKdbInput()) >= 0) {
processKdbInput(ch);
}
}
/**
* Process the input from the kernel debugger.
*
* @param input
* @throws org.vmmagic.pragma.UninterruptiblePragma
*/
@Uninterruptible
@KernelSpace
private final void processKdbInput(int input) {
switch ((char) input) {
case '?':
case 'h':
debug("Commands:\n");
debug("l Show Load/Compile queue\n");
debug("p Ping\n");
debug("q Print thread queues\n");
debug("r Print stacktraces of ready-queue\n");
debug("t Print current thread\n");
debug("v Verify thread\n");
debug("w Print waiting threads\n");
debug("W Print stacktraces of waiting threads\n");
break;
case 'l':
debug("<load-compile-service: ");
debug("\n");
LoadCompileService.showInfo();
debug("/>\n");
break;
case 'p':
debug("<ping/>");
break;
case 'q': {
final VmThread currentThread = VmMagic.currentProcessor().currentThread;
debug("<queues: current-thread name='");
debug(currentThread.getName());
debug("' state='");
debug(currentThread.getThreadStateName());
debug("\n");
vmScheduler.getReadyQueue().dump(false, null);
vmScheduler.getSleepQueue().dump(false, null);
debug("/>\n");
break;
}
case 'r':
debug("<traces: ");
debug("\n");
vmScheduler.getReadyQueue().dump(true, vmScheduler.getStackReader());
debug("/>\n");
break;
case 'v':
debug("<verify: ");
debug("\n");
verifyThreads();
debug("/>\n");
break;
case 'w':
debug("<waiting: ");
debug("\n");
dumpWaitingThreads(false, null);
debug("/>\n");
break;
case 'W':
debug("<waiting: ");
debug("\n");
dumpWaitingThreads(true, vmScheduler.getStackReader());
debug("/>\n");
break;
case 't': {
final VmThread currentThread = VmMagic.currentProcessor().currentThread;
debug("<currentthread name='");
debug(currentThread.getName());
debug("' state='");
debug(currentThread.getThreadStateName());
debug("'/>\n");
break;
}
case 'T': {
final VmThread currentThread = VmMagic.currentProcessor().currentThread;
debug("<currentthread name='");
debug(currentThread.getName());
debug("' state='");
debug(currentThread.getThreadStateName());
vmScheduler.getStackReader().debugStackTrace(currentThread);
debug("'/>\n");
break;
}
case '#':
debug("Halt for ever\n");
while (true)
;
// default:
// debug(input);
}
}
/**
* Dump the status of this queue on debug.
*/
@KernelSpace
private final void dumpWaitingThreads(boolean dumpStack, VmStackReader stackReader) {
VmThreadQueueEntry e = vmScheduler.getAllThreadsQueue().first;
while (e != null) {
if (e.thread.isWaiting()) {
debug(e.thread.getName());
debug(" id0x");
debug(e.thread.getId());
debug(" s0x");
debug(e.thread.getThreadState());
debug(" p0x");
debug(e.thread.priority);
debug(" wf:");
VmThread waitFor = e.thread.getWaitForThread();
debug((waitFor != null) ? waitFor.getName() : "none");
debug("\n");
if (dumpStack && (stackReader != null)) {
stackReader.debugStackTrace(e.thread);
debug("\n");
}
}
e = e.next;
}
}
/**
* Dump the status of this queue on debug.
*/
@KernelSpace
private final void verifyThreads() {
VmThreadQueueEntry e = vmScheduler.getAllThreadsQueue().first;
while (e != null) {
e.thread.verifyState();
e = e.next;
}
}
/**
* Print the given string to the output.
*/
@Inline
private final void debug(String str) {
Unsafe.debug(str);
}
/**
* Print the given integer to the output.
*/
@Inline
private final void debug(int i) {
Unsafe.debug(i);
}
/**
* Read a keystroke from the input.
*/
@Inline
private final int readKdbInput() {
return Unsafe.readKdbInput();
}
}