Changeset 81beb63


Ignore:
Timestamp:
Jun 30, 2011 12:27:00 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
4f5e3401
Parents:
3a2e9ad (diff), f854ac0 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p.zzz.android' (head cbf2d39e1944b9d601558761d0eedcdebfd2f589)

to branch 'i2p.i2p' (head c2393e50afccfd5682a9086f0eec2a0700cda2c9)

Files:
53 edited

Legend:

Unmodified
Added
Removed
  • apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java

    r3a2e9ad r81beb63  
    3333 *
    3434 */
    35 class DaemonThread extends Thread implements NamingServiceUpdater {
     35public class DaemonThread extends Thread implements NamingServiceUpdater {
    3636
    3737    private String[] args;
  • apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java

    r3a2e9ad r81beb63  
    2525import java.util.List;
    2626import java.util.Random;
    27 import java.util.TimerTask;
    2827
    2928import net.i2p.I2PAppContext;
     
    3332 * with the PeerCoordinator to select which Peers get (un)choked.
    3433 */
    35 class PeerCheckerTask extends TimerTask
     34class PeerCheckerTask implements Runnable
    3635{
    3736  private static final long KILOPERSECOND = 1024*(PeerCoordinator.CHECK_PERIOD/1000);
     
    5554        if (peerList.isEmpty() || coordinator.halted()) {
    5655          coordinator.setRateHistory(0, 0);
    57           if (coordinator.halted())
    58             cancel();
    5956          return;
    6057        }
  • apps/i2psnark/java/src/org/klomp/snark/PeerMonitorTask.java

    r3a2e9ad r81beb63  
    2222
    2323import java.util.Iterator;
    24 import java.util.TimerTask;
    2524
    2625import net.i2p.data.DataHelper;
     
    3029 * Works together with the main Snark class to report periodical statistics.
    3130 */
    32 class PeerMonitorTask extends TimerTask
     31class PeerMonitorTask implements Runnable
    3332{
    3433  final static long MONITOR_PERIOD = 10 * 1000; // Ten seconds.
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    r3a2e9ad r81beb63  
    3333import java.util.Random;
    3434import java.util.StringTokenizer;
    35 import java.util.Timer;
    36 import java.util.TimerTask;
    3735
    3836import net.i2p.I2PAppContext;
  • apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java

    r3a2e9ad r81beb63  
    4949    private /* FIXME final FIXME */ File _configFile;
    5050    private Properties _config;
    51     private I2PAppContext _context;
    52     private Log _log;
     51    private final I2PAppContext _context;
     52    private final Log _log;
    5353    private final List _messages;
    54     private I2PSnarkUtil _util;
     54    private final I2PSnarkUtil _util;
    5555    private PeerCoordinatorSet _peerCoordinatorSet;
    5656    private ConnectionAcceptor _connectionAcceptor;
    5757    private Thread _monitor;
    58     private boolean _running;
     58    private volatile boolean _running;
    5959   
    6060    public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
     
    10901090            getBWLimit();
    10911091            boolean doMagnets = true;
    1092             while (true) {
     1092            while (_running) {
    10931093                File dir = getDataDir();
    10941094                if (_log.shouldLog(Log.DEBUG))
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java

    r3a2e9ad r81beb63  
    234234        // Overridden in I2PTunnelHTTPServer, where it does not use the client pool.
    235235        try {
    236             I2PTunnelClientBase._executor.execute(new Pusher(pi, out));
     236            I2PTunnelClientBase.getClientExecutor().execute(new Pusher(pi, out));
    237237        } catch (RejectedExecutionException ree) {
    238238            // shouldn't happen
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java

    r3a2e9ad r81beb63  
    7474 */
    7575public class I2PTunnel implements Logging, EventDispatcher {
    76     private Log _log;
    77     private EventDispatcherImpl _event;
    78     private I2PAppContext _context;
     76    private final Log _log;
     77    private final EventDispatcherImpl _event;
     78    private final I2PAppContext _context;
    7979    private static long __tunnelId = 0;
    80     private long _tunnelId;
    81     private Properties _clientOptions;
     80    private final long _tunnelId;
     81    private final Properties _clientOptions;
    8282    private final List<I2PSession> _sessions;
    8383
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java

    r3a2e9ad r81beb63  
    8484     *  Not for use by servers, as there is no limit on threads.
    8585     */
    86     static final Executor _executor;
     86    private static volatile ThreadPoolExecutor _executor;
    8787    private static int _executorThreadCount;
    88     static {
    89         _executor = new CustomThreadPoolExecutor();
    90     }
    9188
    9289    public I2PTunnelClientBase(int localPort, Logging l, I2PSocketManager sktMgr,
     
    108105        _log = _context.logManager().getLog(getClass());
    109106
     107        synchronized (I2PTunnelClientBase.class) {
     108            if (_executor == null)
     109                _executor = new CustomThreadPoolExecutor();
     110        }
     111
    110112        Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
    111113        listenerReady = false;
     
    160162        _context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    161163        _log = _context.logManager().getLog(getClass());
     164
     165        synchronized (I2PTunnelClientBase.class) {
     166            if (_executor == null)
     167                _executor = new CustomThreadPoolExecutor();
     168        }
    162169
    163170        // normalize path so we can find it
     
    553560
    554561    /**
     562     *  @return may be null if no class has been instantiated
     563     *  @since 0.8.8
     564     */
     565    static ThreadPoolExecutor getClientExecutor() {
     566        return _executor;
     567    }
     568
     569    /**
     570     *  @since 0.8.8
     571     */
     572    static void killClientExecutor() {
     573        synchronized (I2PTunnelClientBase.class) {
     574            if (_executor != null) {
     575                _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
     576                _executor.shutdownNow();
     577                _executor = null;
     578            }
     579            // kill the shared client, so that on restart in android
     580            // we won't latch onto the old one
     581            socketManager = null;
     582        }
     583    }
     584
     585    /**
    555586     * Manage the connection just opened on the specified socket
    556587     *
     
    559590    protected void manageConnection(Socket s) {
    560591        if (s == null) return;
     592        ThreadPoolExecutor tpe = _executor;
     593        if (tpe == null) {
     594            _log.error("No executor for socket!");
     595             try {
     596                 s.close();
     597             } catch (IOException ioe) {}
     598            return;
     599        }
    561600        try {
    562             _executor.execute(new BlockingRunner(s));
     601            tpe.execute(new BlockingRunner(s));
    563602        } catch (RejectedExecutionException ree) {
    564603             // should never happen, we have an unbounded pool and never stop the executor
     
    636675            //l.log("Client closed.");
    637676        }
    638        
    639677        return true;
    640678    }
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java

    r3a2e9ad r81beb63  
    6868    protected I2PTunnelTask task = null;
    6969    protected boolean bidir = false;
     70    private ThreadPoolExecutor _executor;
    7071
    7172    private int DEFAULT_LOCALPORT = 4488;
     
    260261            //l.log("Server shut down.");
    261262            open = false;
     263            if (_usePool && _executor != null) {
     264                _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
     265                _executor.shutdownNow();
     266            }
    262267            return true;
    263268        }
     
    284289    public void run() {
    285290        I2PServerSocket i2pS_S = sockMgr.getServerSocket();
    286         ThreadPoolExecutor executor = null;
    287291        if (_log.shouldLog(Log.WARN)) {
    288292            if (_usePool)
     
    292296        }
    293297        if (_usePool) {
    294             executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
     298            _executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
    295299        }
    296300        while (open) {
     
    300304                if (_usePool) {
    301305                    try {
    302                         executor.execute(new Handler(i2ps));
     306                        _executor.execute(new Handler(i2ps));
    303307                    } catch (RejectedExecutionException ree) {
    304308                         try {
     
    329333            }
    330334        }
    331         if (executor != null)
    332             executor.shutdownNow();
     335        if (_executor != null)
     336            _executor.shutdownNow();
    333337    }
    334338   
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java

    r3a2e9ad r81beb63  
    2727 */
    2828public class TunnelControllerGroup {
    29     private final Log _log;
     29    private Log _log;
    3030    private static TunnelControllerGroup _instance;
    3131    static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config";
     
    5656        _sessions = new HashMap(4);
    5757        loadControllers(_configFile);
     58        I2PAppContext.getGlobalContext().addShutdownTask(new Shutdown());
    5859    }
    5960
     
    7172            }
    7273        }
     74    }
     75
     76    /**
     77     *  Warning - destroys the singleton!
     78     *  @since 0.8.8
     79     */
     80    private static class Shutdown implements Runnable {
     81        public void run() {
     82            shutdown();
     83        }
     84    }
     85
     86    /**
     87     *  Warning - destroys the singleton!
     88     *  Caller must root a new context before calling instance() or main() again.
     89     *  Agressively kill and null everything to reduce memory usage in the JVM
     90     *  after stopping, and to recognize what must be reinitialized on restart (Android)
     91     *
     92     *  @since 0.8.8
     93     */
     94    public static void shutdown() {
     95        synchronized (TunnelControllerGroup.class) {
     96            if (_instance == null) return;
     97            _instance.unloadControllers();
     98            _instance._log = null;
     99            _instance = null;
     100        }
     101        I2PTunnelClientBase.killClientExecutor();
    73102    }
    74103   
  • apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java

    r3a2e9ad r81beb63  
    3838    private File _tempFile;
    3939    private static NewsFetcher _instance;
     40    private volatile boolean _isRunning;
     41
    4042    //public static final synchronized NewsFetcher getInstance() { return _instance; }
    4143    public static final synchronized NewsFetcher getInstance(I2PAppContext ctx) {
     
    6567        updateLastFetched();
    6668        _updateVersion = "";
    67     }
    68    
     69        _isRunning = true;
     70    }
     71   
     72    /** @since 0.8.8 */
     73    void shutdown() {
     74        _isRunning = false;
     75    }
     76
    6977    private void updateLastFetched() {
    7078        if (_newsFile.exists()) {
     
    109117    public void run() {
    110118        try { Thread.sleep(INITIAL_DELAY + _context.random().nextLong(INITIAL_DELAY)); } catch (InterruptedException ie) {}
    111         while (true) {
     119        while (_isRunning) {
    112120            if (!_updateAvailable) checkForUpdates();
    113121            if (shouldFetchNews()) {
  • apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java

    r3a2e9ad r81beb63  
    343343
    344344        NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
    345         Thread t = new I2PAppThread(fetcher, "NewsFetcher", true);
    346         t.start();
     345        Thread newsThread = new I2PAppThread(fetcher, "NewsFetcher", true);
     346        newsThread.start();
    347347       
    348         t = new I2PAppThread(new StatSummarizer(), "StatSummarizer", true);
     348        Thread t = new I2PAppThread(new StatSummarizer(), "StatSummarizer", true);
    349349        t.start();
    350350       
     
    357357                ctx.addShutdownTask(new PluginStopper(ctx));
    358358            }
     359            ctx.addShutdownTask(new NewsShutdown(fetcher, newsThread));
     360            // stat summarizer registers its own hook
     361            ctx.addShutdownTask(new ServerShutdown());
    359362        }
    360363    }
     
    496499    }
    497500   
    498 /*******
    499     public void stopConsole() {
    500         try {
    501             _server.stop();
    502         } catch (InterruptedException ie) {
    503             ie.printStackTrace();
    504         }
    505     }
    506 ********/
    507    
     501    /** @since 0.8.8 */
     502    private class ServerShutdown implements Runnable {
     503        public void run() {
     504            try {
     505                _server.stop();
     506            } catch (InterruptedException ie) {}
     507        }
     508    }
     509   
     510    /** @since 0.8.8 */
     511    private static class NewsShutdown implements Runnable {
     512        private final NewsFetcher _fetcher;
     513        private final Thread _newsThread;
     514
     515        public NewsShutdown(NewsFetcher fetcher, Thread t) {
     516            _fetcher = fetcher;
     517            _newsThread = t;
     518        }
     519
     520        public void run() {
     521            _fetcher.shutdown();
     522            _newsThread.interrupt();
     523        }
     524    }
     525
    508526    public static Properties webAppProperties() {
    509527        return webAppProperties(I2PAppContext.getGlobalContext().getConfigDir().getAbsolutePath());
  • core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java

    r3a2e9ad r81beb63  
    33import java.util.HashMap;
    44import java.util.Map;
     5import java.util.concurrent.LinkedBlockingQueue;
    56
    67import net.i2p.I2PAppContext;
     
    1112 * filled buffer segments rather than one buffer (and blocking when that buffer's data
    1213 * has been eaten)
     14 *
     15 * Note that this class is not fully Thread safe!
     16 * The following methods must be synchronized externally, they are not
     17 * sycned here or in super():
     18 *   addRandomByte(), addRandomBytes(), nextByte(), nextBytes(), seed()
     19 *
    1320 */
    1421public class AsyncFortunaStandalone extends FortunaStandalone implements Runnable {
     
    2027    private static final int DEFAULT_BUFSIZE = 256*1024;
    2128    private final int _bufferCount;
    22     private final byte asyncBuffers[][];
    23     private final int status[];
    24     private int nextBuf = 0;
     29    private final int _bufferSize;
     30    /** the lock */
     31    private final Object asyncBuffers = new Object();
    2532    private final I2PAppContext _context;
    2633    private final Log _log;
    27 
    28     private static final int STATUS_NEED_FILL = 0;
    29     private static final int STATUS_FILLING = 1;
    30     private static final int STATUS_FILLED = 2;
    31     private static final int STATUS_LIVE = 3;
    32    
     34    private volatile boolean _isRunning;
     35    private Thread _refillThread;
     36    private final LinkedBlockingQueue<AsyncBuffer> _fullBuffers;
     37    private final LinkedBlockingQueue<AsyncBuffer> _emptyBuffers;
     38    private AsyncBuffer _currentBuffer;
     39
    3340    public AsyncFortunaStandalone(I2PAppContext context) {
    3441        super();
    3542        _bufferCount = Math.max(context.getProperty("prng.buffers", DEFAULT_BUFFERS), 2);
    36         int bufferSize = Math.max(context.getProperty("prng.bufferSize", DEFAULT_BUFSIZE), 16*1024);
    37         asyncBuffers = new byte[_bufferCount][bufferSize];
    38         status = new int[_bufferCount];
    39         for (int i = 0; i < _bufferCount; i++)
    40             status[i] = STATUS_NEED_FILL;
     43        _bufferSize = Math.max(context.getProperty("prng.bufferSize", DEFAULT_BUFSIZE), 16*1024);
     44        _emptyBuffers = new LinkedBlockingQueue(_bufferCount);
     45        _fullBuffers = new LinkedBlockingQueue(_bufferCount);
    4146        _context = context;
    4247        context.statManager().createRequiredRateStat("prng.bufferWaitTime", "Delay for random number buffer (ms)", "Encryption", new long[] { 60*1000, 10*60*1000, 60*60*1000 } );
     
    4651   
    4752    public void startup() {
    48         Thread refillThread = new Thread(this, "PRNG");
    49         refillThread.setDaemon(true);
    50         refillThread.setPriority(Thread.MIN_PRIORITY+1);
    51         refillThread.start();
     53        for (int i = 0; i < _bufferCount; i++)
     54            _emptyBuffers.offer(new AsyncBuffer(_bufferSize));
     55        _isRunning = true;
     56        _refillThread = new Thread(this, "PRNG");
     57        _refillThread.setDaemon(true);
     58        _refillThread.setPriority(Thread.MIN_PRIORITY+1);
     59        _refillThread.start();
     60    }
     61
     62    /**
     63     *  Note - methods may hang or NPE or throw IllegalStateExceptions after this
     64     *  @since 0.8.8
     65     */
     66    public void shutdown() {
     67        _isRunning = false;
     68        _emptyBuffers.clear();
     69        _fullBuffers.clear();
     70        _refillThread.interrupt();
     71        // unsynchronized to avoid hanging, may NPE elsewhere
     72        _currentBuffer = null;
     73        buffer = null;
    5274    }
    5375
     
    6486    protected void allocBuffer() {}
    6587   
     88    private static class AsyncBuffer {
     89        public final byte[] buffer;
     90
     91        public AsyncBuffer(int size) {
     92            buffer = new byte[size];
     93        }
     94    }
     95
    6696    /**
    6797     * make the next available filled buffer current, scheduling any unfilled
     
    70100    protected void rotateBuffer() {
    71101        synchronized (asyncBuffers) {
    72             // wait until we get some filled
     102            AsyncBuffer old = _currentBuffer;
     103            if (old != null)
     104                _emptyBuffers.offer(old);
    73105            long before = System.currentTimeMillis();
    74             long waited = 0;
    75             while (status[nextBuf] != STATUS_FILLED) {
    76                 //System.out.println(Thread.currentThread().getName() + ": Next PRNG buffer "
    77                 //                   + nextBuf + " isn't ready (" + status[nextBuf] + ")");
    78                 //new Exception("source").printStackTrace();
    79                 asyncBuffers.notifyAll();
     106            AsyncBuffer nextBuffer = null;
     107
     108            while (nextBuffer == null) {
     109                if (!_isRunning)
     110                    throw new IllegalStateException("shutdown");
    80111                try {
    81                     asyncBuffers.wait();
    82                 } catch (InterruptedException ie) {}
    83                 waited = System.currentTimeMillis()-before;
     112                    nextBuffer = _fullBuffers.take();
     113                } catch (InterruptedException ie) {
     114                    continue;
     115                }
    84116            }
     117            long waited = System.currentTimeMillis()-before;
    85118            _context.statManager().addRateData("prng.bufferWaitTime", waited, 0);
    86119            if (waited > 10*1000 && _log.shouldLog(Log.WARN))
    87120                _log.warn(Thread.currentThread().getName() + ": Took " + waited
    88121                                   + "ms for a full PRNG buffer to be found");
    89             //System.out.println(Thread.currentThread().getName() + ": Switching to prng buffer " + nextBuf);
    90             buffer = asyncBuffers[nextBuf];
    91             status[nextBuf] = STATUS_LIVE;
    92             int prev=nextBuf-1;
    93             if (prev<0)
    94                 prev = _bufferCount-1;
    95             if (status[prev] == STATUS_LIVE)
    96                 status[prev] = STATUS_NEED_FILL;
    97             nextBuf++;
    98             if (nextBuf >= _bufferCount)
    99                 nextBuf = 0;
    100             asyncBuffers.notify();
     122            _currentBuffer = nextBuffer;
     123            buffer = nextBuffer.buffer;
    101124        }
    102125    }
    103126   
     127    /**
     128     *  The refiller thread
     129     */
    104130    public void run() {
    105         while (true) {
    106             int toFill = -1;
     131        while (_isRunning) {
     132            AsyncBuffer aBuff = null;
    107133            try {
    108                 synchronized (asyncBuffers) {
    109                     for (int i = 0; i < _bufferCount; i++) {
    110                         if (status[i] == STATUS_NEED_FILL) {
    111                             status[i] = STATUS_FILLING;
    112                             toFill = i;
    113                             break;
    114                         }
    115                     }
    116                     if (toFill == -1) {
    117                         //System.out.println(Thread.currentThread().getName() + ": All pending buffers full");
    118                         asyncBuffers.wait();
    119                     }
    120                 }
    121             } catch (InterruptedException ie) {}
     134                aBuff = _emptyBuffers.take();
     135            } catch (InterruptedException ie) {
     136                continue;
     137            }
    122138           
    123             if (toFill != -1) {
    124                 //System.out.println(Thread.currentThread().getName() + ": Filling prng buffer " + toFill);
    125139                long before = System.currentTimeMillis();
    126                 doFill(asyncBuffers[toFill]);
     140                doFill(aBuff.buffer);
    127141                long after = System.currentTimeMillis();
    128                 synchronized (asyncBuffers) {
    129                     status[toFill] = STATUS_FILLED;
    130                     //System.out.println(Thread.currentThread().getName() + ": Prng buffer " + toFill + " filled after " + (after-before));
    131                     asyncBuffers.notifyAll();
    132                 }
     142                _fullBuffers.offer(aBuff);
    133143                _context.statManager().addRateData("prng.bufferFillTime", after - before, 0);
    134144                Thread.yield();
     
    137147                    waitTime = 50;
    138148                try { Thread.sleep(waitTime); } catch (InterruptedException ie) {}
    139             }
    140149        }
    141150    }
  • core/java/src/net/i2p/I2PAppContext.java

    r3a2e9ad r81beb63  
    22
    33import java.io.File;
     4import java.util.Collections;
    45import java.util.HashSet;
    56import java.util.Properties;
     
    101102    private volatile boolean _keyGeneratorInitialized;
    102103    protected volatile boolean _keyRingInitialized; // used in RouterContext
    103     private Set<Runnable> _shutdownTasks;
     104    protected final Set<Runnable> _shutdownTasks;
    104105    private File _baseDir;
    105106    private File _configDir;
     
    115116     * the first one created.
    116117     *
     118     * Warning - do not save the returned value, or the value of any methods below,
     119     * in a static field, or you will get the old context if a new router is
     120     * started in the same JVM after the first is shut down,
     121     * e.g. on Android.
    117122     */
    118123    public static I2PAppContext getGlobalContext() {
     
    165170        if (doInit) {
    166171            synchronized (I2PAppContext.class) {
    167                 if (_globalAppContext == null)
     172                if (_globalAppContext == null) {
    168173                    _globalAppContext = this;
     174                } else {
     175                    System.out.println("Warning - New context not replacing old one, you now have a second one");
     176                    (new Exception("I did it")).printStackTrace();
     177                }
    169178            }
    170179        }
     
    186195        _logManagerInitialized = false;
    187196        _keyRingInitialized = false;
    188         _shutdownTasks = new ConcurrentHashSet(0);
     197        _shutdownTasks = new ConcurrentHashSet(32);
    189198        initializeDirs();
    190199    }
     
    844853    }
    845854
     855    /**
     856     *  WARNING - Shutdown tasks are not executed in an I2PAppContext.
     857     *  You must be in a RouterContext for the tasks to be executed
     858     *  at shutdown.
     859     *  This method moved from Router in 0.7.1 so that clients
     860     *  may use it without depending on router.jar.
     861     *  @since 0.7.1
     862     */
    846863    public void addShutdownTask(Runnable task) {
    847864        _shutdownTasks.add(task);
    848865    }
    849866   
     867    /**
     868     *  @return an unmodifiable Set
     869     *  @since 0.7.1
     870     */
    850871    public Set<Runnable> getShutdownTasks() {
    851         return new HashSet(_shutdownTasks);
     872        return Collections.unmodifiableSet(_shutdownTasks);
    852873    }
    853874   
  • core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java

    r3a2e9ad r81beb63  
    4848 */
    4949public class DHSessionKeyBuilder {
    50     private static final I2PAppContext _context = I2PAppContext.getGlobalContext();
    51     private static final Log _log;
     50    private static I2PAppContext _context = I2PAppContext.getGlobalContext();
     51    private static Log _log;
    5252    private static final int MIN_NUM_BUILDERS;
    5353    private static final int MAX_NUM_BUILDERS;
    5454    private static final int CALC_DELAY;
    5555    private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
    56     private static final Thread _precalcThread;
     56    private static Thread _precalcThread;
     57    private static volatile boolean _isRunning;
    5758
    5859    // the data of importance
     
    9798            _log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
    9899                       + CALC_DELAY + ")");
    99 
    100         _precalcThread = new I2PThread(new DHSessionKeyBuilderPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS));
    101         _precalcThread.setName("DH Precalc");
    102         _precalcThread.setDaemon(true);
     100        startPrecalc();
     101    }
     102
     103    /**
     104     * Caller must synch on class
     105     * @since 0.8.8
     106     */
     107    private static void startPrecalc() {
     108        _context = I2PAppContext.getGlobalContext();
     109        _log = _context.logManager().getLog(DHSessionKeyBuilder.class);
     110        _precalcThread = new I2PThread(new DHSessionKeyBuilderPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS),
     111                                       "DH Precalc", true);
    103112        _precalcThread.setPriority(Thread.MIN_PRIORITY);
     113        _isRunning = true;
    104114        _precalcThread.start();
     115    }
     116
     117    /**
     118     *  Note that this stops the singleton precalc thread.
     119     *  You don't want to do this if there are multiple routers in the JVM.
     120     *  Fix this if you care. See Router.shutdown().
     121     *  @since 0.8.8
     122     */
     123    public static void shutdown() {
     124        _isRunning = false;
     125        _precalcThread.interrupt();
     126        _builders.clear();
     127    }
     128
     129    /**
     130     *  Only required if shutdown() previously called.
     131     *  @since 0.8.8
     132     */
     133    public static void restart() {
     134        synchronized(DHSessionKeyBuilder.class) {
     135            if (!_isRunning)
     136                startPrecalc();
     137        }
    105138    }
    106139
     
    476509       
    477510        public void run() {
    478             while (true) {
     511            while (_isRunning) {
    479512
    480513                int curSize = 0;
  • core/java/src/net/i2p/crypto/ElGamalEngine.java

    r3a2e9ad r81beb63  
    7979
    8080   
     81    /**
     82     *  Note that this stops the singleton precalc thread.
     83     *  You don't want to do this if there are multiple routers in the JVM.
     84     *  Fix this if you care. See Router.shutdown().
     85     *  @since 0.8.8
     86     */
     87    public void shutdown() {
     88        YKGenerator.shutdown();
     89    }
     90
     91    /**
     92     *  Only required if shutdown() previously called.
     93     *  @since 0.8.8
     94     */
     95    public static void restart() {
     96        YKGenerator.restart();
     97    }
     98
    8199    private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
    82100
  • core/java/src/net/i2p/crypto/YKGenerator.java

    r3a2e9ad r81beb63  
    4343    private static final int CALC_DELAY;
    4444    private static final LinkedBlockingQueue<BigInteger[]> _values;
    45     private static final Thread _precalcThread;
    46     private static final I2PAppContext ctx;
     45    private static Thread _precalcThread;
     46    private static I2PAppContext ctx;
     47    private static volatile boolean _isRunning;
    4748
    4849    public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min";
     
    7677        //               + CALC_DELAY + ")");
    7778
     79        startPrecalc();
     80    }
     81
     82    /**
     83     * Caller must synch on class
     84     * @since 0.8.8
     85     */
     86    private static void startPrecalc() {
     87        ctx = I2PAppContext.getGlobalContext();
    7888        ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 });
    7989        ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 });
    80 
    81         _precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS));
    82         _precalcThread.setName("YK Precalc");
    83         _precalcThread.setDaemon(true);
     90        _precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS),
     91                                       "YK Precalc", true);
    8492        _precalcThread.setPriority(Thread.MIN_PRIORITY);
     93        _isRunning = true;
    8594        _precalcThread.start();
     95    }
     96
     97    /**
     98     *  Note that this stops the singleton precalc thread.
     99     *  You don't want to do this if there are multiple routers in the JVM.
     100     *  Fix this if you care. See Router.shutdown().
     101     *  @since 0.8.8
     102     */
     103    public static void shutdown() {
     104        _isRunning = false;
     105        _precalcThread.interrupt();
     106        _values.clear();
     107    }
     108
     109    /**
     110     *  Only required if shutdown() previously called.
     111     *  @since 0.8.8
     112     */
     113    public static void restart() {
     114        synchronized(YKGenerator.class) {
     115            if (!_isRunning)
     116                startPrecalc();
     117        }
    86118    }
    87119
     
    162194
    163195        public void run() {
    164             while (true) {
     196            while (_isRunning) {
    165197                int curSize = 0;
    166198                //long start = Clock.getInstance().now();
     
    173205                curSize = startSize;
    174206                if (curSize < _minSize) {
    175                     for (int i = curSize; i < _maxSize; i++) {
     207                    for (int i = curSize; i < _maxSize && _isRunning; i++) {
    176208                        //long begin = Clock.getInstance().now();
    177209                        if (!addValues(generateYK()))
  • core/java/src/net/i2p/data/SDSCache.java

    r3a2e9ad r81beb63  
    8484                       " max: " + size + " max mem: " + (len * size));
    8585        I2PAppContext.getGlobalContext().statManager().createRateStat(_statName, "Hit rate", "Router", new long[] { 10*60*1000 });
     86        I2PAppContext.getGlobalContext().addShutdownTask(new Shutdown());
     87    }
     88
     89    /**
     90     * @since 0.8.8
     91     */
     92    private class Shutdown implements Runnable {
     93        public void run() {
     94            synchronized(_cache) {
     95                _cache.clear();
     96            }
     97        }
    8698    }
    8799
  • core/java/src/net/i2p/time/Timestamper.java

    r3a2e9ad r81beb63  
    3030    private boolean _initialized;
    3131    private boolean _wellSynced;
     32    private volatile boolean _isRunning;
     33    private Thread _timestamperThread;
    3234   
    3335    private static final int MIN_QUERY_FREQUENCY = 5*60*1000;
     
    107109   
    108110    private void startTimestamper() {
    109         I2PThread t = new I2PThread(this, "Timestamper");
    110         t.setPriority(I2PThread.MIN_PRIORITY);
    111         t.setDaemon(_daemon);
    112         t.start();
     111        _timestamperThread = new I2PThread(this, "Timestamper", _daemon);
     112        _timestamperThread.setPriority(I2PThread.MIN_PRIORITY);
     113        _isRunning = true;
     114        _timestamperThread.start();
     115        _context.addShutdownTask(new Shutdown());
    113116    }
    114117   
     
    120123            }
    121124        } catch (InterruptedException ie) {}
     125    }
     126   
     127    /** @since 0.8.8 */
     128    private class Shutdown implements Runnable {
     129        public void run() {
     130             _isRunning = false;
     131             if (_timestamperThread != null)
     132                 _timestamperThread.interrupt();
     133        }
    122134    }
    123135   
     
    129141        boolean lastFailed = false;
    130142        try {
    131             while (true) {
     143            while (_isRunning) {
    132144                updateConfig();
    133145                if (!_disabled) {
  • core/java/src/net/i2p/util/DecayingBloomFilter.java

    r3a2e9ad r81beb63  
    108108             "log10 of the false positive rate (must have net.i2p.util.DecayingBloomFilter=DEBUG)",
    109109             "Router", new long[] { Math.max(60*1000, durationMs) });
    110     }
    111    
     110        context.addShutdownTask(new Shutdown());
     111    }
     112   
     113    /**
     114     * @since 0.8.8
     115     */
     116    private class Shutdown implements Runnable {
     117        public void run() {
     118           clear();
     119        }
     120    }
     121
    112122    public long getCurrentDuplicateCount() { return _currentDuplicates; }
    113123
  • core/java/src/net/i2p/util/DecayingHashSet.java

    r3a2e9ad r81beb63  
    9494        context.statManager().createRateStat("router.decayingHashSet." + name + ".dups",
    9595             "1000000 * Duplicates/Size", "Router", new long[] { Math.max(60*1000, durationMs) });
    96     }
    97    
     96        context.addShutdownTask(new Shutdown());
     97    }
     98   
     99    /**
     100     * @since 0.8.8
     101     */
     102    private class Shutdown implements Runnable {
     103        public void run() {
     104            clear();
     105        }
     106    }
     107
    98108    /** unsynchronized but only used for logging elsewhere */
    99109    @Override
  • core/java/src/net/i2p/util/EepGet.java

    r3a2e9ad r81beb63  
    5656    protected long _bytesRemaining;
    5757    protected int _currentAttempt;
     58    protected int _responseCode = -1;
     59    protected boolean _shouldWriteErrorToOutput;
    5860    protected String _etag;
    5961    protected String _lastModified;
     
    246248        public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause);
    247249        public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt);
     250
     251        /**
     252         *  Note: Headers are not processed, and this is not called, for most error response codes,
     253         *  unless setWriteErrorToOutput() is called before fetch().
     254         *  To be changed?
     255         */
    248256        public void headerReceived(String url, int currentAttempt, String key, String val);
     257
    249258        public void attempting(String url);
    250259    }
     
    561570
    562571        int remaining = (int)_bytesRemaining;
    563         byte buf[] = new byte[1024];
     572        byte buf[] = new byte[8*1024];
    564573        while (_keepFetching && ( (remaining > 0) || !strictSize ) && !_aborted) {
    565574            int toRead = buf.length;
     
    655664        boolean read = DataHelper.readLine(_proxyIn, buf);
    656665        if (!read) throw new IOException("Unable to read the first line");
    657         int responseCode = handleStatus(buf.toString());
     666        _responseCode = handleStatus(buf.toString());
    658667        boolean redirect = false;
    659668       
    660669        if (_log.shouldLog(Log.DEBUG))
    661             _log.debug("rc: " + responseCode + " for " + _actualURL);
     670            _log.debug("rc: " + _responseCode + " for " + _actualURL);
    662671        boolean rcOk = false;
    663         switch (responseCode) {
     672        switch (_responseCode) {
    664673            case 200: // full
    665674                if (_outputStream != null)
     
    694703            case 409: // bad addr helper
    695704            case 503: // no outproxy
    696                 _keepFetching = false;
    697705                _transferFailed = true;
    698                 // maybe we should throw instead of return to get the return code back to the user
    699                 return;
     706                if (_alreadyTransferred == 0 && !_shouldWriteErrorToOutput) {
     707                    _keepFetching = false;
     708                    return;
     709                }
     710                // output the error data to the stream
     711                rcOk = true;
     712                if (_out == null) {
     713                    if (_outputStream != null)
     714                        _out = _outputStream;
     715                    else
     716                        _out = new FileOutputStream(_outputFile, true);
     717                }
     718                break;
    700719            case 416: // completed (or range out of reach)
    701720                _bytesRemaining = 0;
    702                 _keepFetching = false;
    703                 return;
     721                if (_alreadyTransferred == 0 && !_shouldWriteErrorToOutput) {
     722                    _keepFetching = false;
     723                    return;
     724                }
     725                // output the error data to the stream
     726                rcOk = true;
     727                if (_out == null) {
     728                    if (_outputStream != null)
     729                        _out = _outputStream;
     730                    else
     731                        _out = new FileOutputStream(_outputFile, true);
     732                }
     733                break;
    704734            case 504: // gateway timeout
    705735                // throw out of doFetch() to fetch() and try again
    706736                throw new IOException("HTTP Proxy timeout");
    707737            default:
    708                 rcOk = false;
    709                 _keepFetching = false;
     738                if (_alreadyTransferred == 0 && !_shouldWriteErrorToOutput) {
     739                    _keepFetching = false;
     740                } else {
     741                    // output the error data to the stream
     742                    rcOk = true;
     743                    if (_out == null) {
     744                        if (_outputStream != null)
     745                            _out = _outputStream;
     746                        else
     747                            _out = new FileOutputStream(_outputFile, true);
     748                    }
     749                }
    710750                _transferFailed = true;
    711751        }
     
    743783                    if (isEndOfHeaders(lookahead)) {
    744784                        if (!rcOk)
    745                             throw new IOException("Invalid HTTP response code: " + responseCode);
     785                            throw new IOException("Invalid HTTP response code: " + _responseCode);
    746786                        if (_encodingChunked) {
    747787                            _bytesRemaining = readChunkLength();
     
    843883                _encodingChunked = true;
    844884        } else if (key.equalsIgnoreCase("Content-Type")) {
    845             _contentType=val;
     885            _contentType=val.trim();
    846886        } else if (key.equalsIgnoreCase("Location")) {
    847887            _redirectLocation=val.trim();
     
    9921032        return _contentType;
    9931033    }
     1034   
     1035    /**
     1036     *  The server response (200, etc).
     1037     *  @return -1 if invalid, or if the proxy never responded,
     1038     *  or if no proxy was used and the server never responded.
     1039     *  If a non-proxied request partially succeeded (for example a redirect followed
     1040     *  by a fail, or a partial fetch followed by a fail), this will
     1041     *  be the last status code received.
     1042     *  Note that fetch() may return false even if this returns 200.
     1043     *
     1044     *  @since 0.8.8
     1045     */
     1046    public int getStatusCode() {
     1047        return _responseCode;
     1048    }
     1049
     1050    /**
     1051     *  If called (before calling fetch()),
     1052     *  data from the server or proxy will be written to the
     1053     *  output file or stream even on an error response code (4xx, 5xx, etc).
     1054     *  The error data will only be written if no previous data was written
     1055     *  on an earlier try.
     1056     *  Caller must of course check getStatusCode() or the
     1057     *  fetch() return value.
     1058     *
     1059     *  @since 0.8.8
     1060     */
     1061    public void setWriteErrorToOutput() {
     1062        _shouldWriteErrorToOutput = true;
     1063    }
    9941064}
  • core/java/src/net/i2p/util/FortunaRandomSource.java

    r3a2e9ad r81beb63  
    4545    }
    4646   
     47    /**
     48     *  Note - methods may hang or NPE or throw IllegalStateExceptions after this
     49     *  @since 0.8.8
     50     */
     51    public void shutdown() {
     52        _fortuna.shutdown();
     53    }
     54
    4755    @Override
    4856    public synchronized void setSeed(byte buf[]) {
  • core/java/src/net/i2p/util/I2PThread.java

    r3a2e9ad r81beb63  
    2121 */
    2222public class I2PThread extends Thread {
    23     private static volatile Log _log;
     23    /**
     24     *  Non-static to avoid refs to old context in Android.
     25     *  Probably should just remove all the logging though.
     26     */
     27    private volatile Log _log;
    2428    private static final Set _listeners = new CopyOnWriteArraySet();
    2529    private String _name;
     
    6266    }
    6367
    64     private static void log(int level, String msg) { log(level, msg, null); }
    65     private static void log(int level, String msg, Throwable t) {
     68    private void log(int level, String msg) { log(level, msg, null); }
     69
     70    private void log(int level, String msg, Throwable t) {
    6671        // we cant assume log is created
    6772        if (_log == null) _log = new Log(I2PThread.class);
     
    8691                fireOOM((OutOfMemoryError)t);
    8792        }
    88         log(Log.INFO, "Thread finished normally: " + _name);
     93        // This creates a new I2PAppContext after it was deleted
     94        // in Router.finalShutdown() via RouterContext.killGlobalContext()
     95        //log(Log.INFO, "Thread finished normally: " + _name);
    8996    }
    9097   
  • core/java/src/net/i2p/util/LogConsoleBuffer.java

    r3a2e9ad r81beb63  
    33import java.util.ArrayList;
    44import java.util.List;
     5import java.util.concurrent.LinkedBlockingQueue;
    56
    67import net.i2p.I2PAppContext;
    78
    89/**
    9  * Offer a glimpse into the last few console messages generated
    10  *
     10 * Offer a glimpse into the last few console messages generated.
     11 * Maintains two buffers, one normal and one critical.
    1112 */
    1213public class LogConsoleBuffer {
    13     private I2PAppContext _context;
    14     private final List<String> _buffer;
    15     private final List<String> _critBuffer;
     14    private final int lim;
     15    private final LinkedBlockingQueue<String> _buffer;
     16    private final LinkedBlockingQueue<String> _critBuffer;
    1617
     18    /**
     19     *  Uses default limit from LogManager.
     20     *  As of 0.8.8, limit is not checked at runtime.
     21     *
     22     *  @param context unused
     23     */
    1724    public LogConsoleBuffer(I2PAppContext context) {
    18         _context = context;
    19         _buffer = new ArrayList();
    20         _critBuffer = new ArrayList();
     25        this(LogManager.DEFAULT_CONSOLEBUFFERSIZE);
     26    }
     27
     28    /**
     29     *  @param limit max size of each buffer
     30     *  In theory the limit is configurable, but it isn't in the UI,
     31     *  so set it at construction.
     32     *
     33     *  @since 0.8.8
     34     */
     35    public LogConsoleBuffer(int limit) {
     36        lim = Math.max(limit, 4);
     37        // Add some extra room to minimize the chance of losing a message,
     38        // since we are doing offer() below.
     39        _buffer = new LinkedBlockingQueue(limit + 4);
     40        _critBuffer = new LinkedBlockingQueue(limit + 4);
    2141    }
    2242
    2343    void add(String msg) {
    24         int lim = _context.logManager().getConsoleBufferSize();
    25         synchronized (_buffer) {
    2644            while (_buffer.size() >= lim)
    27                 _buffer.remove(0);
    28             _buffer.add(msg);
    29         }
    30     }
    31     void addCritical(String msg) {
    32         int lim = _context.logManager().getConsoleBufferSize();
    33         synchronized (_critBuffer) {
    34             while (_critBuffer.size() >= lim)
    35                 _critBuffer.remove(0);
    36             _critBuffer.add(msg);
    37         }
     45                _buffer.poll();
     46            _buffer.offer(msg);
    3847    }
    3948
    4049    /**
    41      * Retrieve the currently bufferd messages, earlier values were generated...
     50     *  Only adds to the critical buffer, not to both.
     51     *
     52     */
     53    void addCritical(String msg) {
     54            while (_critBuffer.size() >= lim)
     55                _critBuffer.poll();
     56            _critBuffer.offer(msg);
     57    }
     58
     59    /**
     60     * Retrieve the currently buffered messages, earlier values were generated...
    4261     * earlier.  All values are strings with no formatting (as they are written
    4362     * in the logs)
    4463     *
     64     * @return oldest first
    4565     */
    4666    public List<String> getMostRecentMessages() {
    47         synchronized (_buffer) {
    4867            return new ArrayList(_buffer);
    49         }
    5068    }
     69
    5170    /**
    52      * Retrieve the currently bufferd crutucak messages, earlier values were generated...
     71     * Retrieve the currently buffered critical messages, earlier values were generated...
    5372     * earlier.  All values are strings with no formatting (as they are written
    5473     * in the logs)
    5574     *
     75     * @return oldest first
    5676     */
    5777    public List<String> getMostRecentCriticalMessages() {
    58         synchronized (_critBuffer) {
    5978            return new ArrayList(_critBuffer);
    60         }
    6179    }
    6280}
  • core/java/src/net/i2p/util/LogManager.java

    r3a2e9ad r81beb63  
    130130        String location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT);
    131131        setConfig(location);
    132         _consoleBuffer = new LogConsoleBuffer(context);
     132        _consoleBuffer = new LogConsoleBuffer(_consoleBufferSize);
    133133        // If we aren't in the router context, delay creating the LogWriter until required,
    134134        // so it doesn't create a log directory and log files unless there is output.
     
    657657            _writer.flushRecords(false);
    658658            _writer.stopWriting();
     659            synchronized (_writer) {
     660                _writer.notifyAll();
     661            }
    659662        }
    660663    }
  • core/java/src/net/i2p/util/LogWriter.java

    r3a2e9ad r81beb63  
    3737    private final LogManager _manager;
    3838
    39     private boolean _write;
     39    private volatile boolean _write;
    4040    private static final int MAX_DISKFULL_MESSAGES = 8;
    4141    private int _diskFullMessageCount;
     
    5656            while (_write) {
    5757                flushRecords();
    58                 rereadConfig();
     58                if (_write)
     59                    rereadConfig();
    5960            }
    6061            //System.err.println("Done writing");
  • core/java/src/net/i2p/util/RandomSource.java

    r3a2e9ad r81beb63  
    2929    protected final I2PAppContext _context;
    3030
     31    /**
     32     *  Deprecated - do not instantiate this directly, as you won't get the
     33     *  good one (Fortuna). Use getInstance() or
     34     *  I2PAppContext.getGlobalContext().random() to get the FortunaRandomSource
     35     *  instance.
     36     */
    3137    public RandomSource(I2PAppContext context) {
    3238        super();
     
    203209        }
    204210    }
    205    
    206     // noop
    207     private static class DummyEntropyHarvester implements EntropyHarvester {
    208         public void feedEntropy(String source, long data, int bitoffset, int bits) {}
    209         public void feedEntropy(String source, byte[] data, int offset, int len) {}
    210     }
    211211}
  • core/java/src/net/i2p/util/SimpleScheduler.java

    r3a2e9ad r81beb63  
    33import java.util.concurrent.Executors;
    44import java.util.concurrent.ScheduledThreadPoolExecutor;
     5import java.util.concurrent.ThreadPoolExecutor;
    56import java.util.concurrent.TimeUnit;
    67import java.util.concurrent.ThreadFactory;
     
    4950        _executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
    5051        _executor.prestartAllCoreThreads();
     52        // don't bother saving ref to remove hook if somebody else calls stop
     53        _context.addShutdownTask(new Shutdown());
    5154    }
    5255   
    5356    /**
    54      * Removes the SimpleScheduler.
     57     * @since 0.8.8
     58     */
     59    private class Shutdown implements Runnable {
     60        public void run() {
     61            stop();
     62        }
     63    }
     64
     65    /**
     66     * Stops the SimpleScheduler.
     67     * Subsequent executions should not throw a RejectedExecutionException.
    5568     */
    5669    public void stop() {
     70        _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
    5771        _executor.shutdownNow();
    5872    }
  • core/java/src/net/i2p/util/SimpleTimer.java

    r3a2e9ad r81beb63  
    5454            executor.start();
    5555        }
    56     }
    57    
     56        _context.addShutdownTask(new Shutdown());
     57    }
     58   
     59    /**
     60     * @since 0.8.8
     61     */
     62    private class Shutdown implements Runnable {
     63        public void run() {
     64            removeSimpleTimer();
     65        }
     66    }
     67
    5868    /**
    5969     * Removes the SimpleTimer.
     
    6272        synchronized(_events) {
    6373            runn.setAnswer(false);
     74            _events.clear();
     75            _eventTimes.clear();
    6476            _events.notifyAll();
     77        }
     78        synchronized (_readyEvents) {
     79            _readyEvents.clear();
     80            _readyEvents.notifyAll();
    6581        }
    6682    }
  • core/java/src/net/i2p/util/SimpleTimer2.java

    r3a2e9ad r81beb63  
    44import java.util.concurrent.ScheduledFuture;
    55import java.util.concurrent.ScheduledThreadPoolExecutor;
     6import java.util.concurrent.ThreadPoolExecutor;
    67import java.util.concurrent.TimeUnit;
    78import java.util.concurrent.ThreadFactory;
     
    4950        _executor = new CustomScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
    5051        _executor.prestartAllCoreThreads();
     52        // don't bother saving ref to remove hook if somebody else calls stop
     53        _context.addShutdownTask(new Shutdown());
    5154    }
    5255   
    5356    /**
    54      * Removes the SimpleTimer.
     57     * @since 0.8.8
     58     */
     59    private class Shutdown implements Runnable {
     60        public void run() {
     61            stop();
     62        }
     63    }
     64
     65    /**
     66     * Stops the SimpleTimer.
     67     * Subsequent executions should not throw a RejectedExecutionException.
    5568     */
    5669    public void stop() {
     70        _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
    5771        _executor.shutdownNow();
    5872    }
  • installer/resources/hosts.txt

    r3a2e9ad r81beb63  
    267267inproxy.tino.i2p=gNVJ0hpqZafnYkh7KFVHcvHuE~DeeOPZ45T1EFc8ARtd41s4dzKKaADtCtAmQIgQ8UYaiXA1l9eahcGP2rfJ4y3Ap4n3t-kext4UpCjzfwdI-u6s824nUb~ZaNfJIlqhu4sjmN0CK87BwKWU4-fYv3bM7mDDPWFT70ret81nN-SA3dQleKa65EK1T6EjKvAWeWkMhD9KnlsSMCc1OHwKX9Z8rM0Q8uXSYCLiY8VfQDPwOINvpTFUnuToo8GZ3KLQlECIZbE9OVJZ-0ZZEny1Muq~J~mQydFQnnCHB3hvPxjuv0rtO25zsBrAy4oFBrGgaFqy81gfTGDKhLwjaJ4hyYZwjBUNK5K-XLRO6ev03iOcVMvfuEdnCb~3uEUxEGYZTcAFJMUhSswo9CquLe0BodHm-biyki0kPxf~vE-yiCj0OPsUSD6frvqSqpksmAlasBhgQXR9hCJ37qJF1tBT2GaoHlHVhHzMqdNDEUHk-R1WRSeTghRDpwhQpCKb8VThAAAA
    268268kohaar.i2p=2qYXoTui18BY9KtzFiMsdw6-8-rZbeSoEMkVkFzYCP-ztPWp4p7-d-6d9Yjkjo647iqTA2DYcQqIZfI8V9gG7Q0NwpC5AHbbBz~117YPLcm1uf13m7nMiXKy66qzsTC~AzIazw4EUCuCTyubr~SzYrcX3M5c0ccl~ltZrnr233Y5B4zt5-6tkckXYLuOJVXfNhRLOAI-EQ~KGP~MxSWiuItDQW7DFo9-zEzN8J0sdiIHW6XcELDWth02PbAGOyi6OlJFfj53oF5MHPLMnR~o50mvu0wWtlZXR7bOcaFonfcfHdoV-m5Ilj9H5tNBdspg7Gimx3HBW8BoUXkxWoJu403mLHNXOhG2Zw1uK9bx2GJdrkMgvFKyQn9iq2USensMrb7Wf2LgFzc0lI5BsR2BTTp~cB~u1HHhXKlVYSxYKPxpjls6-n7bynIe9NSE-ToAvVOJ7ygW8sKJWxNu3tA-8ZSQ1kB4IRpzT901Nng4lAq4aMYVw8l2Wvo1SgALqUNJAAAA
    269 TheBreton.i2p=hYx0~K9CvPjbRwzPG~DCONlB3TwOiMGc47o5FoMAFUOoA7c3uMPuXS--1OXP3J7VbcfyRkWpQjmLhRXjeYD1HuCCJ5P8uuQ7w3RhTLActjkUkoF9yE9xH-3chudIbyZmlXRgNQaVxLkueK3hFFNODAFryITAtdH51RHl-CvBt7oQHdexL6TySL9YqlMIRHwjTCDv-mLngXHhltesU-RTwiJyJbmcNx8aq2RHcW0AdNve0nRCgNOt6k9lZ2RW3llmE42RVJiKIa9OYCNUMU7BNyklpBbfDxpoEPMO74aMqsNBhQmXXsZfNYfGAEWWvnYV~FMD40xJ~6bnlUTJj0AF-njN7mVOO57ne~l5wm-2Ltke1tomI9z-o4IhylIhzIJQYXVbNZezxf54Z5x~ydTWrvZE1KLDy3aAw8ODYByN00GRHLFuRJYYDRVUT2DcCk90wqySRUAV8fEO8EPe4Bx1KJh4yFJ6lgWfj~1hvDj4DZIDjsghonvKohTMZ1j3Pdi-AAAA
     269thebreton.i2p=hYx0~K9CvPjbRwzPG~DCONlB3TwOiMGc47o5FoMAFUOoA7c3uMPuXS--1OXP3J7VbcfyRkWpQjmLhRXjeYD1HuCCJ5P8uuQ7w3RhTLActjkUkoF9yE9xH-3chudIbyZmlXRgNQaVxLkueK3hFFNODAFryITAtdH51RHl-CvBt7oQHdexL6TySL9YqlMIRHwjTCDv-mLngXHhltesU-RTwiJyJbmcNx8aq2RHcW0AdNve0nRCgNOt6k9lZ2RW3llmE42RVJiKIa9OYCNUMU7BNyklpBbfDxpoEPMO74aMqsNBhQmXXsZfNYfGAEWWvnYV~FMD40xJ~6bnlUTJj0AF-njN7mVOO57ne~l5wm-2Ltke1tomI9z-o4IhylIhzIJQYXVbNZezxf54Z5x~ydTWrvZE1KLDy3aAw8ODYByN00GRHLFuRJYYDRVUT2DcCk90wqySRUAV8fEO8EPe4Bx1KJh4yFJ6lgWfj~1hvDj4DZIDjsghonvKohTMZ1j3Pdi-AAAA
    270270adab.i2p=3Z9v5Fx92js68wHTweMVAdqGlIieQRH7VtUiF~~jGLpf6P62ohcEqVaiCnLyfcWjXrGwz-uX-CvTTM5rwzfqciuqrXcG-asRF751TQAs1ncj-GHq5W0C-uRBtfaa5NPpfKsxAGlk4ILNvnUIgZrbwkNuDUulmaa-FwxjXPCcVYlzuUlGE9JYikk0nKgeTgm2ALBzLNH~EyM4CjYoIhtBGNPThqBckIR24JDo~zYB9plqpTvBIlA5iuskv0~3siXQW6eqnU9y3gIMy10vJYPY7rpbrR6YpAu2NoCxFCKsghpSqYXGpy19~1ymFtJMGDTj7uzz2OW9lvj8gtCp-4To7A6A-P2HNH0FpAANZmsX9sRaqqjSsp3kMuqg7T2XfB-Z29XkLtiTcl-rfr3xZdyznDg7n4mVW2DOeyoCthVTbf3dM2d9PmANLWS0Iy2KUDAIt8Y0RqqSB1CORZztsoE4sh7u-CjcE24mmbcVG6MHyhsK4PLDYJADquDDCgD5boolAAAA
    271271awup.i2p=y1UIT5rcMxuEyY9xQvXWOvg50sZnS4wjWqdeuKJCajMy2r9sLmL9KBVpJbTyO-QGOk5IHpyGSjEzWxQQOvFBPMtVllmaMaaHfZjrZ9h5D1iIqiz-DogfBDSjNetHhSRHEOxG1xF6Xq1ViWd14hKwTypfQTq8c~40tDChSdYHKHMJN8OWoTnicVw1AINu3aib6d6sAl5F9CKu1i949UFsVpoZw3LfiXcxjU0r7zQPIAltzezBsqJmhy-HbgyMvOKJb6MiGQ3niu5bM1J7TFz2uRKLxwM0QOblS3QOHzRXNFziPSinS5PkBIM2gDEyeZVlMDWBwVmRbG06mO5uVx~64Xc1jyjRvdvnzqITZRY389028A5HteLps2ge1fKYYINCxE5k4rq2BLXd-Utd5VArlcBDTTZVhapgaF8dE4xS3XLRF9GNY2VUTusElN6-dvhrOUNG80edhyBksUY0C5SszaBiWVBlb~WEZ0pTwdjCDf7B7sEsZVhRgqm~k3e62SNFAAAA
  • router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java

    r3a2e9ad r81beb63  
    2323 */
    2424public class I2NPMessageHandler {
    25     private Log _log;
    26     private I2PAppContext _context;
     25    private final Log _log;
     26    private final I2PAppContext _context;
    2727    private long _lastReadBegin;
    2828    private long _lastReadEnd;
  • router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java

    r3a2e9ad r81beb63  
    2929 */
    3030public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage {
    31     private Log _log;
    32     protected I2PAppContext _context;
     31    private final Log _log;
     32    protected final I2PAppContext _context;
    3333    private long _expiration;
    3434    private long _uniqueId;
  • router/java/src/net/i2p/router/JobQueue.java

    r3a2e9ad r81beb63  
    281281    void shutdown() {
    282282        _alive = false;
    283         _timedJobs.clear();
    284         _readyJobs.clear();
     283        synchronized (_jobLock) {
     284            _timedJobs.clear();
     285            _readyJobs.clear();
     286            _jobLock.notifyAll();
     287        }
    285288        // The JobQueueRunners are NOT daemons,
    286289        // so they must be stopped.
    287290        Job poison = new PoisonJob();
    288         for (int i = 0; i < _queueRunners.size(); i++)
     291        for (JobQueueRunner runner : _queueRunners.values()) {
     292             runner.stopRunning();
    289293            _readyJobs.offer(poison);
    290 
     294            // TODO interrupt thread for each runner
     295        }
     296        _queueRunners.clear();
     297        _jobStats.clear();
     298        _runnerId = 0;
    291299
    292300      /********
  • router/java/src/net/i2p/router/Router.java

    r3a2e9ad r81beb63  
    4646import net.i2p.util.ByteCache;
    4747import net.i2p.util.FileUtil;
     48import net.i2p.util.FortunaRandomSource;
    4849import net.i2p.util.I2PAppThread;
    4950import net.i2p.util.I2PThread;
    5051import net.i2p.util.Log;
    5152import net.i2p.util.SecureFileOutputStream;
     53import net.i2p.util.SimpleByteCache;
    5254import net.i2p.util.SimpleScheduler;
    5355import net.i2p.util.SimpleTimer;
     
    7476    private ShutdownHook _shutdownHook;
    7577    private final I2PThread _gracefulShutdownDetector;
     78    private final RouterWatchdog _watchdog;
     79    private final Thread _watchdogThread;
    7680   
    7781    public final static String PROP_CONFIG_FILE = "router.configLocation";
     
    188192        envProps.setProperty("i2p.systemTimeZone", originalTimeZoneID);
    189193
     194        // Make darn sure we don't have a leftover I2PAppContext in the same JVM
     195        // e.g. on Android - see finalShutdown() also
     196        List<RouterContext> contexts = RouterContext.getContexts();
     197        if (contexts.isEmpty()) {
     198            RouterContext.killGlobalContext();
     199        } else if (System.getProperty("java.vendor").contains("Android")) {
     200            System.err.println("Warning: Killing " + contexts.size() + " other routers in this JVM");
     201            contexts.clear();
     202            RouterContext.killGlobalContext();
     203        } else {
     204            System.err.println("Warning: " + contexts.size() + " other routers in this JVM");
     205        }
     206
    190207        // The important thing that happens here is the directory paths are set and created
    191208        // i2p.dir.router defaults to i2p.dir.config
     
    258275        _oomListener = new I2PThread.OOMEventListener() {
    259276            public void outOfMemory(OutOfMemoryError oom) {
    260                 ByteCache.clearAll();
     277                clearCaches();
    261278                _log.log(Log.CRIT, "Thread ran out of memory", oom);
    262279                for (int i = 0; i < 5; i++) { // try this 5 times, in case it OOMs
     
    276293        _gracefulShutdownDetector.start();
    277294       
    278         Thread watchdog = new I2PAppThread(new RouterWatchdog(_context), "RouterWatchdog", true);
    279         watchdog.start();
    280        
    281     }
    282    
     295        _watchdog = new RouterWatchdog(_context);
     296        _watchdogThread = new I2PAppThread(_watchdog, "RouterWatchdog", true);
     297        _watchdogThread.start();
     298       
     299    }
     300   
     301    /** @since 0.8.8 */
     302    private static final void clearCaches() {
     303        ByteCache.clearAll();
     304        SimpleByteCache.clearAll();
     305    }
     306
    283307    /**
    284308     * Configure the router to kill the JVM when the router shuts down, as well
     
    617641        killKeys();
    618642        for (Runnable task : _context.getShutdownTasks()) {
     643            if (_log.shouldLog(Log.WARN))
     644                _log.warn("Running shutdown task " + task.getClass());
    619645            try {
    620646                task.run();
     
    623649            }
    624650        }
     651        _context.removeShutdownTasks();
    625652        // hard and ugly
    626653        if (System.getProperty("wrapper.version") != null)
     
    633660    private void warmupCrypto() {
    634661        _context.random().nextBoolean();
    635         new DHSessionKeyBuilder(); // load the class so it starts the precalc process
     662        // Use restart() to refire the static refiller threads, in case
     663        // we are restarting the router in the same JVM (Android)
     664        DHSessionKeyBuilder.restart();
     665        _context.elGamalEngine().restart();
    636666    }
    637667   
     
    939969        // Maybe we need a delay after this too?
    940970        for (Runnable task : _context.getShutdownTasks()) {
     971            if (_log.shouldLog(Log.WARN))
     972                _log.warn("Running shutdown task " + task.getClass());
    941973            try {
    942974                task.run();
     
    945977            }
    946978        }
     979        _context.removeShutdownTasks();
    947980        try { _context.clientManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client manager", t); }
    948981        try { _context.namingService().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the naming service", t); }
     
    954987        try { _context.netDb().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the networkDb", t); }
    955988        try { _context.commSystem().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the comm system", t); }
     989        try { _context.bandwidthLimiter().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the comm system", t); }
    956990        try { _context.peerManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the peer manager", t); }
    957991        try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
     
    960994        //try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
    961995        _context.deleteTempDir();
    962         RouterContext.listContexts().remove(_context);
     996        List<RouterContext> contexts = RouterContext.getContexts();
     997        contexts.remove(_context);
     998
     999        // shut down I2PAppContext tasks here
     1000
     1001        // If there are multiple routers in the JVM, we don't want to do this
     1002        // to the DH or YK tasks, as they are singletons.
     1003        if (contexts.isEmpty()) {
     1004            try {
     1005                DHSessionKeyBuilder.shutdown();
     1006            } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting DH", t); }
     1007            try {
     1008                _context.elGamalEngine().shutdown();
     1009            } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting elGamal", t); }
     1010        } else {
     1011            _log.logAlways(Log.WARN, "Warning - " + contexts.size() + " routers remaining in this JVM, not releasing all resources");
     1012        }
     1013        try {
     1014            ((FortunaRandomSource)_context.random()).shutdown();
     1015        } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting random()", t); }
     1016
     1017        // logManager shut down in finalShutdown()
     1018        _watchdog.shutdown();
     1019        _watchdogThread.interrupt();
    9631020        finalShutdown(exitCode);
    9641021    }
     
    9711028
    9721029    private void finalShutdown(int exitCode) {
     1030        clearCaches();
    9731031        _log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete"  /* , new Exception("Shutdown") */ );
    9741032        try { _context.logManager().shutdown(); } catch (Throwable t) { }
     
    9801038        File f = getPingFile();
    9811039        f.delete();
     1040        if (RouterContext.getContexts().isEmpty())
     1041            RouterContext.killGlobalContext();
     1042
     1043        // Since 0.8.8, mainly for Android
     1044        for (Runnable task : _context.getFinalShutdownTasks()) {
     1045            System.err.println("Running final shutdown task " + task.getClass());
     1046            try {
     1047                task.run();
     1048            } catch (Throwable t) {
     1049                System.err.println("Running final shutdown task " + t);
     1050            }
     1051        }
     1052        _context.getFinalShutdownTasks().clear();
     1053
    9821054        if (_killVMOnEnd) {
    9831055            try { Thread.sleep(1000); } catch (InterruptedException ie) {}
     
    15421614        getContext().statManager().addRateData("router.memoryUsed", used, 0);
    15431615        if (_maxMemory - used < LOW_MEMORY_THRESHOLD)
    1544             ByteCache.clearAll();
     1616            clearCaches();
    15451617
    15461618        getContext().tunnelDispatcher().updateParticipatingStats(COALESCE_TIME);
  • router/java/src/net/i2p/router/RouterContext.java

    r3a2e9ad r81beb63  
    22
    33import java.util.ArrayList;
     4import java.util.Collections;
    45import java.util.List;
    56import java.util.Properties;
     7import java.util.Set;
     8import java.util.concurrent.CopyOnWriteArraySet;
    69
    710import net.i2p.I2PAppContext;
     
    5659    private MessageStateMonitor _messageStateMonitor;
    5760    private RouterThrottle _throttle;
     61    private final Set<Runnable> _finalShutdownTasks;
    5862
    5963    private static List<RouterContext> _contexts = new ArrayList(1);
     
    6872        // Sorry, this breaks some main() unit tests out there.
    6973        //initAll();
     74        if (!_contexts.isEmpty())
     75            System.err.println("Warning - More than one router in this JVM");
    7076        _contexts.add(this);
     77        _finalShutdownTasks = new CopyOnWriteArraySet();
    7178    }
    7279
     
    166173     * Retrieve the list of router contexts currently instantiated in this JVM. 
    167174     * This will always contain only one item (except when a simulation per the
    168      * MultiRouter is going on), and the list should only be modified when a new
     175     * MultiRouter is going on).
     176     *
     177     * @return an unmodifiable list (as of 0.8.8). May be null or empty.
     178     */
     179    public static List<RouterContext> listContexts() {
     180        return Collections.unmodifiableList(_contexts);
     181    }
     182   
     183    /**
     184     * Same as listContexts() but package private and modifiable.
     185     * The list should only be modified when a new
    169186     * context is created or a router is shut down.
    170187     *
    171      */
    172     public static List<RouterContext> listContexts() { return _contexts; }
     188     * @since 0.8.8
     189     */
     190    static List<RouterContext> getContexts() {
     191        return _contexts;
     192    }
     193   
     194    /**
     195     * Kill the global I2PAppContext, so it isn't still around
     196     * when we restart in the same JVM (Android).
     197     * Only do this if there are no other routers in the JVM.
     198     *
     199     * @since 0.8.8
     200     */
     201    static void killGlobalContext() {
     202        synchronized (I2PAppContext.class) {
     203            _globalAppContext = null;
     204        }
     205    }
    173206   
    174207    /** what router is this context working for? */
     
    404437   
    405438    /**
     439     *  @since 0.8.8
     440     */
     441    void removeShutdownTasks() {
     442        _shutdownTasks.clear();
     443    }
     444   
     445    /**
     446     *  The last thing to be called before router shutdown.
     447     *  No context resources, including logging, will be available.
     448     *  Only for external threads in the same JVM needing to know when
     449     *  the shutdown is complete, like Android.
     450     *  @since 0.8.8
     451     */
     452    public void addFinalShutdownTask(Runnable task) {
     453        _finalShutdownTasks.add(task);
     454    }
     455   
     456    /**
     457     *  @return the Set
     458     *  @since 0.8.8
     459     */
     460    Set<Runnable> getFinalShutdownTasks() {
     461        return _finalShutdownTasks;
     462    }
     463   
     464    /**
    406465     *  Use this instead of context instanceof RouterContext
    407466     *  @return true
  • router/java/src/net/i2p/router/RouterWatchdog.java

    r3a2e9ad r81beb63  
    1616    private final RouterContext _context;
    1717    private int _consecutiveErrors;
     18    private volatile boolean _isRunning;
    1819   
    1920    private static final long MAX_JOB_RUN_LAG = 60*1000;
     
    2223        _context = ctx;
    2324        _log = ctx.logManager().getLog(RouterWatchdog.class);
     25        _isRunning = true;
    2426    }
    2527   
     28    /** @since 0.8.8 */
     29    public void shutdown() {
     30        _isRunning = false;
     31    }
     32
    2633    public boolean verifyJobQueueLiveliness() {
    2734        long when = _context.jobQueue().getLastJobBegin();
     
    110117   
    111118    public void run() {
    112         while (true) {
     119        while (_isRunning) {
    113120            try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
    114121            monitorRouter();
  • router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java

    r3a2e9ad r81beb63  
    360360                        _alreadyWarned = false;
    361361                    for (int i = 0; i < routerInfoFiles.length; i++) {
     362                        // drop out if the router gets killed right after startup
     363                        if (!_context.router().isAlive())
     364                            break;
    362365                        Hash key = getRouterInfoHash(routerInfoFiles[i].getName());
    363366                        if ( (key != null) && (!isKnown(key)) ) {
  • router/java/src/net/i2p/router/peermanager/PeerManager.java

    r3a2e9ad r81beb63  
    5353    private static final long REORGANIZE_TIME_LONG = 551*1000;
    5454   
     55    /**
     56     *  Warning - this loads all the profiles in the constructor.
     57     *  This may take a long time - 30 seconds or more.
     58     *  Instantiate this in a Job or Thread.
     59     */
    5560    public PeerManager(RouterContext context) {
    5661        _context = context;
     
    100105    }
    101106
     107    /** @since 0.8.8 */
     108    void clearProfiles() {
     109        _organizer.clearProfiles();
     110        _capabilitiesByPeer.clear();
     111        for (int i = 0; i < _peersByCapability.length; i++)
     112            _peersByCapability[i].clear();
     113    }
     114
    102115    Set selectPeers() {
    103116        return _organizer.selectAllPeers();
     
    112125    }
    113126
     127    /**
     128     *  This may take a long time - 30 seconds or more
     129     */
    114130    void loadProfiles() {
    115131        Set<PeerProfile> profiles = _persistenceHelper.readProfiles();
  • router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java

    r3a2e9ad r81beb63  
    4848        _log.info("Shutting down the peer manager");
    4949        _testJob.stopTesting();
    50         if (_manager != null)
     50        if (_manager != null) {
    5151            _manager.storeProfiles();
     52            _manager.clearProfiles();
     53        }
    5254    }
    5355   
  • router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java

    r3a2e9ad r81beb63  
    228228    public boolean isFailing(Hash peer) { return isX(_failingPeers, peer); }
    229229       
     230    /** @since 0.8.8 */
     231    void clearProfiles() {
     232        getReadLock();
     233        try {
     234            _failingPeers.clear();
     235            _fastPeers.clear();
     236            _highCapacityPeers.clear();
     237            _notFailingPeers.clear();
     238            _notFailingPeersList.clear();
     239            _wellIntegratedPeers.clear();
     240        } finally { releaseReadLock(); }
     241    }
     242
    230243    /**
    231244     * if a peer sends us more than 5 replies in a searchReply that we cannot
  • router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java

    r3a2e9ad r81beb63  
    6565    private final AtomicLong _totalWastedOutboundBytes = new AtomicLong();
    6666    private final FIFOBandwidthRefiller _refiller;
     67    private final Thread _refillerThread;
    6768   
    6869    private long _lastTotalSent;
     
    9293        _lastStatsUpdated = now();
    9394        _refiller = new FIFOBandwidthRefiller(_context, this);
    94         I2PThread t = new I2PThread(_refiller, "BWRefiller", true);
    95         t.setPriority(I2PThread.NORM_PRIORITY-1);
    96         t.start();
     95        _refillerThread = new I2PThread(_refiller, "BWRefiller", true);
     96        _refillerThread.setPriority(I2PThread.NORM_PRIORITY-1);
     97        _refillerThread.start();
    9798    }
    9899
     
    123124   
    124125    public void reinitialize() {
     126        clear();
     127        _refiller.reinitialize();
     128    }
     129
     130    /** @since 0.8.8 */
     131    public void shutdown() {
     132        _refiller.shutdown();
     133        _refillerThread.interrupt();
     134        clear();
     135    }
     136
     137    /** @since 0.8.8 */
     138    private void clear() {
    125139        _pendingInboundRequests.clear();
    126140        _pendingOutboundRequests.clear();
     
    135149        _inboundUnlimited = false;
    136150        _outboundUnlimited = false;
    137         _refiller.reinitialize();
    138151    }
    139152   
  • router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java

    r3a2e9ad r81beb63  
    2525    /** how frequently do we check the config for updates? */
    2626    private long _configCheckPeriodMs = 60*1000;
     27    private volatile boolean _isRunning;
    2728 
    2829    public static final String PROP_INBOUND_BANDWIDTH = "i2np.bandwidth.inboundKBytesPerSecond";
     
    6869        _log = context.logManager().getLog(FIFOBandwidthRefiller.class);
    6970        reinitialize();
    70     }
     71        _isRunning = true;
     72    }
     73
     74    /** @since 0.8.8 */
     75    public void shutdown() {
     76        _isRunning = false;
     77    }
     78
    7179    public void run() {
    7280        // bootstrap 'em with nothing
    7381        _lastRefillTime = _limiter.now();
    7482        List<FIFOBandwidthLimiter.Request> buffer = new ArrayList(2);
    75         while (true) {
     83        while (_isRunning) {
    7684            long now = _limiter.now();
    7785            if (now >= _lastCheckConfigTime + _configCheckPeriodMs) {
  • router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java

    r3a2e9ad r81beb63  
    10901090   
    10911091    private static final int MAX_HANDLERS = 4;
     1092
     1093    /**
     1094     *  FIXME static queue mixes handlers from different contexts in multirouter JVM
     1095     */
    10921096    private final static LinkedBlockingQueue<I2NPMessageHandler> _i2npHandlers = new LinkedBlockingQueue(MAX_HANDLERS);
    10931097
     
    11281132        buf.bais.reset();
    11291133        _dataReadBufs.offer(buf);
     1134    }
     1135
     1136    /** @since 0.8.8 */
     1137    static void releaseResources() {
     1138        _i2npHandlers.clear();
     1139        _dataReadBufs.clear();
     1140        synchronized(_bufs) {
     1141            _bufs.clear();
     1142        }
    11301143    }
    11311144
  • router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java

    r3a2e9ad r81beb63  
    703703            con.close();
    704704        }
     705        NTCPConnection.releaseResources();
    705706        // will this work?
    706707        replaceAddress(null);
  • router/java/src/net/i2p/router/transport/udp/PacketHandler.java

    r3a2e9ad r81beb63  
    114114    }
    115115
     116    /** @since 0.8.8 */
     117    int getHandlerCount() {
     118        return _handlers.length;
     119    }
     120
    116121    /** the packet is from a peer we are establishing an outbound con to, but failed validation, so fallback */
    117122    private static final short OUTBOUND_FALLBACK = 1;
  • router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java

    r3a2e9ad r81beb63  
    148148    /**
    149149     * Blocking call to receive the next inbound UDP packet from any peer.
     150     * @return null if we have shut down
    150151     */
    151152    public UDPPacket receive() {
  • router/java/src/net/i2p/router/transport/udp/UDPReceiver.java

    r3a2e9ad r81beb63  
    5959        _keepRunning = false;
    6060        _inboundQueue.clear();
    61         UDPPacket poison = UDPPacket.acquire(_context, false);
    62         poison.setMessageType(TYPE_POISON);
    63         _inboundQueue.offer(poison);
     61        for (int i = 0; i < _transport.getPacketHandlerCount(); i++) {
     62            UDPPacket poison = UDPPacket.acquire(_context, false);
     63            poison.setMessageType(TYPE_POISON);
     64            _inboundQueue.offer(poison);
     65        }
    6466        for (int i = 1; i <= 5 && !_inboundQueue.isEmpty(); i++) {
    6567            try {
  • router/java/src/net/i2p/router/transport/udp/UDPTransport.java

    r3a2e9ad r81beb63  
    13661366        else
    13671367            return "";
     1368    }
     1369
     1370    /** @since 0.8.8 */
     1371    int getPacketHandlerCount() {
     1372        PacketHandler handler = _handler;
     1373        if (handler != null)
     1374            return handler.getHandlerCount();
     1375        else
     1376            return 0;
    13681377    }
    13691378
  • router/java/src/net/i2p/router/util/RandomIterator.java

    r3a2e9ad r81beb63  
    8585    * for some implementations, which are faster than java.util.Random.
    8686    */
    87     private static final Random rand = RandomSource.getInstance();
     87    private final Random rand = RandomSource.getInstance();
    8888
    8989    /** Used to narrow the range to take random indexes from */
  • router/java/src/org/cybergarage/upnp/ssdp/HTTPMUSocket.java

    r3a2e9ad r81beb63  
    121121                       
    122122                try {
    123                         ssdpMultiSock.leaveGroup(ssdpMultiGroup, ssdpMultiIf);
     123                        // I2P close it instead of leaving group so the thread dies
     124                        //ssdpMultiSock.leaveGroup(ssdpMultiGroup, ssdpMultiIf);
     125                        ssdpMultiSock.close();
    124126                        ssdpMultiSock = null;
    125127                }
  • router/java/src/org/cybergarage/util/ThreadCore.java

    r3a2e9ad r81beb63  
    6666                        //threadObject.stop();
    6767                        setThreadObject(null);
     68                        // I2P break Disposer out of sleep()
     69                        threadObject.interrupt();
    6870                }
    6971        }
Note: See TracChangeset for help on using the changeset viewer.