001 /*
002 * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.lang.ref;
027
028 import java.security.PrivilegedAction;
029 import java.security.AccessController;
030
031 final class Finalizer extends FinalReference { /* Package-private; must be in
032 same package as the Reference
033 class */
034
035 /* A native method that invokes an arbitrary object's finalize method is
036 required since the finalize method is protected
037 */
038 static native void invokeFinalizeMethod(Object o) throws Throwable;
039
040 static private ReferenceQueue queue = new ReferenceQueue();
041 static private Finalizer unfinalized = null;
042 static private Object lock = new Object();
043
044 private Finalizer next = null, prev = null;
045
046 private boolean hasBeenFinalized() {
047 return (next == this );
048 }
049
050 private void add() {
051 synchronized (lock) {
052 if (unfinalized != null) {
053 this .next = unfinalized;
054 unfinalized.prev = this ;
055 }
056 unfinalized = this ;
057 }
058 }
059
060 private void remove() {
061 synchronized (lock) {
062 if (unfinalized == this ) {
063 if (this .next != null) {
064 unfinalized = this .next;
065 } else {
066 unfinalized = this .prev;
067 }
068 }
069 if (this .next != null) {
070 this .next.prev = this .prev;
071 }
072 if (this .prev != null) {
073 this .prev.next = this .next;
074 }
075 this .next = this ; /* Indicates that this has been finalized */
076 this .prev = this ;
077 }
078 }
079
080 private Finalizer(Object finalizee) {
081 super (finalizee, queue);
082 add();
083 }
084
085 /* Invoked by VM */
086 static void register(Object finalizee) {
087 new Finalizer(finalizee);
088 }
089
090 private void runFinalizer() {
091 synchronized (this ) {
092 if (hasBeenFinalized())
093 return;
094 remove();
095 }
096 try {
097 Object finalizee = this .get();
098 if (finalizee != null
099 && !(finalizee instanceof java.lang.Enum)) {
100 invokeFinalizeMethod(finalizee);
101 /* Clear stack slot containing this variable, to decrease
102 the chances of false retention with a conservative GC */
103 finalizee = null;
104 }
105 } catch (Throwable x) {
106 }
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 PrivilegedAction pa = new PrivilegedAction() {
125 public Object run() {
126 ThreadGroup tg = Thread.currentThread()
127 .getThreadGroup();
128 for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg
129 .getParent())
130 ;
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 AccessController.doPrivileged(pa);
142 }
143
144 /* Called by Runtime.runFinalization() */
145 static void runFinalization() {
146 forkSecondaryFinalizer(new Runnable() {
147 public void run() {
148 for (;;) {
149 Finalizer f = (Finalizer) queue.poll();
150 if (f == null)
151 break;
152 f.runFinalizer();
153 }
154 }
155 });
156 }
157
158 /* Invoked by java.lang.Shutdown */
159 static void runAllFinalizers() {
160 forkSecondaryFinalizer(new Runnable() {
161 public void run() {
162 for (;;) {
163 Finalizer f;
164 synchronized (lock) {
165 f = unfinalized;
166 if (f == null)
167 break;
168 unfinalized = f.next;
169 }
170 f.runFinalizer();
171 }
172 }
173 });
174 }
175
176 private static class FinalizerThread extends Thread {
177 FinalizerThread(ThreadGroup g) {
178 super (g, "Finalizer");
179 }
180
181 public void run() {
182 for (;;) {
183 try {
184 Finalizer f = (Finalizer) queue.remove();
185 f.runFinalizer();
186 } catch (InterruptedException x) {
187 continue;
188 }
189 }
190 }
191 }
192
193 static {
194 ThreadGroup tg = Thread.currentThread().getThreadGroup();
195 for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg
196 .getParent())
197 ;
198 Thread finalizer = new FinalizerThread(tg);
199 finalizer.setPriority(Thread.MAX_PRIORITY - 2);
200 finalizer.setDaemon(true);
201 finalizer.start();
202 }
203
204 }
|