001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /*
018: * @author Salikh Zakirov, Pavel Afremov
019: * @version $Revision: 1.1.2.2.4.3 $
020: */
021: package java.lang;
022:
023: /**
024: * Dedicated finalizer thread.
025: */
026: class FinalizerThread extends Thread {
027:
028: /**
029: * Wake up permanent finalizer threads or create additional
030: * temporary threads, and wait until they start.
031: * @param wait - says to wait untill all finalizer threads complite work.
032: */
033: public static void startFinalization(boolean wait) {
034: if (!enabled) {
035: return;
036: }
037:
038: //wakeup finalazer threads
039: wakeupFinalization();
040:
041: // work balance system creates balancing threads
042: spawnBalanceThreads();
043:
044: // if flag is raised up waits finalization complete
045: if (wait) {
046: waitFinalizationEnd();
047: }
048: }
049:
050: /**
051: * VM calls this thread from Runtime.runFinalization().
052: */
053: public static void runFinalization() {
054: /* BEGIN: added for NATIVE FINALIZER THREAD */
055: if (NATIVE_FINALIZER_THREAD)
056: runFinalizationInNativeFinalizerThreads();
057: else
058: /* END: added for NATIVE FINALIZER THREAD */
059: startFinalization(true);
060: }
061:
062: /*
063: * Staic package private part
064: */
065:
066: /**
067: * Initializes finalization system. Starts permanent thread.
068: */
069: static void initialize() {
070: /* BEGIN: added for NATIVE FINALIZER THREAD */
071: if (NATIVE_FINALIZER_THREAD)
072: return;
073: /* END: added for NATIVE FINALIZER THREAD */
074:
075: if (TRACE) {
076: trace("FinalizerThread: static initialization started");
077: }
078:
079: processorsQuantity = getProcessorsQuantity();
080:
081: // -XDvm.finalize=0 disables the finalizer thread
082: if (!isNativePartEnabled()) {
083: warn("finalizer thread have not been created");
084: } else {
085: (new FinalizerThread(true)).start();
086: enabled = true;
087: }
088:
089: if (TRACE) {
090: trace("FinalizerThread: static initialization complete");
091: }
092: }
093:
094: /**
095: * VM calls this method to request finalizer thread shutdown.
096: */
097: static void shutdown(boolean startFinalizationOnExit) {
098: /* BEGIN: added for NATIVE FINALIZER THREAD */
099: if (NATIVE_FINALIZER_THREAD) {
100: finalizerShutDown(startFinalizationOnExit);
101: return;
102: }
103: /* END: added for NATIVE FINALIZER THREAD */
104: if (TRACE) {
105: trace("shutting down finalizer thread");
106: }
107:
108: if (startFinalizationOnExit) {
109: doFinalizationOnExit();
110: }
111:
112: synchronized (workLock) {
113: shutdown = true;
114: workLock.notifyAll();
115: }
116: }
117:
118: /* added for NATIVE FINALIZER THREAD
119: * A flag to indicate whether the finalizer threads are native threads or Java threads.
120: */
121: private static final boolean NATIVE_FINALIZER_THREAD = getNativeFinalizerThreadFlagFromVM();
122:
123: /* BEGIN: These three methods are added for NATIVE FINALIZER THREAD */
124: /**
125: * This method gets the flag that indicates
126: * whether VM uses native finalizer threads or Java finalizer threads.
127: */
128: private static native boolean getNativeFinalizerThreadFlagFromVM();
129:
130: /**
131: * This method implements runFinalization() method in native finalizer threads.
132: */
133: private static native void runFinalizationInNativeFinalizerThreads();
134:
135: /**
136: * This method does finalization work related to VM shutdown in native finalizer threads.
137: */
138: private static native void finalizerShutDown(boolean finalizeOnExit);
139:
140: /* END: These three methods are added for NATIVE FINALIZER THREAD */
141:
142: /*
143: * Staic private part
144: */
145:
146: // Maximum quantity of finalizers threads
147: private static final int MAX_THREADS = 256;
148:
149: // create separate class for finalizer workLock to easier debugging
150: private static class FinalizerWorkLock {
151: };
152:
153: // Lock used to wake up permanent finalizer threads and synchronize change of state of work
154: private static Object workLock = new FinalizerWorkLock();
155:
156: // Shows that finalizers works in state on exit
157: // Used by VM. It should be package private to eliminate compiler warning.
158: static boolean onExit = false;
159:
160: // create separate class for finalizer waitFinishLock to easier debugging
161: private static class FinalizerWaitFinishLock {
162: };
163:
164: /*
165: * Lock used to to synchronize quantity of active threads and to wake up finalizer starter thread
166: * when new finalization tasks aren't available and finalizer threads finish work.
167: */
168: private static Object waitFinishLock = new FinalizerWaitFinishLock();
169:
170: /*
171: * The Quantity of active finalizer threads which shoud be stopped to wake up finalizer starter
172: * thread. When is thread is started this counter is incremented when thread is stoppig it's decremeted.
173: * Zero means finalization tasks aren't available and finalizer threads aren't working.
174: */
175: private static int waitFinishCounter = 0;
176:
177: // Indicates processors quantity in the system
178: private static int processorsQuantity;
179:
180: // true means finalizer threads is enabled
181: private static boolean enabled = false;
182:
183: // true means finalizer threads need to shut down
184: private static boolean shutdown = false;
185:
186: /**
187: * Gets quantity of processors in the System
188: */
189: private static native int getFinalizersQuantity();
190:
191: /**
192: * Gets quantity of processors in the System
193: */
194: private static native int getProcessorsQuantity();
195:
196: /**
197: * Do finalizations in native mode for specified quantity of finalizable object
198: */
199: private static native int doFinalization(int quantity);
200:
201: private static native void fillFinalizationQueueOnExit();
202:
203: /**
204: * Returns true if native part of finalization system is
205: * turned on, and false otherwise.
206: */
207: private static native boolean isNativePartEnabled();
208:
209: /**
210: * Returns true if current thread is finalizer thread
211: */
212: private static boolean isFinalizerThread() {
213: return ((Thread.currentThread()) instanceof FinalizerThread);
214: }
215:
216: /**
217: * Wakes up permanent finalizer threads
218: */
219: private static void wakeupFinalization() {
220: synchronized (workLock) {
221: workLock.notifyAll();
222: }
223: }
224:
225: /**
226: * Waits when finalization work is completed and then returns.
227: */
228: private static void waitFinalizationEnd() {
229: if (isFinalizerThread()) {
230: return;
231: }
232:
233: synchronized (waitFinishLock) {
234: if (waitFinishCounter > 0) {
235: try {
236: waitFinishLock.wait();
237: } catch (InterruptedException e) {
238: }
239: }
240: }
241: }
242:
243: /**
244: * Starts additional temporary threads to make sure
245: * finalization system keeps number of unfinalized objects
246: * at acceptable level.
247: * Waits until created thraed starts and then return.
248: * It is called from startFinalization() only.
249: */
250: private static void spawnBalanceThreads() {
251: /* finalizer threads shouldn't be spawn by finalizer thread,
252: * in this case balancing can't work
253: */
254: if (isFinalizerThread()) {
255: return;
256: }
257:
258: FinalizerThread newThread = null;
259: if (waitFinishCounter >= MAX_THREADS) {
260: Thread.yield();
261: } else {
262: try {
263: for (int i = 0; i < processorsQuantity; i++) {
264: newThread = new FinalizerThread(false);
265:
266: synchronized (newThread.startLock) {
267: newThread.start();
268:
269: // waiting when new thread will be started
270: try {
271: newThread.startLock.wait();
272: } catch (InterruptedException e) {
273: }
274: }
275: }
276: } catch (OutOfMemoryError e) {
277: }
278: }
279: }
280:
281: private static void doFinalizationOnExit() {
282: System.gc();
283: startFinalization(true);
284:
285: fillFinalizationQueueOnExit();
286:
287: synchronized (workLock) {
288: onExit = true;
289: }
290: startFinalization(true);
291: }
292:
293: /**
294: * Waits when new finalization task are available and finalizer threads can continue work
295: */
296: private static void waitNewTask() {
297: if (getFinalizersQuantity() != 0) {
298: return;
299: }
300:
301: synchronized (workLock) {
302: synchronized (waitFinishLock) {
303: waitFinishCounter--;
304:
305: if (waitFinishCounter == 0) {
306: waitFinishLock.notifyAll();
307: }
308: }
309:
310: while ((getFinalizersQuantity() == 0) && (!shutdown)) {
311: try {
312: workLock.wait();
313: } catch (InterruptedException e) {
314: }
315: }
316:
317: synchronized (waitFinishLock) {
318: waitFinishCounter++;
319: }
320: }
321: }
322:
323: private static final boolean TRACE = false;
324:
325: /**
326: * debug output.
327: */
328: private static void trace(Object o) {
329: /*
330: System.err.println(o);
331: System.err.flush();
332: */
333: }
334:
335: /**
336: * Prints warning.
337: */
338: private static void warn(Object o) {
339: System.err.println("FinalizerThread: " + o);
340: System.err.flush();
341: }
342:
343: public FinalizerThread() {
344: this (true);
345: }
346:
347: // create separate class for finalizer startLock to easier debugging
348: private class FinalizerStartLock {
349: };
350:
351: private FinalizerStartLock startLock = new FinalizerStartLock();
352:
353: protected FinalizerThread(boolean permanent) {
354: super (Thread.systemThreadGroup, "FinalizerThread");
355: this .permanent = permanent;
356: this .setDaemon(true);
357: }
358:
359: public void run() {
360: // don't put any code here, before try block
361:
362: try {
363: synchronized (waitFinishLock) {
364: waitFinishCounter++;
365: }
366:
367: /* notify that finalizer thread has started.
368: * Don't put any code whith any memory allocation before here!
369: * It should be granted that notify is called in any case!
370: */
371: synchronized (startLock) {
372: startLock.notify();
373: }
374:
375: if (TRACE) {
376: if (permanent) {
377: trace("permanent finalization thread started");
378: } else {
379: trace("temporary finalization thread started");
380: }
381: }
382:
383: while (true) {
384: int n = doFinalization(128);
385:
386: synchronized (workLock) {
387: if (shutdown) {
388:
389: if (TRACE) {
390: trace("terminated by shutdown request");
391: }
392: break;
393: }
394: }
395:
396: if (0 == n) {
397: if (permanent) {
398: waitNewTask();
399: } else {
400: break;
401: }
402: }
403: }
404: } catch (Throwable th) {
405: warn("FinalizerThread terminated by " + th);
406: throw new RuntimeException("FinalizerThread interrupted",
407: th);
408: } finally {
409: synchronized (waitFinishLock) {
410: waitFinishCounter--;
411:
412: if (waitFinishCounter == 0) {
413: waitFinishLock.notifyAll();
414: }
415: }
416:
417: if (TRACE) {
418: trace("FinalizerThread completed");
419: }
420: }
421: }
422:
423: /**
424: * Indicates that thread shouldn't be destroyed when finalization is complete
425: */
426: private boolean permanent;
427: }
|