- /*
- * @(#)Shutdown.java 1.7 00/02/02
- *
- * Copyright 1999, 2000 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the proprietary information of Sun Microsystems, Inc.
- * Use is subject to license terms.
- *
- */
-
- package java.lang;
-
- import java.util.HashSet;
- import java.util.Iterator;
-
-
- /**
- * Package-private utility class containing data structures and logic
- * governing the virtual-machine shutdown sequence.
- *
- * @author Mark Reinhold
- * @version 1.7, 00/02/02
- * @since 1.3
- */
-
- class Shutdown {
-
- /* Wrapper class for registered hooks, to ensure that hook identity is
- * object identity rather than .equals identity
- */
- private static class WrappedHook {
-
- private Thread hook;
-
- WrappedHook(Thread t) {
- hook = t;
- }
-
- public int hashCode() {
- return System.identityHashCode(hook);
- }
-
- public boolean equals(Object o) {
- if (!(o instanceof WrappedHook)) return false;
- return (((WrappedHook)o).hook == hook);
- }
-
- }
-
-
- /* Shutdown state */
- private static final int RUNNING = 0;
- private static final int HOOKS = 1;
- private static final int FINALIZERS = 2;
- private static int state = RUNNING;
-
- /* Should we run all finalizers upon exit? */
- private static boolean runFinalizersOnExit = false;
-
- /* The set of registered, wrapped hooks, or null if there aren't any */
- private static HashSet hooks = null;
-
- /* The preceding static fields are protected by this lock */
- private static class Lock { };
- private static Object lock = new Lock();
-
-
- /* Invoked by Runtime.runFinalizersOnExit */
- static void setRunFinalizersOnExit(boolean run) {
- synchronized (lock) {
- runFinalizersOnExit = run;
- }
- }
-
-
- /* Add a new shutdown hook. Checks the shutdown state and the hook itself,
- * but does not do any security checks.
- */
- static void add(Thread hook) {
- synchronized (lock) {
- if (state > RUNNING)
- throw new IllegalStateException("Shutdown in progress");
- if (hook.isAlive())
- throw new IllegalArgumentException("Hook already running");
- if (hooks == null) {
- hooks = new HashSet(11);
- hooks.add(new WrappedHook(hook));
- Terminator.setup();
- } else {
- WrappedHook wh = new WrappedHook(hook);
- if (hooks.contains(wh))
- throw new IllegalArgumentException("Hook previously registered");
- hooks.add(wh);
- }
- }
- }
-
-
- /* Remove a previously-registered hook. Like the add method, this method
- * does not do any security checks.
- */
- static boolean remove(Thread hook) {
- synchronized (lock) {
- if (state > RUNNING)
- throw new IllegalStateException("Shutdown in progress");
- if (hook == null) throw new NullPointerException();
- if (hooks == null) {
- return false;
- } else {
- boolean rv = hooks.remove(new WrappedHook(hook));
- if (rv && hooks.isEmpty()) {
- hooks = null;
- Terminator.teardown();
- }
- return rv;
- }
- }
- }
-
-
- /* Run all registered shutdown hooks
- */
- private static void runHooks() {
- /* We needn't bother acquiring the lock just to read the hooks field,
- * since the hooks can't be modified once shutdown is in progress
- */
- if (hooks == null) return;
- for (Iterator i = hooks.iterator(); i.hasNext();) {
- ((WrappedHook)(i.next())).hook.start();
- }
- for (Iterator i = hooks.iterator(); i.hasNext();) {
- try {
- ((WrappedHook)(i.next())).hook.join();
- } catch (InterruptedException x) {
- continue;
- }
- }
- }
-
-
- /* The true native halt method; also invoked by Runtime.halt
- * after doing the necessary security checks
- */
- static native void halt(int status);
-
- /* 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
- */
- if (state != HOOKS) return;
- }
- runHooks();
- boolean rfoe;
- synchronized (lock) {
- state = FINALIZERS;
- rfoe = runFinalizersOnExit;
- }
- 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.
- */
- static void exit(int status) {
- boolean runMoreFinalizers = false;
- synchronized (lock) {
- if (status != 0) runFinalizersOnExit = false;
- switch (state) {
- case RUNNING: /* Initiate shutdown */
- state = HOOKS;
- break;
- case HOOKS: /* Stall and halt */
- break;
- case FINALIZERS:
- if (status != 0) {
- /* Halt immediately on nonzero status */
- halt(status);
- } else {
- /* Compatibility with old behavior:
- * Run more finalizers and then halt
- */
- runMoreFinalizers = runFinalizersOnExit;
- }
- break;
- }
- }
- if (runMoreFinalizers) {
- runAllFinalizers();
- halt(status);
- }
- synchronized (Shutdown.class) {
- /* Synchronize on the class object, causing any other thread
- * that attempts to initiate shutdown to stall indefinitely
- */
- sequence();
- halt(status);
- }
- }
-
-
- /* 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 */
- state = HOOKS;
- break;
- case HOOKS: /* Stall and then return */
- case FINALIZERS:
- break;
- }
- }
- synchronized (Shutdown.class) {
- sequence();
- }
- }
-
- }