src/java.base/share/classes/java/lang/Shutdown.java
changeset 48942 a6c4b85163c1
parent 47216 71c04702a3d5
child 49186 b8bfadfacded
equal deleted inserted replaced
48941:4f11514fe783 48942:a6c4b85163c1
     1 /*
     1 /*
     2  * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    24  */
    24  */
    25 
    25 
    26 package java.lang;
    26 package java.lang;
    27 
    27 
    28 
    28 
       
    29 import jdk.internal.misc.VM;
       
    30 
    29 /**
    31 /**
    30  * Package-private utility class containing data structures and logic
    32  * Package-private utility class containing data structures and logic
    31  * governing the virtual-machine shutdown sequence.
    33  * governing the virtual-machine shutdown sequence.
    32  *
    34  *
    33  * @author   Mark Reinhold
    35  * @author   Mark Reinhold
    34  * @since    1.3
    36  * @since    1.3
       
    37  *
       
    38  * @see java.io.Console
       
    39  * @see ApplicationShutdownHooks
       
    40  * @see java.io.DeleteOnExitHook
    35  */
    41  */
    36 
    42 
    37 class Shutdown {
    43 class Shutdown {
    38 
    44 
    39     /* Shutdown state */
       
    40     private static final int RUNNING = 0;
       
    41     private static final int HOOKS = 1;
       
    42     private static final int FINALIZERS = 2;
       
    43     private static int state = RUNNING;
       
    44 
       
    45     /* Should we run all finalizers upon exit? */
       
    46     private static boolean runFinalizersOnExit = false;
       
    47 
       
    48     // The system shutdown hooks are registered with a predefined slot.
    45     // The system shutdown hooks are registered with a predefined slot.
    49     // The list of shutdown hooks is as follows:
    46     // The list of shutdown hooks is as follows:
    50     // (0) Console restore hook
    47     // (0) Console restore hook
    51     // (1) Application hooks
    48     // (1) ApplicationShutdownHooks that invokes all registered application
       
    49     //     shutdown hooks and waits until they finish
    52     // (2) DeleteOnExit hook
    50     // (2) DeleteOnExit hook
    53     private static final int MAX_SYSTEM_HOOKS = 10;
    51     private static final int MAX_SYSTEM_HOOKS = 10;
    54     private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
    52     private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
    55 
    53 
    56     // the index of the currently running shutdown hook to the hooks array
    54     // the index of the currently running shutdown hook to the hooks array
    57     private static int currentRunningHook = 0;
    55     private static int currentRunningHook = -1;
    58 
    56 
    59     /* The preceding static fields are protected by this lock */
    57     /* The preceding static fields are protected by this lock */
    60     private static class Lock { };
    58     private static class Lock { };
    61     private static Object lock = new Lock();
    59     private static Object lock = new Lock();
    62 
    60 
    63     /* Lock object for the native halt method */
    61     /* Lock object for the native halt method */
    64     private static Object haltLock = new Lock();
    62     private static Object haltLock = new Lock();
    65 
    63 
    66     /* Invoked by Runtime.runFinalizersOnExit */
       
    67     static void setRunFinalizersOnExit(boolean run) {
       
    68         synchronized (lock) {
       
    69             runFinalizersOnExit = run;
       
    70         }
       
    71     }
       
    72 
       
    73 
       
    74     /**
    64     /**
    75      * Add a new shutdown hook.  Checks the shutdown state and the hook itself,
    65      * Add a new system shutdown hook.  Checks the shutdown state and
    76      * but does not do any security checks.
    66      * the hook itself, but does not do any security checks.
    77      *
    67      *
    78      * The registerShutdownInProgress parameter should be false except
    68      * The registerShutdownInProgress parameter should be false except
    79      * registering the DeleteOnExitHook since the first file may
    69      * registering the DeleteOnExitHook since the first file may
    80      * be added to the delete on exit list by the application shutdown
    70      * be added to the delete on exit list by the application shutdown
    81      * hooks.
    71      * hooks.
    90      *         if registerShutdownInProgress is false and shutdown is in progress; or
    80      *         if registerShutdownInProgress is false and shutdown is in progress; or
    91      *         if registerShutdownInProgress is true and the shutdown process
    81      *         if registerShutdownInProgress is true and the shutdown process
    92      *         already passes the given slot
    82      *         already passes the given slot
    93      */
    83      */
    94     static void add(int slot, boolean registerShutdownInProgress, Runnable hook) {
    84     static void add(int slot, boolean registerShutdownInProgress, Runnable hook) {
       
    85         if (slot < 0 || slot >= MAX_SYSTEM_HOOKS) {
       
    86             throw new IllegalArgumentException("Invalid slot: " + slot);
       
    87         }
    95         synchronized (lock) {
    88         synchronized (lock) {
    96             if (hooks[slot] != null)
    89             if (hooks[slot] != null)
    97                 throw new InternalError("Shutdown hook at slot " + slot + " already registered");
    90                 throw new InternalError("Shutdown hook at slot " + slot + " already registered");
    98 
    91 
    99             if (!registerShutdownInProgress) {
    92             if (!registerShutdownInProgress) {
   100                 if (state > RUNNING)
    93                 if (currentRunningHook >= 0)
   101                     throw new IllegalStateException("Shutdown in progress");
    94                     throw new IllegalStateException("Shutdown in progress");
   102             } else {
    95             } else {
   103                 if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook))
    96                 if (VM.isShutdown() || slot <= currentRunningHook)
   104                     throw new IllegalStateException("Shutdown in progress");
    97                     throw new IllegalStateException("Shutdown in progress");
   105             }
    98             }
   106 
    99 
   107             hooks[slot] = hook;
   100             hooks[slot] = hook;
   108         }
   101         }
   109     }
   102     }
   110 
   103 
   111     /* Run all registered shutdown hooks
   104     /* Run all system shutdown hooks.
       
   105      *
       
   106      * The system shutdown hooks are run in the thread synchronized on
       
   107      * Shutdown.class.  Other threads calling Runtime::exit, Runtime::halt
       
   108      * or JNI DestroyJavaVM will block indefinitely.
       
   109      *
       
   110      * ApplicationShutdownHooks is registered as one single hook that starts
       
   111      * all application shutdown hooks and waits until they finish.
   112      */
   112      */
   113     private static void runHooks() {
   113     private static void runHooks() {
       
   114         synchronized (lock) {
       
   115             /* Guard against the possibility of a daemon thread invoking exit
       
   116              * after DestroyJavaVM initiates the shutdown sequence
       
   117              */
       
   118             if (VM.isShutdown()) return;
       
   119         }
       
   120 
   114         for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
   121         for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
   115             try {
   122             try {
   116                 Runnable hook;
   123                 Runnable hook;
   117                 synchronized (lock) {
   124                 synchronized (lock) {
   118                     // acquire the lock to make sure the hook registered during
   125                     // acquire the lock to make sure the hook registered during
   119                     // shutdown is visible here.
   126                     // shutdown is visible here.
   120                     currentRunningHook = i;
   127                     currentRunningHook = i;
   121                     hook = hooks[i];
   128                     hook = hooks[i];
   122                 }
   129                 }
   123                 if (hook != null) hook.run();
   130                 if (hook != null) hook.run();
   124             } catch(Throwable t) {
   131             } catch (Throwable t) {
   125                 if (t instanceof ThreadDeath) {
   132                 if (t instanceof ThreadDeath) {
   126                     ThreadDeath td = (ThreadDeath)t;
   133                     ThreadDeath td = (ThreadDeath)t;
   127                     throw td;
   134                     throw td;
   128                 }
   135                 }
   129             }
   136             }
   130         }
   137         }
       
   138 
       
   139         // set shutdown state
       
   140         VM.shutdown();
   131     }
   141     }
   132 
   142 
   133     /* The halt method is synchronized on the halt lock
   143     /* The halt method is synchronized on the halt lock
   134      * to avoid corruption of the delete-on-shutdown file list.
   144      * to avoid corruption of the delete-on-shutdown file list.
   135      * It invokes the true native halt method.
   145      * It invokes the true native halt method.
   140         }
   150         }
   141     }
   151     }
   142 
   152 
   143     static native void halt0(int status);
   153     static native void halt0(int status);
   144 
   154 
   145     /* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
       
   146     private static native void runAllFinalizers();
       
   147 
       
   148 
       
   149     /* The actual shutdown sequence is defined here.
       
   150      *
       
   151      * If it weren't for runFinalizersOnExit, this would be simple -- we'd just
       
   152      * run the hooks and then halt.  Instead we need to keep track of whether
       
   153      * we're running hooks or finalizers.  In the latter case a finalizer could
       
   154      * invoke exit(1) to cause immediate termination, while in the former case
       
   155      * any further invocations of exit(n), for any n, simply stall.  Note that
       
   156      * if on-exit finalizers are enabled they're run iff the shutdown is
       
   157      * initiated by an exit(0); they're never run on exit(n) for n != 0 or in
       
   158      * response to SIGINT, SIGTERM, etc.
       
   159      */
       
   160     private static void sequence() {
       
   161         synchronized (lock) {
       
   162             /* Guard against the possibility of a daemon thread invoking exit
       
   163              * after DestroyJavaVM initiates the shutdown sequence
       
   164              */
       
   165             if (state != HOOKS) return;
       
   166         }
       
   167         runHooks();
       
   168         boolean rfoe;
       
   169         synchronized (lock) {
       
   170             state = FINALIZERS;
       
   171             rfoe = runFinalizersOnExit;
       
   172         }
       
   173         if (rfoe) runAllFinalizers();
       
   174     }
       
   175 
       
   176 
       
   177     /* Invoked by Runtime.exit, which does all the security checks.
   155     /* Invoked by Runtime.exit, which does all the security checks.
   178      * Also invoked by handlers for system-provided termination events,
   156      * Also invoked by handlers for system-provided termination events,
   179      * which should pass a nonzero status code.
   157      * which should pass a nonzero status code.
   180      */
   158      */
   181     static void exit(int status) {
   159     static void exit(int status) {
   182         boolean runMoreFinalizers = false;
       
   183         synchronized (lock) {
   160         synchronized (lock) {
   184             if (status != 0) runFinalizersOnExit = false;
   161             if (status != 0 && VM.isShutdown()) {
   185             switch (state) {
   162                 /* Halt immediately on nonzero status */
   186             case RUNNING:       /* Initiate shutdown */
   163                 halt(status);
   187                 state = HOOKS;
       
   188                 break;
       
   189             case HOOKS:         /* Stall and halt */
       
   190                 break;
       
   191             case FINALIZERS:
       
   192                 if (status != 0) {
       
   193                     /* Halt immediately on nonzero status */
       
   194                     halt(status);
       
   195                 } else {
       
   196                     /* Compatibility with old behavior:
       
   197                      * Run more finalizers and then halt
       
   198                      */
       
   199                     runMoreFinalizers = runFinalizersOnExit;
       
   200                 }
       
   201                 break;
       
   202             }
   164             }
   203         }
       
   204         if (runMoreFinalizers) {
       
   205             runAllFinalizers();
       
   206             halt(status);
       
   207         }
   165         }
   208         synchronized (Shutdown.class) {
   166         synchronized (Shutdown.class) {
   209             /* Synchronize on the class object, causing any other thread
   167             /* Synchronize on the class object, causing any other thread
   210              * that attempts to initiate shutdown to stall indefinitely
   168              * that attempts to initiate shutdown to stall indefinitely
   211              */
   169              */
   212             sequence();
   170             runHooks();
   213             halt(status);
   171             halt(status);
   214         }
   172         }
   215     }
   173     }
   216 
   174 
   217 
   175 
   218     /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon
   176     /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon
   219      * thread has finished.  Unlike the exit method, this method does not
   177      * thread has finished.  Unlike the exit method, this method does not
   220      * actually halt the VM.
   178      * actually halt the VM.
   221      */
   179      */
   222     static void shutdown() {
   180     static void shutdown() {
   223         synchronized (lock) {
       
   224             switch (state) {
       
   225             case RUNNING:       /* Initiate shutdown */
       
   226                 state = HOOKS;
       
   227                 break;
       
   228             case HOOKS:         /* Stall and then return */
       
   229             case FINALIZERS:
       
   230                 break;
       
   231             }
       
   232         }
       
   233         synchronized (Shutdown.class) {
   181         synchronized (Shutdown.class) {
   234             sequence();
   182             runHooks();
   235         }
   183         }
   236     }
   184     }
   237 
   185 
   238 }
   186 }