001: /*
002: * @(#)Finalizer.java 1.32 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.lang.ref;
029:
030: import java.security.PrivilegedAction;
031: import java.security.AccessController;
032: import sun.misc.ThreadRegistry;
033: import sun.misc.CVM;
034:
035: final class Finalizer extends FinalReference { /* Package-private; must be in
036: same package as the Reference
037: class */
038:
039: /* A native method that invokes an arbitrary object's finalize method is
040: required since the finalize method is protected
041: */
042: static native void invokeFinalizeMethod(Object o) throws Throwable;
043:
044: static private ReferenceQueue queue = new ReferenceQueue();
045: static private Finalizer unfinalized = null;
046: static private Object lock = new Object();
047:
048: private Finalizer next = null, prev = null;
049:
050: private boolean hasBeenFinalized() {
051: return (next == this );
052: }
053:
054: private void add() {
055: synchronized (lock) {
056: if (unfinalized != null) {
057: this .next = unfinalized;
058: unfinalized.prev = this ;
059: }
060: unfinalized = this ;
061: }
062: }
063:
064: private void remove() {
065: synchronized (lock) {
066: if (unfinalized == this ) {
067: if (this .next != null) {
068: unfinalized = this .next;
069: } else {
070: unfinalized = this .prev;
071: }
072: }
073: if (this .next != null) {
074: this .next.prev = this .prev;
075: }
076: if (this .prev != null) {
077: this .prev.next = this .next;
078: }
079: this .next = this ; /* Indicates that this has been finalized */
080: this .prev = this ;
081: }
082: }
083:
084: private Finalizer(Object finalizee) {
085: super (finalizee, queue);
086: add();
087: }
088:
089: /* Invoked by VM */
090: static void register(Object finalizee) {
091: new Finalizer(finalizee);
092: }
093:
094: /* This function is called with remote exception disabled */
095: private void runFinalizer() {
096: synchronized (this ) {
097: if (hasBeenFinalized()) {
098: CVM.enableRemoteExceptions(); // lvm
099: return;
100: }
101: remove();
102: }
103: try {
104: Object finalizee = this .get();
105: if (finalizee != null) {
106: invokeFinalizeMethod(finalizee);
107: /* Clear stack slot containing this variable, to decrease
108: the chances of false retention with a conservative GC */
109: finalizee = null;
110: } else {
111: CVM.enableRemoteExceptions(); // lvm
112: }
113: } catch (ThreadDeath td) {
114: throw td;
115: } catch (Throwable x) {
116: }
117: super .clear();
118: }
119:
120: /* Create a privileged secondary finalizer thread in the system thread
121: group for the given Runnable, and wait for it to complete.
122:
123: This method is used by both runFinalization and runFinalizersOnExit.
124: The former method invokes all pending finalizers, while the latter
125: invokes all uninvoked finalizers if on-exit finalization has been
126: enabled.
127:
128: These two methods could have been implemented by offloading their work
129: to the regular finalizer thread and waiting for that thread to finish.
130: The advantage of creating a fresh thread, however, is that it insulates
131: invokers of these methods from a stalled or deadlocked finalizer thread.
132: */
133: private static void forkSecondaryFinalizer(final Runnable proc) {
134: PrivilegedAction pa = new PrivilegedAction() {
135: public Object run() {
136: ThreadGroup tg = Thread.currentThread()
137: .getThreadGroup();
138: for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg
139: .getParent())
140: ;
141: Thread sft = new Thread(tg, proc, "Secondary finalizer");
142: sft.start();
143: try {
144: sft.join();
145: } catch (InterruptedException x) {
146: /* Ignore */
147: }
148: return null;
149: }
150: };
151: AccessController.doPrivileged(pa);
152: }
153:
154: /* Called by Runtime.runFinalization() */
155: static void runFinalization() {
156: forkSecondaryFinalizer(new Runnable() {
157: public void run() {
158: for (;;) {
159: Finalizer f = (Finalizer) queue.poll();
160: if (f == null)
161: break;
162: CVM.disableRemoteExceptions(); // lvm
163: f.runFinalizer();
164: }
165: }
166: });
167: }
168:
169: /* Invoked by java.lang.Shutdown */
170: static void runAllFinalizers() {
171: forkSecondaryFinalizer(new Runnable() {
172: public void run() {
173: for (;;) {
174: Finalizer f;
175: CVM.disableRemoteExceptions(); // lvm
176: synchronized (lock) {
177: f = unfinalized;
178: if (f == null)
179: break;
180: unfinalized = f.next;
181: }
182: f.runFinalizer();
183: }
184: }
185: });
186: }
187:
188: // %begin lvm
189: /* Invoked by sun.misc.LogicalVMImpl when we shutdown a Logical VM.
190: * Run all the finalizers of system class without forking a new
191: * finalizer thread since new thread creation is disenabled during
192: * LVM termination. We know the thread that executes this code, and
193: * have full control over it. */
194: static void runAllFinalizersOfSystemClass() {
195: for (;;) {
196: Finalizer f;
197: CVM.disableRemoteExceptions(); // lvm
198: synchronized (lock) {
199: f = unfinalized;
200: if (f == null)
201: break;
202: unfinalized = f.next;
203: }
204: Object finalizee = f.get();
205: if (finalizee.getClass().getClassLoader() == null) {
206: f.runFinalizer();
207: } else {
208: CVM.enableRemoteExceptions(); // lvm
209: }
210: }
211: }
212:
213: // %end lvm
214:
215: private static class FinalizerThread extends Thread {
216: FinalizerThread(ThreadGroup g) {
217: super (g, "Finalizer");
218: }
219:
220: public void run() {
221: while (!ThreadRegistry.exitRequested()) {
222: try {
223: CVM.disableRemoteExceptions(); // lvm
224: Finalizer f = (Finalizer) queue.remove();
225: f.runFinalizer();
226: } catch (InterruptedException x) {
227: continue;
228: }
229: }
230: }
231: }
232:
233: //
234: // Package private, so that the finalizer thread can be re-startable.
235: //
236: static void startFinalizerThread() {
237: ThreadGroup tg = Thread.currentThread().getThreadGroup();
238: for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg
239: .getParent())
240: ;
241: Thread finalizer = new FinalizerThread(tg);
242: finalizer.setPriority(Thread.MAX_PRIORITY - 2);
243: finalizer.setDaemon(true);
244: finalizer.start();
245: }
246:
247: static {
248: startFinalizerThread();
249: }
250:
251: }
|