I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Unverified Commit 265804a7 authored by zzz's avatar zzz
Browse files

Console: Add deadlock detector

parent 74795a83
No related branches found
No related tags found
No related merge requests found
......@@ -277,6 +277,9 @@ public class ConfigServiceHandler extends FormHandler {
}
File wlog = wrapperLogFile(_context);
addFormNotice(_t("Threads dumped to {0}", wlog.getAbsolutePath()));
boolean deadlock = DeadlockDetector.detect(_context);
if (deadlock)
addFormErrorNoEscape("Deadlock detected!<br><a href=\"/logs\">Please report using the information on the logs page!</a><br>After reporting, please restart your router!");
} else if (_t("View console on startup").equals(_action)) {
browseOnStartup(true);
addFormNotice(_t("Console is to be shown on startup"));
......
package net.i2p.router.web;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
/**
* Periodic check
* ref: https://dzone.com/articles/how-detect-java-deadlocks
*
* In routerconsole because java.lang.management is
* not available in Android.
*
* @since 0.9.55
*/
class DeadlockDetector extends SimpleTimer2.TimedEvent {
private final I2PAppContext _context;
private final Log _log;
private static final String PROP_INTERVAL = "router.deadlockDetectIntervalHours";
private static final long DEFAULT_INTERVAL = 24;
public DeadlockDetector(I2PAppContext ctx) {
super(ctx.simpleTimer2());
_context = ctx;
_log = _context.logManager().getLog(DeadlockDetector.class);
long interval = getInterval();
if (interval > 0)
schedule(interval);
}
private long getInterval() {
long rv = _context.getProperty(PROP_INTERVAL, DEFAULT_INTERVAL);
return rv * 60*60*1000L;
}
public void timeReached() {
long start = System.currentTimeMillis();
boolean detected = detect();
if (!detected) {
long time = System.currentTimeMillis() - start;
if (_log.shouldDebug())
_log.debug("No deadlocks detected, took " + time + "ms");
long interval = getInterval();
if (interval > 0)
schedule(interval);
}
}
private boolean detect() {
return detect(_context);
}
public static boolean detect(I2PAppContext ctx) {
try {
ThreadMXBean mxb = ManagementFactory.getThreadMXBean();
long[] ids = mxb.findDeadlockedThreads();
if (ids == null)
return false;
ThreadInfo[] infos;
try {
// java 10
//infos = mxb.getThreadInfo(ids, true, true, Integer.MAX_VALUE);
// java 6
infos = mxb.getThreadInfo(ids, true, true);
} catch (UnsupportedOperationException e) {
// won't throw
infos = mxb.getThreadInfo(ids, Integer.MAX_VALUE);
}
StringBuilder buf = new StringBuilder(2048);
buf.append("Deadlock detected, please report\n\n");
for (int i = 0; i < infos.length; i++) {
ThreadInfo info = infos[i];
if (info == null)
continue;
buf.append("Thread ").append(i).append(':');
buf.append(info.toString());
StackTraceElement[] stes = info.getStackTrace();
buf.append(" Stack Trace:\n");
for (StackTraceElement ste : stes) {
buf.append(" at ").append(ste.toString()).append('\n');
}
buf.append('\n');
}
buf.append("\nAfter reporting, please restart your router!\n");
Log log = ctx.logManager().getLog(DeadlockDetector.class);
log.log(Log.CRIT, buf.toString());
} catch (Throwable t) {
// class not found, unsupportedoperation, ...
Log log = ctx.logManager().getLog(DeadlockDetector.class);
log.warn("fail", t);
return false;
}
return true;
}
/*
public static void main(String[] args) {
final Object o1 = new Object();
final Object o2 = new Object();
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized(o1) {
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
// should hang here
synchronized(o2) {
System.out.println("Test fail");
}
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
public void run() {
synchronized(o2) {
// should hang here
synchronized(o1) {
System.out.println("Test fail");
}
}
}
});
t2.start();
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
long start = System.currentTimeMillis();
boolean yes = detect(I2PAppContext.getGlobalContext());
if (!yes)
System.out.println("Test fail");
long time = System.currentTimeMillis() - start;
System.out.println("Test took " + time + "ms");
}
*/
}
......@@ -233,6 +233,7 @@ public class RouterConsoleRunner implements RouterApp {
checkJavaVersion();
startTrayApp();
startConsole();
new DeadlockDetector(_context);
}
/** @since 0.9.4 */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment