From 67825a766822b4c1f9f997abfb93707b0f9e7845 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 18 Jun 2011 17:01:15 +0000 Subject: [PATCH] * Shutdown: - Add final shutdown hook --- router/java/src/net/i2p/router/Router.java | 22 +++++++++++++++- .../src/net/i2p/router/RouterContext.java | 25 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index a2e903593..d8836e3c4 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -193,8 +193,16 @@ public class Router { // Make darn sure we don't have a leftover I2PAppContext in the same JVM // e.g. on Android - see finalShutdown() also - if (RouterContext.getContexts().isEmpty()) + List contexts = RouterContext.getContexts(); + if (contexts.isEmpty()) { RouterContext.killGlobalContext(); + } else if (System.getProperty("java.vendor").contains("Android")) { + System.err.println("Warning: Killing " + contexts.size() + " other routers in this JVM"); + contexts.clear(); + RouterContext.killGlobalContext(); + } else { + System.err.println("Warning: " + contexts.size() + " other routers in this JVM"); + } // The important thing that happens here is the directory paths are set and created // i2p.dir.router defaults to i2p.dir.config @@ -1031,6 +1039,18 @@ public class Router { f.delete(); if (RouterContext.getContexts().isEmpty()) RouterContext.killGlobalContext(); + + // Since 0.8.8, mainly for Android + for (Runnable task : _context.getFinalShutdownTasks()) { + System.err.println("Running final shutdown task " + task.getClass()); + try { + task.run(); + } catch (Throwable t) { + System.err.println("Running final shutdown task " + t); + } + } + _context.getFinalShutdownTasks().clear(); + if (_killVMOnEnd) { try { Thread.sleep(1000); } catch (InterruptedException ie) {} Runtime.getRuntime().halt(exitCode); diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index 985f6df4b..77d33b725 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import net.i2p.I2PAppContext; import net.i2p.data.Hash; @@ -56,6 +58,7 @@ public class RouterContext extends I2PAppContext { private MessageValidator _messageValidator; private MessageStateMonitor _messageStateMonitor; private RouterThrottle _throttle; + private final Set _finalShutdownTasks; private static List _contexts = new ArrayList(1); @@ -69,8 +72,9 @@ public class RouterContext extends I2PAppContext { // Sorry, this breaks some main() unit tests out there. //initAll(); if (!_contexts.isEmpty()) - System.out.println("Warning - More than one router in this JVM"); + System.err.println("Warning - More than one router in this JVM"); _contexts.add(this); + _finalShutdownTasks = new CopyOnWriteArraySet(); } /** @@ -438,6 +442,25 @@ public class RouterContext extends I2PAppContext { _shutdownTasks.clear(); } + /** + * The last thing to be called before router shutdown. + * No context resources, including logging, will be available. + * Only for external threads in the same JVM needing to know when + * the shutdown is complete, like Android. + * @since 0.8.8 + */ + public void addFinalShutdownTask(Runnable task) { + _finalShutdownTasks.add(task); + } + + /** + * @return the Set + * @since 0.8.8 + */ + Set getFinalShutdownTasks() { + return _finalShutdownTasks; + } + /** * Use this instead of context instanceof RouterContext * @return true