From 890ad257e1ef0a7d68718a0e32ff868f2a8d0649 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Mon, 30 Jan 2017 22:05:43 +0000
Subject: [PATCH] Router: Run shutdown tasks in parallel, increase max time for
 shutdown tasks (ticket #1893) i2psnark: Remove most delay between announces
 at shutdown

---
 .../src/org/klomp/snark/SnarkManager.java     | 15 ++++++--
 router/java/src/net/i2p/router/Router.java    | 35 +++++++++++++++----
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index fde46724b6..78dbdf30b5 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -42,6 +42,7 @@ import net.i2p.util.SecureDirectory;
 import net.i2p.util.SecureFileOutputStream;
 import net.i2p.util.SimpleTimer;
 import net.i2p.util.SimpleTimer2;
+import net.i2p.util.SystemVersion;
 import net.i2p.util.Translate;
 
 import org.klomp.snark.dht.DHT;
@@ -302,6 +303,8 @@ public class SnarkManager implements CompleteListener {
      *  Runs inline.
      */
     public void stop() {
+        if (_log.shouldWarn())
+            _log.warn("Snark stop() begin", new Exception("I did it"));
         if (_umgr != null && _uhandler != null) {
             //_uhandler.shutdown();
             _umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
@@ -312,6 +315,8 @@ public class SnarkManager implements CompleteListener {
         _connectionAcceptor.halt();
         _idleChecker.cancel();
         stopAllTorrents(true);
+        if (_log.shouldWarn())
+            _log.warn("Snark stop() end");
     }
     
     /** @since 0.9.1 */
@@ -2580,7 +2585,9 @@ public class SnarkManager implements CompleteListener {
                     stopTorrent(snark, false);
                 // Throttle since every unannounce is now threaded.
                 // How to do this without creating a ton of threads?
-                try { Thread.sleep(20); } catch (InterruptedException ie) {}
+                if (count % 8 == 0) {
+                    try { Thread.sleep(20); } catch (InterruptedException ie) {}
+                }
             }
         }
         if (_util.connected()) {
@@ -2593,8 +2600,12 @@ public class SnarkManager implements CompleteListener {
                 _context.simpleTimer2().addEvent(new Disconnector(), 60*1000);
                 addMessage(_t("Closing I2P tunnel after notifying trackers."));
                 if (finalShutdown) {
-                    try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
+                    long toWait = 5*1000;
+                    if (SystemVersion.isARM())
+                        toWait *= 2;
+                    try { Thread.sleep(toWait); } catch (InterruptedException ie) {}
                 }
+                _util.disconnect();
             } else {
                 _util.disconnect();
                 _stopping = false;
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index bdc107ff60..a45ab6d9d8 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -13,6 +13,7 @@ import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -121,6 +122,8 @@ public class Router implements RouterClock.ClockShiftListener {
     private static final String PROP_JBIGI = "jbigi.loadedResource";
     public static final String UPDATE_FILE = "i2pupdate.zip";
         
+    private static final int SHUTDOWN_WAIT_SECS = 60;
+
     private static final String originalTimeZoneID;
     static {
         //
@@ -955,8 +958,6 @@ public class Router implements RouterClock.ClockShiftListener {
         int bwLim = Math.min(_context.bandwidthLimiter().getInboundKBytesPerSecond(),
                              _context.bandwidthLimiter().getOutboundKBytesPerSecond());
         bwLim = (int)(bwLim * getSharePercentage());
-        if (_log.shouldLog(Log.INFO))
-            _log.info("Adding capabilities w/ bw limit @ " + bwLim, new Exception("caps"));
         
         String force = _context.getProperty(PROP_FORCE_BWCLASS);
         if (force != null && force.length() > 0) {
@@ -1210,6 +1211,7 @@ public class Router implements RouterClock.ClockShiftListener {
         I2PThread.removeOOMEventListener(_oomListener);
         // Run the shutdown hooks first in case they want to send some goodbye messages
         // Maybe we need a delay after this too?
+        LinkedList<Thread> tasks = new LinkedList<Thread>();
         for (Runnable task : _context.getShutdownTasks()) {
             //System.err.println("Running shutdown task " + task.getClass());
             if (_log.shouldLog(Log.WARN))
@@ -1219,15 +1221,34 @@ public class Router implements RouterClock.ClockShiftListener {
                 Thread t = new I2PAppThread(task, "Shutdown task " + task.getClass().getName());
                 t.setDaemon(true);
                 t.start();
-                try {
-                    t.join(10*1000);
-                } catch (InterruptedException ie) {}
-                if (t.isAlive())
-                    _log.logAlways(Log.WARN, "Shutdown task took more than 10 seconds to run: " + task.getClass());
+                tasks.add(t);
             } catch (Throwable t) {
                 _log.log(Log.CRIT, "Error running shutdown task", t);
             }
         }
+        long waitSecs = SHUTDOWN_WAIT_SECS;
+        if (SystemVersion.isARM())
+            waitSecs *= 2;
+        final long maxWait = System.currentTimeMillis() + (waitSecs *1000);
+        Thread th;
+        while ((th = tasks.poll()) != null) {
+            long toWait = maxWait - System.currentTimeMillis();
+            if (toWait <= 0) {
+                _log.logAlways(Log.WARN, "Shutdown tasks took more than " + waitSecs + " seconds to run");
+                tasks.clear();
+                break;
+            }
+            try {
+                th.join(toWait);
+            } catch (InterruptedException ie) {}
+            if (th.isAlive()) {
+                _log.logAlways(Log.WARN, "Shutdown task took more than " + waitSecs + " seconds to run: " + th.getName());
+                tasks.clear();
+                break;
+            } else if (_log.shouldInfo()) {
+                _log.info("Shutdown task complete: " + th.getName());
+            }
+        }
 
         // Set the last version to the current version, since 0.8.13
         if (!RouterVersion.VERSION.equals(_config.get("router.previousVersion"))) {
-- 
GitLab