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
23 * questions.
24 */
25
26 package java.lang.ref;
27
28 import java.security.PrivilegedAction;
29 import java.security.AccessController;
30 import jdk.internal.misc.JavaLangAccess;
31 import jdk.internal.misc.SharedSecrets;
32 import jdk.internal.misc.VM;
33
34 final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
35 same package as the Reference
36 class */
37
38 private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
39
40 /** Head of doubly linked list of Finalizers awaiting finalization. */
41 private static Finalizer unfinalized = null;
42
43 /** Lock guarding access to unfinalized list. */
44 private static final Object lock = new Object();
45
46 private Finalizer next, prev;
47
48 private Finalizer(Object finalizee) {
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 the 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 that method 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 }
191