Changeset 0bf0715


Ignore:
Timestamp:
Jul 15, 2011 1:13:35 AM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
65656b3
Parents:
857f0a0
Message:
  • Shutdown:
    • Cancel our JVM shutdown hook when shutting down
    • Run a spinner task so shutdown always completes
    • exit() instead of halt() so other JVM shutdown hooks run
    • Prevent duplicate wrapper notifier hooks
    • Notify the wrapper twice, once for stopping and once for stopped
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java

    r857f0a0 r0bf0715  
    299299        // Full restart required to generate new keys
    300300        // FIXME don't call wrapper if not present, only rekey
    301         _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
     301        ConfigServiceHandler.registerWrapperNotifier(_context, Router.EXIT_GRACEFUL_RESTART, false);
    302302        _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    303303    }
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java

    r857f0a0 r0bf0715  
    3232            if ("shutdownImmediate".equals(action) || _("Shutdown immediately", ctx).equals(action)) {
    3333                if (ctx.hasWrapper())
    34                     ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
     34                    ConfigServiceHandler.registerWrapperNotifier(ctx, Router.EXIT_HARD, false);
    3535                //ctx.router().shutdown(Router.EXIT_HARD); // never returns
    3636                ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond
     
    4040            } else if ("restartImmediate".equals(action) || _("Restart immediately", ctx).equals(action)) {
    4141                if (ctx.hasWrapper())
    42                     ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
     42                    ConfigServiceHandler.registerWrapperNotifier(ctx, Router.EXIT_HARD_RESTART, false);
    4343                //ctx.router().shutdown(Router.EXIT_HARD_RESTART); // never returns
    4444                ctx.router().shutdownGracefully(Router.EXIT_HARD_RESTART); // give the UI time to respond
    4545            } else if ("restart".equals(action) || _("Restart", ctx).equals(action)) {
    4646                if (ctx.hasWrapper())
    47                     ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
     47                    ConfigServiceHandler.registerWrapperNotifier(ctx, Router.EXIT_GRACEFUL_RESTART, false);
    4848                ctx.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    4949            } else if ("shutdown".equals(action) || _("Shutdown", ctx).equals(action)) {
    5050                if (ctx.hasWrapper())
    51                     ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
     51                    ConfigServiceHandler.registerWrapperNotifier(ctx, Router.EXIT_GRACEFUL, false);
    5252                ctx.router().shutdownGracefully();
    5353            }
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java

    r857f0a0 r0bf0715  
    77import net.i2p.apps.systray.UrlLauncher;
    88import net.i2p.router.Router;
     9import net.i2p.router.RouterContext;
    910import net.i2p.router.startup.ClientAppConfig;
    1011
     
    1819public class ConfigServiceHandler extends FormHandler {
    1920   
    20     public static class UpdateWrapperManagerTask implements Runnable {
    21         private int _exitCode;
    22         public UpdateWrapperManagerTask(int exitCode) {
     21    /**
     22     *  Register two shutdown hooks, one to rekey and/or tell the wrapper we are stopping,
     23     *  and a final one to tell the wrapper we are stopped.
     24     *
     25     *  @since 0.8.8
     26     */
     27    private void registerWrapperNotifier(int code, boolean rekey) {
     28        registerWrapperNotifier(_context, code, rekey);
     29    }
     30   
     31    /**
     32     *  Register two shutdown hooks, one to rekey and/or tell the wrapper we are stopping,
     33     *  and a final one to tell the wrapper we are stopped.
     34     *
     35     *  @since 0.8.8
     36     */
     37    public static void registerWrapperNotifier(RouterContext ctx, int code, boolean rekey) {
     38        Runnable task = new UpdateWrapperOrRekeyTask(rekey, ctx.hasWrapper());
     39        ctx.addShutdownTask(task);
     40        if (ctx.hasWrapper()) {
     41            task = new FinalWrapperTask(code);
     42            ctx.addFinalShutdownTask(task);
     43        }
     44    }
     45
     46    /**
     47     *  Rekey and/or tell the wrapper we are stopping,
     48     */
     49    private static class UpdateWrapperOrRekeyTask implements Runnable {
     50        private final boolean _rekey;
     51        private final boolean _tellWrapper;
     52        private static final int HASHCODE = -123999871;
     53        private static final int WAIT = 30*1000;
     54
     55        public UpdateWrapperOrRekeyTask(boolean rekey, boolean tellWrapper) {
     56            _rekey = rekey;
     57            _tellWrapper = tellWrapper;
     58        }
     59
     60        public void run() {
     61            try {
     62                if (_rekey)
     63                    ContextHelper.getContext(null).router().killKeys();
     64                if (_tellWrapper)
     65                    WrapperManager.signalStopping(WAIT);
     66            } catch (Throwable t) {
     67                t.printStackTrace();
     68            }
     69        }
     70
     71        /**
     72         *  Make them all look the same since the hooks are stored in a set
     73         *  and we don't want dups
     74         */
     75        @Override
     76        public int hashCode() {
     77            return HASHCODE;
     78        }
     79
     80        /**
     81         *  Make them all look the same since the hooks are stored in a set
     82         *  and we don't want dups
     83         */
     84        @Override
     85        public boolean equals(Object o) {
     86            return (o != null) && (o instanceof UpdateWrapperOrRekeyTask);
     87        }
     88    }
     89
     90    /**
     91     *  Tell the wrapper we are stopped.
     92     *
     93     *  @since 0.8.8
     94     */
     95    private static class FinalWrapperTask implements Runnable {
     96        private final int _exitCode;
     97        private static final int HASHCODE = 123999871;
     98
     99        public FinalWrapperTask(int exitCode) {
    23100            _exitCode = exitCode;
    24101        }
     102
    25103        public void run() {
    26104            try {
     
    30108            }
    31109        }
    32     }
    33 
    34     public static class UpdateWrapperManagerAndRekeyTask implements Runnable {
    35         private int _exitCode;
    36         public UpdateWrapperManagerAndRekeyTask(int exitCode) {
    37             _exitCode = exitCode;
    38         }
    39         public void run() {
    40             try {
    41                 ContextHelper.getContext(null).router().killKeys();
    42                 WrapperManager.signalStopped(_exitCode);
    43             } catch (Throwable t) {
    44                 t.printStackTrace();
    45             }
    46         }
    47     }
    48    
     110
     111        /**
     112         *  Make them all look the same since the hooks are stored in a set
     113         *  and we don't want dups
     114         */
     115        @Override
     116        public int hashCode() {
     117            return HASHCODE;
     118        }
     119
     120        /**
     121         *  Make them all look the same since the hooks are stored in a set
     122         *  and we don't want dups
     123         */
     124        @Override
     125        public boolean equals(Object o) {
     126            return (o != null) && (o instanceof FinalWrapperTask);
     127        }
     128    }
     129
    49130    @Override
    50131    protected void processForm() {
     
    53134        if (_("Shutdown gracefully").equals(_action)) {
    54135            if (_context.hasWrapper())
    55                 _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
     136                registerWrapperNotifier(Router.EXIT_GRACEFUL, false);
    56137            _context.router().shutdownGracefully();
    57138            addFormNotice(_("Graceful shutdown initiated"));
    58139        } else if (_("Shutdown immediately").equals(_action)) {
    59140            if (_context.hasWrapper())
    60                 _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
     141                registerWrapperNotifier(Router.EXIT_HARD, false);
    61142            _context.router().shutdown(Router.EXIT_HARD);
    62143            addFormNotice(_("Shutdown immediately!  boom bye bye bad bwoy"));
     
    67148            // should have wrapper if restart button is visible
    68149            if (_context.hasWrapper())
    69                 _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
     150                registerWrapperNotifier(Router.EXIT_GRACEFUL_RESTART, false);
    70151            _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    71152            addFormNotice(_("Graceful restart requested"));
     
    73154            // should have wrapper if restart button is visible
    74155            if (_context.hasWrapper())
    75                 _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
     156                registerWrapperNotifier(Router.EXIT_HARD_RESTART, false);
    76157            _context.router().shutdown(Router.EXIT_HARD_RESTART);
    77158            addFormNotice(_("Hard restart requested"));
    78159        } else if (_("Rekey and Restart").equals(_action)) {
    79160            addFormNotice(_("Rekeying after graceful restart"));
    80             // FIXME don't call wrapper if not present, only rekey
    81             _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
     161            registerWrapperNotifier(Router.EXIT_GRACEFUL_RESTART, true);
    82162            _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    83163        } else if (_("Rekey and Shutdown").equals(_action)) {
    84164            addFormNotice(_("Rekeying after graceful shutdown"));
    85             // FIXME don't call wrapper if not present, only rekey
    86             _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL));
     165            registerWrapperNotifier(Router.EXIT_GRACEFUL, true);
    87166            _context.router().shutdownGracefully(Router.EXIT_GRACEFUL);
    88167        } else if (_("Run I2P on startup").equals(_action)) {
  • apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java

    r857f0a0 r0bf0715  
    314314    protected void restart() {
    315315        if (_context.hasWrapper())
    316             _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
     316            ConfigServiceHandler.registerWrapperNotifier(_context, Router.EXIT_GRACEFUL_RESTART, false);
    317317        _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    318318    }
  • history.txt

    r857f0a0 r0bf0715  
     12011-07-15 zzz
     2  * Shutdown:
     3    - Cancel our JVM shutdown hook when shutting down
     4    - Run a spinner task so shutdown always completes
     5    - exit() instead of halt() so other JVM shutdown hooks run
     6    - Prevent duplicate wrapper notifier hooks
     7    - Notify the wrapper twice, once for stopping and once for stopped
     8
    192011-07-13 zzz
    210  * Blocklist:
  • router/java/src/net/i2p/router/Router.java

    r857f0a0 r0bf0715  
    376376        _isAlive = true;
    377377        _started = _context.clock().now();
    378         Runtime.getRuntime().addShutdownHook(_shutdownHook);
     378        try {
     379            Runtime.getRuntime().removeShutdownHook(_shutdownHook);
     380        } catch (IllegalStateException ise) {}
    379381        I2PThread.addOOMEventListener(_oomListener);
    380382       
     
    645647     */
    646648    public void rebuildNewIdentity() {
     649        if (_shutdownHook != null) {
     650            try {
     651                Runtime.getRuntime().removeShutdownHook(_shutdownHook);
     652            } catch (IllegalStateException ise) {}
     653        }
    647654        killKeys();
    648655        for (Runnable task : _context.getShutdownTasks()) {
     
    961968    }
    962969******/
     970
     971    /**
     972     *  A non-daemon thread to let
     973     *  the shutdown task get all the way to the end
     974     *  @since 0.8.8
     975     */
     976    private static class Spinner extends Thread {
     977
     978        public Spinner() {
     979            super();
     980            setName("Shutdown Spinner");
     981            setDaemon(false);
     982        }
     983
     984        @Override
     985        public void run() {
     986            try {
     987                sleep(60*1000);
     988            } catch (InterruptedException ie) {}
     989        }
     990    }
    963991   
    964992    public static final int EXIT_GRACEFUL = 2;
     
    9721000     */
    9731001    public void shutdown(int exitCode) {
     1002        if (_shutdownHook != null) {
     1003            try {
     1004                Runtime.getRuntime().removeShutdownHook(_shutdownHook);
     1005            } catch (IllegalStateException ise) {}
     1006        }
     1007        shutdown2(exitCode);
     1008    }
     1009
     1010    /**
     1011     *  Cancel the JVM runtime hook before calling this.
     1012     */
     1013    private void shutdown2(int exitCode) {
     1014        // So we can get all the way to the end
     1015        // No, you can't do Thread.currentThread.setDaemon(false)
     1016        if (_killVMOnEnd) {
     1017            try {
     1018                (new Spinner()).start();
     1019            } catch (Throwable t) {}
     1020        }
    9741021        ((RouterClock) _context.clock()).removeShiftListener(this);
    9751022        _isAlive = false;
     
    10391086    private static final boolean ALLOW_DYNAMIC_KEYS = false;
    10401087
     1088    /**
     1089     *  Cancel the JVM runtime hook before calling this.
     1090     */
    10411091    private void finalShutdown(int exitCode) {
    10421092        clearCaches();
     
    10531103            RouterContext.killGlobalContext();
    10541104
    1055         // Since 0.8.8, mainly for Android
     1105        // Since 0.8.8, for Android and the wrapper
    10561106        for (Runnable task : _context.getFinalShutdownTasks()) {
    1057             System.err.println("Running final shutdown task " + task.getClass());
     1107            //System.err.println("Running final shutdown task " + task.getClass());
    10581108            try {
    10591109                task.run();
     
    10661116        if (_killVMOnEnd) {
    10671117            try { Thread.sleep(1000); } catch (InterruptedException ie) {}
    1068             Runtime.getRuntime().halt(exitCode);
     1118            //Runtime.getRuntime().halt(exitCode);
     1119            // allow the Runtime shutdown hooks to execute
     1120            Runtime.getRuntime().exit(exitCode);
    10691121        } else {
    10701122            Runtime.getRuntime().gc();
     
    17731825}
    17741826
     1827/**
     1828 *  Just for failsafe. Standard shutdown should cancel this.
     1829 */
    17751830private static class ShutdownHook extends Thread {
    1776     private RouterContext _context;
     1831    private final RouterContext _context;
    17771832    private static int __id = 0;
    1778     private int _id;
     1833    private final int _id;
     1834
    17791835    public ShutdownHook(RouterContext ctx) {
    17801836        _context = ctx;
    17811837        _id = ++__id;
    17821838    }
    1783         @Override
     1839
     1840    @Override
    17841841    public void run() {
    17851842        setName("Router " + _id + " shutdown");
    17861843        Log l = _context.logManager().getLog(Router.class);
    17871844        l.log(Log.CRIT, "Shutting down the router...");
    1788         _context.router().shutdown(Router.EXIT_HARD);
     1845        _context.router().shutdown2(Router.EXIT_HARD);
    17891846    }
    17901847}
  • router/java/src/net/i2p/router/RouterVersion.java

    r857f0a0 r0bf0715  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 10;
     21    public final static long BUILD = 11;
    2222
    2323    /** for example "-test" */
Note: See TracChangeset for help on using the changeset viewer.