1 /*
2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
49 super(finalizee, queue);
50 // push onto unfinalized
51 synchronized (lock) {
52 if (unfinalized != null) {
53 this.next = unfinalized;
54 unfinalized.prev = this;
55 }
56 unfinalized = this;
57 }
58 }
59
60 static ReferenceQueue<Object> getQueue() {
61 return queue;
62 }
63
64 /* Invoked by VM */
65 static void register(Object finalizee) {
66 new Finalizer(finalizee);
67 }
68
69 private void deregisterAndRunFinalizer(JavaLangAccess jla) {
70 synchronized (lock) {
71 if (this.next == this) // already finalized
72 return;
73 // unlink from unfinalized
74 if (unfinalized == this)
75 unfinalized = this.next;
76 else
77 this.prev.next = this.next;
78 if (this.next != null)
79 this.next.prev = this.prev;
80 this.prev = null;
81 this.next = this; // mark as finalized
82 }
83 runFinalizer(jla);
84 }
85
86 private void runFinalizer(JavaLangAccess jla) {
87 try {
88 Object finalizee = this.get();
89 if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
90 jla.invokeFinalize(finalizee);
91
92 /* Clear stack slot containing this variable, to decrease
93 the chances of false retention with a conservative GC */
94 finalizee = null;
95 }
96 } catch (Throwable x) { }
97 super.clear();
98 }
99
100 /* Create a privileged secondary finalizer thread in the system thread
101 group for the given Runnable, and wait for it to complete.
102
103 This method is used by both runFinalization and runFinalizersOnExit.
104 The former method invokes all pending finalizers, while the latter
105 invokes all uninvoked finalizers if on-exit finalization has been
106 enabled.
107
108 These two methods could have been implemented by offloading their work
109 to the regular finalizer thread and waiting for that thread to finish.
110 The advantage of creating a fresh thread, however, is that it insulates
111 invokers of these methods from a stalled or deadlocked finalizer thread.
112 */
113 private static void forkSecondaryFinalizer(final Runnable proc) {
114 AccessController.doPrivileged(
115 new PrivilegedAction<>() {
116 public Void run() {
117 ThreadGroup tg = Thread.currentThread().getThreadGroup();
118 for (ThreadGroup tgn = tg;
119 tgn != null;
120 tg = tgn, tgn = tg.getParent());
121 Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
122 sft.start();
123 try {
124 sft.join();
125 } catch (InterruptedException x) {
126 Thread.currentThread().interrupt();
127 }
128 return null;
129 }});
130 }
131
132 /* Called by Runtime.runFinalization() */
133 static void runFinalization() {
134 if (VM.initLevel() == 0) {
135 return;
136 }
137
138 forkSecondaryFinalizer(new Runnable() {
139 private volatile boolean running;
140 public void run() {
141 // in case of recursive call to run()
142 if (running)
143 return;
144 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
145 running = true;
146 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
147 f.deregisterAndRunFinalizer(jla);
148 }
149 });
150 }
151
152 /* Invoked by java.lang.Shutdown */
153 static void runAllFinalizers() {
154 if (VM.initLevel() == 0) {
155 return;
156 }
157
158 forkSecondaryFinalizer(new Runnable() {
159 private volatile boolean running;
160 public void run() {
161 // in case of recursive call to run()
162 if (running)
163 return;
164 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
165 running = true;
166 for (;;) {
167 // "pollFirst" from unfinalized
168 Finalizer f;
169 synchronized (lock) {
170 f = unfinalized;
171 if (f == null) break;
172 unfinalized = f.next;
173 if (unfinalized != null)
174 unfinalized.prev = null;
175 f.next = f; // mark as finalized
176 }
177 f.runFinalizer(jla);
178 }}});
179 }
180
181 private static class FinalizerThread extends Thread {
182 private volatile boolean running;
183 FinalizerThread(ThreadGroup g) {
184 super(g, null, "Finalizer", 0, false);
185 }
186 public void run() {
187 // in case of recursive call to run()
188 if (running)
189 return;
190
191 // Finalizer thread starts before System.initializeSystemClass
192 // is called. Wait until JavaLangAccess is available
193 while (VM.initLevel() == 0) {
194 // delay until VM completes initialization
195 try {
196 VM.awaitInitLevel(1);
197 } catch (InterruptedException x) {
198 // ignore and continue
199 }
200 }
201 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
202 running = true;
203 for (;;) {
204 try {
205 Finalizer f = (Finalizer)queue.remove();
206 f.deregisterAndRunFinalizer(jla);
207 } catch (InterruptedException x) {
208 // ignore and continue
209 }
210 }
211 }
212 }
213
214 static {
215 ThreadGroup tg = Thread.currentThread().getThreadGroup();
216 for (ThreadGroup tgn = tg;
217 tgn != null;
218 tg = tgn, tgn = tg.getParent());
219 Thread finalizer = new FinalizerThread(tg);
220 finalizer.setPriority(Thread.MAX_PRIORITY - 2);
221 finalizer.setDaemon(true);
222 finalizer.start();
223 }
224
225 }
|
1 /*
2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
49 super(finalizee, queue);
50 // push onto unfinalized
51 synchronized (lock) {
52 if (unfinalized != null) {
53 this.next = unfinalized;
54 unfinalized.prev = this;
55 }
56 unfinalized = this;
57 }
58 }
59
60 static ReferenceQueue<Object> getQueue() {
61 return queue;
62 }
63
64 /* Invoked by VM */
65 static void register(Object finalizee) {
66 new Finalizer(finalizee);
67 }
68
69 private void runFinalizer(JavaLangAccess jla) {
70 synchronized (lock) {
71 if (this.next == this) // already finalized
72 return;
73 // unlink from unfinalized
74 if (unfinalized == this)
75 unfinalized = this.next;
76 else
77 this.prev.next = this.next;
78 if (this.next != null)
79 this.next.prev = this.prev;
80 this.prev = null;
81 this.next = this; // mark as finalized
82 }
83
84 try {
85 Object finalizee = this.get();
86 if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
87 jla.invokeFinalize(finalizee);
88
89 // Clear stack slot containing this variable, to decrease
90 // the chances of false retention with a conservative GC
91 finalizee = null;
92 }
93 } catch (Throwable x) { }
94 super.clear();
95 }
96
97 /* Create a privileged secondary finalizer thread in the system thread
98 * group for the given Runnable, and wait for it to complete.
99 *
100 * This method is used by runFinalization.
101 *
102 * It could have been implemented by offloading their work to the
103 * regular finalizer thread and waiting for that thread to finish.
104 * The advantage of creating a fresh thread, however, is that it insulates
105 * invokers of these methods from a stalled or deadlocked finalizer thread.
106 */
107 private static void forkSecondaryFinalizer(final Runnable proc) {
108 AccessController.doPrivileged(
109 new PrivilegedAction<>() {
110 public Void run() {
111 ThreadGroup tg = Thread.currentThread().getThreadGroup();
112 for (ThreadGroup tgn = tg;
113 tgn != null;
114 tg = tgn, tgn = tg.getParent());
115 Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
116 sft.start();
117 try {
118 sft.join();
119 } catch (InterruptedException x) {
120 Thread.currentThread().interrupt();
121 }
122 return null;
123 }});
124 }
125
126 /* Called by Runtime.runFinalization() */
127 static void runFinalization() {
128 if (VM.initLevel() == 0) {
129 return;
130 }
131
132 forkSecondaryFinalizer(new Runnable() {
133 private volatile boolean running;
134 public void run() {
135 // in case of recursive call to run()
136 if (running)
137 return;
138 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
139 running = true;
140 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
141 f.runFinalizer(jla);
142 }
143 });
144 }
145
146 private static class FinalizerThread extends Thread {
147 private volatile boolean running;
148 FinalizerThread(ThreadGroup g) {
149 super(g, null, "Finalizer", 0, false);
150 }
151 public void run() {
152 // in case of recursive call to run()
153 if (running)
154 return;
155
156 // Finalizer thread starts before System.initializeSystemClass
157 // is called. Wait until JavaLangAccess is available
158 while (VM.initLevel() == 0) {
159 // delay until VM completes initialization
160 try {
161 VM.awaitInitLevel(1);
162 } catch (InterruptedException x) {
163 // ignore and continue
164 }
165 }
166 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
167 running = true;
168 for (;;) {
169 try {
170 Finalizer f = (Finalizer)queue.remove();
171 f.runFinalizer(jla);
172 } catch (InterruptedException x) {
173 // ignore and continue
174 }
175 }
176 }
177 }
178
179 static {
180 ThreadGroup tg = Thread.currentThread().getThreadGroup();
181 for (ThreadGroup tgn = tg;
182 tgn != null;
183 tg = tgn, tgn = tg.getParent());
184 Thread finalizer = new FinalizerThread(tg);
185 finalizer.setPriority(Thread.MAX_PRIORITY - 2);
186 finalizer.setDaemon(true);
187 finalizer.start();
188 }
189
190 }
|