KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > lang > Shutdown


1 /*
2  * @(#)Shutdown.java 1.11 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.lang;
9
10 import java.util.HashSet JavaDoc;
11 import java.util.Iterator JavaDoc;
12
13
14 /**
15  * Package-private utility class containing data structures and logic
16  * governing the virtual-machine shutdown sequence.
17  *
18  * @author Mark Reinhold
19  * @version 1.11, 03/12/19
20  * @since 1.3
21  */

22
23 class Shutdown {
24
25     /* Wrapper class for registered hooks, to ensure that hook identity is
26      * object identity rather than .equals identity
27      */

28     private static class WrappedHook {
29
30     private Thread JavaDoc hook;
31
32     WrappedHook(Thread JavaDoc t) {
33         hook = t;
34     }
35
36     public int hashCode() {
37         return System.identityHashCode(hook);
38     }
39
40     public boolean equals(Object JavaDoc o) {
41         if (!(o instanceof WrappedHook)) return false;
42         return (((WrappedHook)o).hook == hook);
43     }
44
45     }
46
47
48     /* Shutdown state */
49     private static final int RUNNING = 0;
50     private static final int HOOKS = 1;
51     private static final int FINALIZERS = 2;
52     private static int state = RUNNING;
53
54     /* Should we run all finalizers upon exit? */
55     private static boolean runFinalizersOnExit = false;
56
57     /* The set of registered, wrapped hooks, or null if there aren't any */
58     private static HashSet JavaDoc hooks = null;
59
60     /* The preceding static fields are protected by this lock */
61     private static class Lock { };
62     private static Object JavaDoc lock = new Lock();
63
64     /* Lock object for the native halt method */
65     private static Object JavaDoc haltLock = new Lock();
66
67     /* Invoked by Runtime.runFinalizersOnExit */
68     static void setRunFinalizersOnExit(boolean run) {
69     synchronized (lock) {
70         runFinalizersOnExit = run;
71     }
72     }
73
74
75     /* Add a new shutdown hook. Checks the shutdown state and the hook itself,
76      * but does not do any security checks.
77      */

78     static void add(Thread JavaDoc hook) {
79     synchronized (lock) {
80         if (state > RUNNING)
81         throw new IllegalStateException JavaDoc("Shutdown in progress");
82         if (hook.isAlive())
83         throw new IllegalArgumentException JavaDoc("Hook already running");
84         if (hooks == null) {
85         hooks = new HashSet JavaDoc(11);
86         hooks.add(new WrappedHook(hook));
87         Terminator.setup();
88         } else {
89         WrappedHook wh = new WrappedHook(hook);
90         if (hooks.contains(wh))
91             throw new IllegalArgumentException JavaDoc("Hook previously registered");
92         hooks.add(wh);
93         }
94     }
95     }
96
97
98     /* Remove a previously-registered hook. Like the add method, this method
99      * does not do any security checks.
100      */

101     static boolean remove(Thread JavaDoc hook) {
102     synchronized (lock) {
103         if (state > RUNNING)
104         throw new IllegalStateException JavaDoc("Shutdown in progress");
105         if (hook == null) throw new NullPointerException JavaDoc();
106         if (hooks == null) {
107         return false;
108         } else {
109         boolean rv = hooks.remove(new WrappedHook(hook));
110         if (rv && hooks.isEmpty()) {
111             hooks = null;
112             Terminator.teardown();
113         }
114         return rv;
115         }
116     }
117     }
118
119
120     /* Run all registered shutdown hooks
121      */

122     private static void runHooks() {
123     /* We needn't bother acquiring the lock just to read the hooks field,
124      * since the hooks can't be modified once shutdown is in progress
125      */

126     if (hooks == null) return;
127     for (Iterator JavaDoc i = hooks.iterator(); i.hasNext();) {
128         ((WrappedHook)(i.next())).hook.start();
129     }
130     for (Iterator JavaDoc i = hooks.iterator(); i.hasNext();) {
131         try {
132         ((WrappedHook)(i.next())).hook.join();
133         } catch (InterruptedException JavaDoc x) {
134         continue;
135         }
136     }
137     }
138
139     /* The halt method is synchronized on the halt lock
140      * to avoid corruption of the delete-on-shutdown file list.
141      * It invokes the true native halt method.
142      */

143     static void halt(int status) {
144         synchronized (haltLock) {
145             halt0(status);
146         }
147     }
148
149     static native void halt0(int status);
150
151     /* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
152     private static native void runAllFinalizers();
153
154
155     /* The actual shutdown sequence is defined here.
156      *
157      * If it weren't for runFinalizersOnExit, this would be simple -- we'd just
158      * run the hooks and then halt. Instead we need to keep track of whether
159      * we're running hooks or finalizers. In the latter case a finalizer could
160      * invoke exit(1) to cause immediate termination, while in the former case
161      * any further invocations of exit(n), for any n, simply stall. Note that
162      * if on-exit finalizers are enabled they're run iff the shutdown is
163      * initiated by an exit(0); they're never run on exit(n) for n != 0 or in
164      * response to SIGINT, SIGTERM, etc.
165      */

166     private static void sequence() {
167     synchronized (lock) {
168         /* Guard against the possibility of a daemon thread invoking exit
169          * after DestroyJavaVM initiates the shutdown sequence
170          */

171         if (state != HOOKS) return;
172     }
173     runHooks();
174     boolean rfoe;
175     synchronized (lock) {
176         state = FINALIZERS;
177         rfoe = runFinalizersOnExit;
178     }
179     if (rfoe) runAllFinalizers();
180     }
181
182
183     /* Invoked by Runtime.exit, which does all the security checks.
184      * Also invoked by handlers for system-provided termination events,
185      * which should pass a nonzero status code.
186      */

187     static void exit(int status) {
188     boolean runMoreFinalizers = false;
189     synchronized (lock) {
190         if (status != 0) runFinalizersOnExit = false;
191         switch (state) {
192         case RUNNING: /* Initiate shutdown */
193         state = HOOKS;
194         break;
195         case HOOKS: /* Stall and halt */
196         break;
197         case FINALIZERS:
198         if (status != 0) {
199             /* Halt immediately on nonzero status */
200             halt(status);
201         } else {
202             /* Compatibility with old behavior:
203              * Run more finalizers and then halt
204              */

205             runMoreFinalizers = runFinalizersOnExit;
206         }
207         break;
208         }
209     }
210     if (runMoreFinalizers) {
211         runAllFinalizers();
212         halt(status);
213     }
214     synchronized (Shutdown JavaDoc.class) {
215         /* Synchronize on the class object, causing any other thread
216              * that attempts to initiate shutdown to stall indefinitely
217          */

218         sequence();
219         halt(status);
220     }
221     }
222
223
224     /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon
225      * thread has finished. Unlike the exit method, this method does not
226      * actually halt the VM.
227      */

228     static void shutdown() {
229     synchronized (lock) {
230         switch (state) {
231         case RUNNING: /* Initiate shutdown */
232         state = HOOKS;
233         break;
234         case HOOKS: /* Stall and then return */
235         case FINALIZERS:
236         break;
237         }
238     }
239     synchronized (Shutdown JavaDoc.class) {
240         sequence();
241     }
242     }
243
244 }
245
Popular Tags