author | martin |
Sun, 14 Jun 2009 14:33:30 -0700 | |
changeset 2947 | b0135c99348e |
parent 2703 | acd4d6a53e3e |
child 5506 | 202f599c92aa |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
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 |
|
7 |
* published by the Free Software Foundation. Sun designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Sun in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 |
* have any questions. |
|
24 |
*/ |
|
25 |
||
26 |
package java.lang; |
|
27 |
||
28 |
||
29 |
/** |
|
30 |
* Package-private utility class containing data structures and logic |
|
31 |
* governing the virtual-machine shutdown sequence. |
|
32 |
* |
|
33 |
* @author Mark Reinhold |
|
34 |
* @since 1.3 |
|
35 |
*/ |
|
36 |
||
37 |
class Shutdown { |
|
38 |
||
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 |
||
2277
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
48 |
// The system shutdown hooks are registered with a predefined slot. |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
49 |
// The list of shutdown hooks is as follows: |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
50 |
// (0) Console restore hook |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
51 |
// (1) Application hooks |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
52 |
// (2) DeleteOnExit hook |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
53 |
private static final int MAX_SYSTEM_HOOKS = 10; |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
54 |
private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; |
2 | 55 |
|
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
56 |
// the index of the currently running shutdown hook to the hooks array |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
57 |
private static int currentRunningHook = 0; |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
58 |
|
2 | 59 |
/* The preceding static fields are protected by this lock */ |
60 |
private static class Lock { }; |
|
61 |
private static Object lock = new Lock(); |
|
62 |
||
63 |
/* Lock object for the native halt method */ |
|
64 |
private static Object haltLock = new Lock(); |
|
65 |
||
66 |
/* Invoked by Runtime.runFinalizersOnExit */ |
|
67 |
static void setRunFinalizersOnExit(boolean run) { |
|
68 |
synchronized (lock) { |
|
69 |
runFinalizersOnExit = run; |
|
70 |
} |
|
71 |
} |
|
72 |
||
73 |
||
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
74 |
/** |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
75 |
* Add a new shutdown hook. Checks the shutdown state and the hook itself, |
2 | 76 |
* but does not do any security checks. |
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
77 |
* |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
78 |
* The registerShutdownInProgress parameter should be false except |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
79 |
* registering the DeleteOnExitHook since the first file may |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
80 |
* be added to the delete on exit list by the application shutdown |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
81 |
* hooks. |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
82 |
* |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
83 |
* @params slot the slot in the shutdown hook array, whose element |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
84 |
* will be invoked in order during shutdown |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
85 |
* @params registerShutdownInProgress true to allow the hook |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
86 |
* to be registered even if the shutdown is in progress. |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
87 |
* @params hook the hook to be registered |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
88 |
* |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
89 |
* @throw IllegalStateException |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
90 |
* if registerShutdownInProgress is false and shutdown is in progress; or |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
91 |
* if registerShutdownInProgress is true and the shutdown process |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
92 |
* already passes the given slot |
2 | 93 |
*/ |
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
94 |
static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { |
2 | 95 |
synchronized (lock) { |
2277
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
96 |
if (hooks[slot] != null) |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
97 |
throw new InternalError("Shutdown hook at slot " + slot + " already registered"); |
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
98 |
|
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
99 |
if (!registerShutdownInProgress) { |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
100 |
if (state > RUNNING) |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
101 |
throw new IllegalStateException("Shutdown in progress"); |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
102 |
} else { |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
103 |
if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
104 |
throw new IllegalStateException("Shutdown in progress"); |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
105 |
} |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
106 |
|
2277
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
107 |
hooks[slot] = hook; |
2 | 108 |
} |
109 |
} |
|
110 |
||
111 |
/* Run all registered shutdown hooks |
|
112 |
*/ |
|
113 |
private static void runHooks() { |
|
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
114 |
for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { |
2 | 115 |
try { |
2703
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
116 |
Runnable hook; |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
117 |
synchronized (lock) { |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
118 |
// acquire the lock to make sure the hook registered during |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
119 |
// shutdown is visible here. |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
120 |
currentRunningHook = i; |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
121 |
hook = hooks[i]; |
acd4d6a53e3e
6829503: addShutdownHook fails if called after shutdown has commenced.
mchung
parents:
2277
diff
changeset
|
122 |
} |
2277
445a331b4a8b
6810254: Lazily instantiate the shared secret access objects
mchung
parents:
2
diff
changeset
|
123 |
if (hook != null) hook.run(); |
2 | 124 |
} catch(Throwable t) { |
125 |
if (t instanceof ThreadDeath) { |
|
126 |
ThreadDeath td = (ThreadDeath)t; |
|
127 |
throw td; |
|
128 |
} |
|
129 |
} |
|
130 |
} |
|
131 |
} |
|
132 |
||
133 |
/* The halt method is synchronized on the halt lock |
|
134 |
* to avoid corruption of the delete-on-shutdown file list. |
|
135 |
* It invokes the true native halt method. |
|
136 |
*/ |
|
137 |
static void halt(int status) { |
|
138 |
synchronized (haltLock) { |
|
139 |
halt0(status); |
|
140 |
} |
|
141 |
} |
|
142 |
||
143 |
static native void halt0(int status); |
|
144 |
||
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. |
|
178 |
* Also invoked by handlers for system-provided termination events, |
|
179 |
* which should pass a nonzero status code. |
|
180 |
*/ |
|
181 |
static void exit(int status) { |
|
182 |
boolean runMoreFinalizers = false; |
|
183 |
synchronized (lock) { |
|
184 |
if (status != 0) runFinalizersOnExit = false; |
|
185 |
switch (state) { |
|
186 |
case RUNNING: /* Initiate shutdown */ |
|
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 |
} |
|
203 |
} |
|
204 |
if (runMoreFinalizers) { |
|
205 |
runAllFinalizers(); |
|
206 |
halt(status); |
|
207 |
} |
|
208 |
synchronized (Shutdown.class) { |
|
209 |
/* Synchronize on the class object, causing any other thread |
|
210 |
* that attempts to initiate shutdown to stall indefinitely |
|
211 |
*/ |
|
212 |
sequence(); |
|
213 |
halt(status); |
|
214 |
} |
|
215 |
} |
|
216 |
||
217 |
||
218 |
/* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon |
|
219 |
* thread has finished. Unlike the exit method, this method does not |
|
220 |
* actually halt the VM. |
|
221 |
*/ |
|
222 |
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) { |
|
234 |
sequence(); |
|
235 |
} |
|
236 |
} |
|
237 |
||
238 |
} |