/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Package-private utility class containing data structures and logic
* governing the virtual-machine shutdown sequence.
*
* @author Mark Reinhold
* @since 1.3
*/
class Shutdown {
/* Shutdown state */
/* Should we run all finalizers upon exit? */
private static boolean runFinalizersOnExit = false;
// The system shutdown hooks are registered with a predefined slot.
// The list of shutdown hooks is as follows:
// (0) Console restore hook
// (1) Application hooks
// (2) DeleteOnExit hook
// the index of the currently running shutdown hook to the hooks array
/* The preceding static fields are protected by this lock */
private static class Lock { };
/* Lock object for the native halt method */
/* Invoked by Runtime.runFinalizersOnExit */
synchronized (lock) {
}
}
/**
* Add a new shutdown hook. Checks the shutdown state and the hook itself,
* but does not do any security checks.
*
* The registerShutdownInProgress parameter should be false except
* registering the DeleteOnExitHook since the first file may
* be added to the delete on exit list by the application shutdown
* hooks.
*
* @params slot the slot in the shutdown hook array, whose element
* will be invoked in order during shutdown
* @params registerShutdownInProgress true to allow the hook
* to be registered even if the shutdown is in progress.
* @params hook the hook to be registered
*
* @throw IllegalStateException
* if registerShutdownInProgress is false and shutdown is in progress; or
* if registerShutdownInProgress is true and the shutdown process
* already passes the given slot
*/
synchronized (lock) {
if (!registerShutdownInProgress) {
throw new IllegalStateException("Shutdown in progress");
} else {
throw new IllegalStateException("Shutdown in progress");
}
}
}
/* Run all registered shutdown hooks
*/
private static void runHooks() {
for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
try {
synchronized (lock) {
// acquire the lock to make sure the hook registered during
// shutdown is visible here.
currentRunningHook = i;
}
} catch(Throwable t) {
if (t instanceof ThreadDeath) {
throw td;
}
}
}
}
/* The halt method is synchronized on the halt lock
* to avoid corruption of the delete-on-shutdown file list.
* It invokes the true native halt method.
*/
synchronized (haltLock) {
}
}
/* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
private static native void runAllFinalizers();
/* The actual shutdown sequence is defined here.
*
* If it weren't for runFinalizersOnExit, this would be simple -- we'd just
* run the hooks and then halt. Instead we need to keep track of whether
* we're running hooks or finalizers. In the latter case a finalizer could
* invoke exit(1) to cause immediate termination, while in the former case
* any further invocations of exit(n), for any n, simply stall. Note that
* if on-exit finalizers are enabled they're run iff the shutdown is
* initiated by an exit(0); they're never run on exit(n) for n != 0 or in
* response to SIGINT, SIGTERM, etc.
*/
private static void sequence() {
synchronized (lock) {
/* Guard against the possibility of a daemon thread invoking exit
* after DestroyJavaVM initiates the shutdown sequence
*/
}
runHooks();
boolean rfoe;
synchronized (lock) {
state = FINALIZERS;
}
if (rfoe) runAllFinalizers();
}
/* Invoked by Runtime.exit, which does all the security checks.
* Also invoked by handlers for system-provided termination events,
* which should pass a nonzero status code.
*/
boolean runMoreFinalizers = false;
synchronized (lock) {
switch (state) {
case RUNNING: /* Initiate shutdown */
break;
case HOOKS: /* Stall and halt */
break;
case FINALIZERS:
if (status != 0) {
/* Halt immediately on nonzero status */
} else {
/* Compatibility with old behavior:
* Run more finalizers and then halt
*/
}
break;
}
}
if (runMoreFinalizers) {
}
synchronized (Shutdown.class) {
/* Synchronize on the class object, causing any other thread
* that attempts to initiate shutdown to stall indefinitely
*/
sequence();
}
}
/* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon
* thread has finished. Unlike the exit method, this method does not
* actually halt the VM.
*/
static void shutdown() {
synchronized (lock) {
switch (state) {
case RUNNING: /* Initiate shutdown */
break;
case HOOKS: /* Stall and then return */
case FINALIZERS:
break;
}
}
synchronized (Shutdown.class) {
sequence();
}
}
}