blob: 18e32d96f8e3a0db64eda0312976ff087ec9b105 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
26package java.lang;
27
28import java.util.ArrayList;
29
30
31/**
32 * Package-private utility class containing data structures and logic
33 * governing the virtual-machine shutdown sequence.
34 *
35 * @author Mark Reinhold
36 * @since 1.3
37 */
38
39class Shutdown {
40
41 /* Shutdown state */
42 private static final int RUNNING = 0;
43 private static final int HOOKS = 1;
44 private static final int FINALIZERS = 2;
45 private static int state = RUNNING;
46
47 /* Should we run all finalizers upon exit? */
48 private static boolean runFinalizersOnExit = false;
49
50 /* The set of registered, wrapped hooks, or null if there aren't any */
51 private static ArrayList<Runnable> hooks = new ArrayList<Runnable>();
52
53 /* The preceding static fields are protected by this lock */
54 private static class Lock { };
55 private static Object lock = new Lock();
56
57 /* Lock object for the native halt method */
58 private static Object haltLock = new Lock();
59
60 /* Invoked by Runtime.runFinalizersOnExit */
61 static void setRunFinalizersOnExit(boolean run) {
62 synchronized (lock) {
63 runFinalizersOnExit = run;
64 }
65 }
66
67
68 /* Add a new shutdown hook. Checks the shutdown state and the hook itself,
69 * but does not do any security checks.
70 */
71 static void add(Runnable hook) {
72 synchronized (lock) {
73 if (state > RUNNING)
74 throw new IllegalStateException("Shutdown in progress");
75
76 hooks.add(hook);
77 }
78 }
79
80
81 /* Remove a previously-registered hook. Like the add method, this method
82 * does not do any security checks.
83 */
84 static boolean remove(Runnable hook) {
85 synchronized (lock) {
86 if (state > RUNNING)
87 throw new IllegalStateException("Shutdown in progress");
88 if (hook == null) throw new NullPointerException();
89 if (hooks == null) {
90 return false;
91 } else {
92 return hooks.remove(hook);
93 }
94 }
95 }
96
97
98 /* Run all registered shutdown hooks
99 */
100 private static void runHooks() {
101 /* We needn't bother acquiring the lock just to read the hooks field,
102 * since the hooks can't be modified once shutdown is in progress
103 */
104 for (Runnable hook : hooks) {
105 try {
106 hook.run();
107 } catch(Throwable t) {
108 if (t instanceof ThreadDeath) {
109 ThreadDeath td = (ThreadDeath)t;
110 throw td;
111 }
112 }
113 }
114 }
115
116 /* The halt method is synchronized on the halt lock
117 * to avoid corruption of the delete-on-shutdown file list.
118 * It invokes the true native halt method.
119 */
120 static void halt(int status) {
121 synchronized (haltLock) {
122 halt0(status);
123 }
124 }
125
126 static native void halt0(int status);
127
128 /* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
129 private static native void runAllFinalizers();
130
131
132 /* The actual shutdown sequence is defined here.
133 *
134 * If it weren't for runFinalizersOnExit, this would be simple -- we'd just
135 * run the hooks and then halt. Instead we need to keep track of whether
136 * we're running hooks or finalizers. In the latter case a finalizer could
137 * invoke exit(1) to cause immediate termination, while in the former case
138 * any further invocations of exit(n), for any n, simply stall. Note that
139 * if on-exit finalizers are enabled they're run iff the shutdown is
140 * initiated by an exit(0); they're never run on exit(n) for n != 0 or in
141 * response to SIGINT, SIGTERM, etc.
142 */
143 private static void sequence() {
144 synchronized (lock) {
145 /* Guard against the possibility of a daemon thread invoking exit
146 * after DestroyJavaVM initiates the shutdown sequence
147 */
148 if (state != HOOKS) return;
149 }
150 runHooks();
151 boolean rfoe;
152 synchronized (lock) {
153 state = FINALIZERS;
154 rfoe = runFinalizersOnExit;
155 }
156 if (rfoe) runAllFinalizers();
157 }
158
159
160 /* Invoked by Runtime.exit, which does all the security checks.
161 * Also invoked by handlers for system-provided termination events,
162 * which should pass a nonzero status code.
163 */
164 static void exit(int status) {
165 boolean runMoreFinalizers = false;
166 synchronized (lock) {
167 if (status != 0) runFinalizersOnExit = false;
168 switch (state) {
169 case RUNNING: /* Initiate shutdown */
170 state = HOOKS;
171 break;
172 case HOOKS: /* Stall and halt */
173 break;
174 case FINALIZERS:
175 if (status != 0) {
176 /* Halt immediately on nonzero status */
177 halt(status);
178 } else {
179 /* Compatibility with old behavior:
180 * Run more finalizers and then halt
181 */
182 runMoreFinalizers = runFinalizersOnExit;
183 }
184 break;
185 }
186 }
187 if (runMoreFinalizers) {
188 runAllFinalizers();
189 halt(status);
190 }
191 synchronized (Shutdown.class) {
192 /* Synchronize on the class object, causing any other thread
193 * that attempts to initiate shutdown to stall indefinitely
194 */
195 sequence();
196 halt(status);
197 }
198 }
199
200
201 /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon
202 * thread has finished. Unlike the exit method, this method does not
203 * actually halt the VM.
204 */
205 static void shutdown() {
206 synchronized (lock) {
207 switch (state) {
208 case RUNNING: /* Initiate shutdown */
209 state = HOOKS;
210 break;
211 case HOOKS: /* Stall and then return */
212 case FINALIZERS:
213 break;
214 }
215 }
216 synchronized (Shutdown.class) {
217 sequence();
218 }
219 }
220
221}