diff --git a/apps/routerconsole/java/src/net/i2p/router/web/DeadlockDetector.java b/apps/routerconsole/java/src/net/i2p/router/web/DeadlockDetector.java index b2655a86c..7e6d345f9 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/DeadlockDetector.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/DeadlockDetector.java @@ -3,11 +3,15 @@ package net.i2p.router.web; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; +import java.util.concurrent.atomic.AtomicBoolean; +import net.i2p.app.ClientAppManager; +import net.i2p.app.NotificationService; import net.i2p.router.RouterContext; import net.i2p.router.util.EventLog; import net.i2p.util.Log; import net.i2p.util.SimpleTimer2; +import net.i2p.util.SystemVersion; /** * Periodic check @@ -16,14 +20,15 @@ import net.i2p.util.SimpleTimer2; * In routerconsole because java.lang.management is * not available in Android. * - * @since 0.9.55 + * @since 0.9.55, public since 0.9.56 */ -class DeadlockDetector extends SimpleTimer2.TimedEvent { +public class DeadlockDetector extends SimpleTimer2.TimedEvent { private final RouterContext _context; private final Log _log; private static final String PROP_INTERVAL = "router.deadlockDetectIntervalHours"; - private static final long DEFAULT_INTERVAL = 24; + private static final long DEFAULT_INTERVAL = SystemVersion.isSlow() ? 12 : 4; + private static final AtomicBoolean _isDeadlocked = new AtomicBoolean(); public DeadlockDetector(RouterContext ctx) { super(ctx.simpleTimer2()); @@ -58,6 +63,8 @@ class DeadlockDetector extends SimpleTimer2.TimedEvent { } public static boolean detect(RouterContext ctx) { + if (_isDeadlocked.get()) + return true; try { ThreadMXBean mxb = ManagementFactory.getThreadMXBean(); long[] ids = mxb.findDeadlockedThreads(); @@ -74,7 +81,8 @@ class DeadlockDetector extends SimpleTimer2.TimedEvent { infos = mxb.getThreadInfo(ids, Integer.MAX_VALUE); } StringBuilder buf = new StringBuilder(2048); - buf.append("Deadlock detected, please report\n\n"); + String msg1 = Messages.getString("Deadlock detected", ctx) + " - " + Messages.getString("Please report", ctx); + buf.append(msg1).append("\n\n"); for (int i = 0; i < infos.length; i++) { ThreadInfo info = infos[i]; if (info == null) @@ -88,10 +96,20 @@ class DeadlockDetector extends SimpleTimer2.TimedEvent { } buf.append('\n'); } - buf.append("\nAfter reporting, please restart your router!\n"); + String msg2 = Messages.getString("After reporting, please restart your router", ctx); + buf.append('\n').append(msg2).append('\n'); Log log = ctx.logManager().getLog(DeadlockDetector.class); log.log(Log.CRIT, buf.toString()); ctx.router().eventLog().addEvent(EventLog.DEADLOCK, infos.length + " threads"); + _isDeadlocked.set(true); + ClientAppManager cmgr = ctx.clientAppManager(); + if (cmgr != null) { + NotificationService ns = (NotificationService) cmgr.getRegisteredApp("desktopgui"); + if (ns != null) { + ns.notify("Router", null, Log.CRIT, Messages.getString("Router", ctx), + msg1 + '\n' + msg2, null); + } + } } catch (Throwable t) { // class not found, unsupportedoperation, ... Log log = ctx.logManager().getLog(DeadlockDetector.class); @@ -101,6 +119,15 @@ class DeadlockDetector extends SimpleTimer2.TimedEvent { return true; } + /** + * Return the results of the last test. Does not run a new test. + * + * @since 0.9.56 + */ + public static boolean isDeadlocked() { + return _isDeadlocked.get(); + } + /* public static void main(String[] args) { final Object o1 = new Object(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryHelper.java index cfa6ab0c8..5dab02a45 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryHelper.java @@ -26,6 +26,7 @@ import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.networkdb.reseed.ReseedChecker; import net.i2p.router.transport.TransportUtil; import net.i2p.router.web.CSSHelper; +import net.i2p.router.web.DeadlockDetector; import net.i2p.router.web.HelperBase; import net.i2p.router.web.NewsHelper; import net.i2p.router.web.WebAppStarter; @@ -951,6 +952,15 @@ public class SummaryHelper extends HelperBase { .append(""); } + if (DeadlockDetector.isDeadlocked()) { + buf.append("
") + .append(_t("Deadlock detected")) + .append(" - ") + .append(_t("Please report")) + .append(" - ").append(_t("After reporting, please restart your router")) + .append("
"); + } + ReseedChecker checker = _context.netDb().reseedChecker(); String status = checker.getStatus(); if (status.length() > 0) {