1 /*
2 * Copyright 1997-2004 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.ref;
27
28 import java.security.PrivilegedAction;
29 import java.security.AccessController;
30
31
32 final class Finalizer extends FinalReference { /* Package-private; must be in
33 same package as the Reference
34 class */
35
36 /* A native method that invokes an arbitrary object's finalize method is
37 required since the finalize method is protected
38 */
39 static native void invokeFinalizeMethod(Object o) throws Throwable;
40
41 static private ReferenceQueue queue = new ReferenceQueue();
42 static private Finalizer unfinalized = null;
43 static private Object lock = new Object();
44
45 private Finalizer
46 next = null,
47 prev = null;
48
49 private boolean hasBeenFinalized() {
50 return (next == this);
51 }
52
53 private void add() {
54 synchronized (lock) {
55 if (unfinalized != null) {
56 this.next = unfinalized;
57 unfinalized.prev = this;
58 }
59 unfinalized = this;
60 }
61 }
62
63 private void remove() {
64 synchronized (lock) {
65 if (unfinalized == this) {
66 if (this.next != null) {
67 unfinalized = this.next;
68 } else {
69 unfinalized = this.prev;
70 }
71 }
72 if (this.next != null) {
73 this.next.prev = this.prev;
74 }
75 if (this.prev != null) {
76 this.prev.next = this.next;
77 }
78 this.next = this; /* Indicates that this has been finalized */
79 this.prev = this;
80 }
81 }
82
83 private Finalizer(Object finalizee) {
84 super(finalizee, queue);
85 add();
86 }
87
88 /* Invoked by VM */
89 static void register(Object finalizee) {
90 new Finalizer(finalizee);
91 }
92
93 private void runFinalizer() {
94 synchronized (this) {
95 if (hasBeenFinalized()) return;
96 remove();
97 }
98 try {
99 Object finalizee = this.get();
100 if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
101 invokeFinalizeMethod(finalizee);
102 /* Clear stack slot containing this variable, to decrease
103 the chances of false retention with a conservative GC */
104 finalizee = null;
105 }
106 } catch (Throwable x) { }
107 super.clear();
108 }
109
110 /* Create a privileged secondary finalizer thread in the system thread
111 group for the given Runnable, and wait for it to complete.
112
113 This method is used by both runFinalization and runFinalizersOnExit.
114 The former method invokes all pending finalizers, while the latter
115 invokes all uninvoked finalizers if on-exit finalization has been
116 enabled.
117
118 These two methods could have been implemented by offloading their work
119 to the regular finalizer thread and waiting for that thread to finish.
120 The advantage of creating a fresh thread, however, is that it insulates
121 invokers of these methods from a stalled or deadlocked finalizer thread.
122 */
123 private static void forkSecondaryFinalizer(final Runnable proc) {
124 AccessController.doPrivileged(
125 new PrivilegedAction<Void>() {
126 public Void run() {
127 ThreadGroup tg = Thread.currentThread().getThreadGroup();
128 for (ThreadGroup tgn = tg;
129 tgn != null;
130 tg = tgn, tgn = tg.getParent());
131 Thread sft = new Thread(tg, proc, "Secondary finalizer");
132 sft.start();
133 try {
134 sft.join();
135 } catch (InterruptedException x) {
136 /* Ignore */
137 }
138 return null;
139 }});
140 }
141
142 /* Called by Runtime.runFinalization() */
143 static void runFinalization() {
144 forkSecondaryFinalizer(new Runnable() {
145 public void run() {
146 for (;;) {
147 Finalizer f = (Finalizer)queue.poll();
148 if (f == null) break;
149 f.runFinalizer();
150 }
151 }
152 });
153 }
154
155 /* Invoked by java.lang.Shutdown */
156 static void runAllFinalizers() {
157 forkSecondaryFinalizer(new Runnable() {
158 public void run() {
159 for (;;) {
160 Finalizer f;
161 synchronized (lock) {
162 f = unfinalized;
163 if (f == null) break;
164 unfinalized = f.next;
165 }
166 f.runFinalizer();
167 }}});
168 }
169
170 private static class FinalizerThread extends Thread {
171 FinalizerThread(ThreadGroup g) {
172 super(g, "Finalizer");
173 }
174 public void run() {
175 for (;;) {
176 try {
177 Finalizer f = (Finalizer)queue.remove();
178 f.runFinalizer();
179 } catch (InterruptedException x) {
180 continue;
181 }
182 }
183 }
184 }
185
186 static {
187 ThreadGroup tg = Thread.currentThread().getThreadGroup();
188 for (ThreadGroup tgn = tg;
189 tgn != null;
190 tg = tgn, tgn = tg.getParent());
191 Thread finalizer = new FinalizerThread(tg);
192 finalizer.setPriority(Thread.MAX_PRIORITY - 2);
193 finalizer.setDaemon(true);
194 finalizer.start();
195 }
196
197 }