1 /* |
1 /* |
2 * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
24 */ |
24 */ |
25 |
25 |
26 package java.lang; |
26 package java.lang; |
27 |
27 |
28 |
28 |
|
29 import jdk.internal.misc.VM; |
|
30 |
29 /** |
31 /** |
30 * Package-private utility class containing data structures and logic |
32 * Package-private utility class containing data structures and logic |
31 * governing the virtual-machine shutdown sequence. |
33 * governing the virtual-machine shutdown sequence. |
32 * |
34 * |
33 * @author Mark Reinhold |
35 * @author Mark Reinhold |
34 * @since 1.3 |
36 * @since 1.3 |
|
37 * |
|
38 * @see java.io.Console |
|
39 * @see ApplicationShutdownHooks |
|
40 * @see java.io.DeleteOnExitHook |
35 */ |
41 */ |
36 |
42 |
37 class Shutdown { |
43 class Shutdown { |
38 |
44 |
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 |
|
48 // The system shutdown hooks are registered with a predefined slot. |
45 // The system shutdown hooks are registered with a predefined slot. |
49 // The list of shutdown hooks is as follows: |
46 // The list of shutdown hooks is as follows: |
50 // (0) Console restore hook |
47 // (0) Console restore hook |
51 // (1) Application hooks |
48 // (1) ApplicationShutdownHooks that invokes all registered application |
|
49 // shutdown hooks and waits until they finish |
52 // (2) DeleteOnExit hook |
50 // (2) DeleteOnExit hook |
53 private static final int MAX_SYSTEM_HOOKS = 10; |
51 private static final int MAX_SYSTEM_HOOKS = 10; |
54 private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; |
52 private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; |
55 |
53 |
56 // the index of the currently running shutdown hook to the hooks array |
54 // the index of the currently running shutdown hook to the hooks array |
57 private static int currentRunningHook = 0; |
55 private static int currentRunningHook = -1; |
58 |
56 |
59 /* The preceding static fields are protected by this lock */ |
57 /* The preceding static fields are protected by this lock */ |
60 private static class Lock { }; |
58 private static class Lock { }; |
61 private static Object lock = new Lock(); |
59 private static Object lock = new Lock(); |
62 |
60 |
63 /* Lock object for the native halt method */ |
61 /* Lock object for the native halt method */ |
64 private static Object haltLock = new Lock(); |
62 private static Object haltLock = new Lock(); |
65 |
63 |
66 /* Invoked by Runtime.runFinalizersOnExit */ |
|
67 static void setRunFinalizersOnExit(boolean run) { |
|
68 synchronized (lock) { |
|
69 runFinalizersOnExit = run; |
|
70 } |
|
71 } |
|
72 |
|
73 |
|
74 /** |
64 /** |
75 * Add a new shutdown hook. Checks the shutdown state and the hook itself, |
65 * Add a new system shutdown hook. Checks the shutdown state and |
76 * but does not do any security checks. |
66 * the hook itself, but does not do any security checks. |
77 * |
67 * |
78 * The registerShutdownInProgress parameter should be false except |
68 * The registerShutdownInProgress parameter should be false except |
79 * registering the DeleteOnExitHook since the first file may |
69 * registering the DeleteOnExitHook since the first file may |
80 * be added to the delete on exit list by the application shutdown |
70 * be added to the delete on exit list by the application shutdown |
81 * hooks. |
71 * hooks. |
90 * if registerShutdownInProgress is false and shutdown is in progress; or |
80 * if registerShutdownInProgress is false and shutdown is in progress; or |
91 * if registerShutdownInProgress is true and the shutdown process |
81 * if registerShutdownInProgress is true and the shutdown process |
92 * already passes the given slot |
82 * already passes the given slot |
93 */ |
83 */ |
94 static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { |
84 static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { |
|
85 if (slot < 0 || slot >= MAX_SYSTEM_HOOKS) { |
|
86 throw new IllegalArgumentException("Invalid slot: " + slot); |
|
87 } |
95 synchronized (lock) { |
88 synchronized (lock) { |
96 if (hooks[slot] != null) |
89 if (hooks[slot] != null) |
97 throw new InternalError("Shutdown hook at slot " + slot + " already registered"); |
90 throw new InternalError("Shutdown hook at slot " + slot + " already registered"); |
98 |
91 |
99 if (!registerShutdownInProgress) { |
92 if (!registerShutdownInProgress) { |
100 if (state > RUNNING) |
93 if (currentRunningHook >= 0) |
101 throw new IllegalStateException("Shutdown in progress"); |
94 throw new IllegalStateException("Shutdown in progress"); |
102 } else { |
95 } else { |
103 if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) |
96 if (VM.isShutdown() || slot <= currentRunningHook) |
104 throw new IllegalStateException("Shutdown in progress"); |
97 throw new IllegalStateException("Shutdown in progress"); |
105 } |
98 } |
106 |
99 |
107 hooks[slot] = hook; |
100 hooks[slot] = hook; |
108 } |
101 } |
109 } |
102 } |
110 |
103 |
111 /* Run all registered shutdown hooks |
104 /* Run all system shutdown hooks. |
|
105 * |
|
106 * The system shutdown hooks are run in the thread synchronized on |
|
107 * Shutdown.class. Other threads calling Runtime::exit, Runtime::halt |
|
108 * or JNI DestroyJavaVM will block indefinitely. |
|
109 * |
|
110 * ApplicationShutdownHooks is registered as one single hook that starts |
|
111 * all application shutdown hooks and waits until they finish. |
112 */ |
112 */ |
113 private static void runHooks() { |
113 private static void runHooks() { |
|
114 synchronized (lock) { |
|
115 /* Guard against the possibility of a daemon thread invoking exit |
|
116 * after DestroyJavaVM initiates the shutdown sequence |
|
117 */ |
|
118 if (VM.isShutdown()) return; |
|
119 } |
|
120 |
114 for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { |
121 for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { |
115 try { |
122 try { |
116 Runnable hook; |
123 Runnable hook; |
117 synchronized (lock) { |
124 synchronized (lock) { |
118 // acquire the lock to make sure the hook registered during |
125 // acquire the lock to make sure the hook registered during |
119 // shutdown is visible here. |
126 // shutdown is visible here. |
120 currentRunningHook = i; |
127 currentRunningHook = i; |
121 hook = hooks[i]; |
128 hook = hooks[i]; |
122 } |
129 } |
123 if (hook != null) hook.run(); |
130 if (hook != null) hook.run(); |
124 } catch(Throwable t) { |
131 } catch (Throwable t) { |
125 if (t instanceof ThreadDeath) { |
132 if (t instanceof ThreadDeath) { |
126 ThreadDeath td = (ThreadDeath)t; |
133 ThreadDeath td = (ThreadDeath)t; |
127 throw td; |
134 throw td; |
128 } |
135 } |
129 } |
136 } |
130 } |
137 } |
|
138 |
|
139 // set shutdown state |
|
140 VM.shutdown(); |
131 } |
141 } |
132 |
142 |
133 /* The halt method is synchronized on the halt lock |
143 /* The halt method is synchronized on the halt lock |
134 * to avoid corruption of the delete-on-shutdown file list. |
144 * to avoid corruption of the delete-on-shutdown file list. |
135 * It invokes the true native halt method. |
145 * It invokes the true native halt method. |
140 } |
150 } |
141 } |
151 } |
142 |
152 |
143 static native void halt0(int status); |
153 static native void halt0(int status); |
144 |
154 |
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. |
155 /* Invoked by Runtime.exit, which does all the security checks. |
178 * Also invoked by handlers for system-provided termination events, |
156 * Also invoked by handlers for system-provided termination events, |
179 * which should pass a nonzero status code. |
157 * which should pass a nonzero status code. |
180 */ |
158 */ |
181 static void exit(int status) { |
159 static void exit(int status) { |
182 boolean runMoreFinalizers = false; |
|
183 synchronized (lock) { |
160 synchronized (lock) { |
184 if (status != 0) runFinalizersOnExit = false; |
161 if (status != 0 && VM.isShutdown()) { |
185 switch (state) { |
162 /* Halt immediately on nonzero status */ |
186 case RUNNING: /* Initiate shutdown */ |
163 halt(status); |
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 } |
164 } |
203 } |
|
204 if (runMoreFinalizers) { |
|
205 runAllFinalizers(); |
|
206 halt(status); |
|
207 } |
165 } |
208 synchronized (Shutdown.class) { |
166 synchronized (Shutdown.class) { |
209 /* Synchronize on the class object, causing any other thread |
167 /* Synchronize on the class object, causing any other thread |
210 * that attempts to initiate shutdown to stall indefinitely |
168 * that attempts to initiate shutdown to stall indefinitely |
211 */ |
169 */ |
212 sequence(); |
170 runHooks(); |
213 halt(status); |
171 halt(status); |
214 } |
172 } |
215 } |
173 } |
216 |
174 |
217 |
175 |
218 /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon |
176 /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon |
219 * thread has finished. Unlike the exit method, this method does not |
177 * thread has finished. Unlike the exit method, this method does not |
220 * actually halt the VM. |
178 * actually halt the VM. |
221 */ |
179 */ |
222 static void shutdown() { |
180 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) { |
181 synchronized (Shutdown.class) { |
234 sequence(); |
182 runHooks(); |
235 } |
183 } |
236 } |
184 } |
237 |
185 |
238 } |
186 } |