001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.scheduler;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.mm.mminterface.MemoryManager;
017import org.jikesrvm.runtime.Magic;
018import org.vmmagic.pragma.Uninterruptible;
019import org.vmmagic.pragma.NonMoving;
020
021/**
022 * Finalizer thread.
023 * <p>
024 * This thread is created by RVMThread.boot() at runtime startup.
025 * Its "run" method does the following:
026 * <ul>
027 *   <li>1. yield to the gcwaitqueue, until scheduled by GC.
028 *   <li> 2. For all objects on finalize queue, run the finalize() method
029 *   <li> 3. Go to 1
030 * </ul>
031 * <p>
032 * This thread comes out of wait state via notify from the garbage collector
033 */
034@NonMoving
035public class FinalizerThread extends SystemThread {
036
037  private static final int verbose = 0; // currently goes up to 2
038
039  private final Object[] none = new Object[0];
040  private static boolean shouldRun;
041  private static Monitor schedLock;
042
043  public static void boot() {
044    schedLock = new Monitor();
045    FinalizerThread ft = new FinalizerThread();
046    ft.start();
047  }
048
049  @Uninterruptible
050  public static void schedule() {
051    schedLock.lockNoHandshake();
052    shouldRun = true;
053    schedLock.broadcast();
054    schedLock.unlock();
055  }
056
057  public FinalizerThread() {
058    super("FinalizerThread");
059  }
060
061  /** Run the finalizer thread (one per RVM) */
062  @Override
063  public void run() {
064    if (verbose >= 1) {
065      RVMThread.trace("FinalizerThread ", "run routine entered");
066    }
067
068    try {
069      while (true) {
070
071        // suspend this thread: it will resume when the garbage collector
072        // places objects on the finalizer queue and notifies.
073        schedLock.lockNoHandshake();
074        if (!shouldRun) {
075          if (verbose >= 1) {
076            VM.sysWriteln("finalizer thread sleeping.");
077          }
078          schedLock.waitWithHandshake();
079        }
080        shouldRun = false;
081        schedLock.unlock();
082
083        if (verbose >= 1) {
084          VM.sysWriteln("FinalizerThread starting finalization");
085        }
086
087        while (true) {
088          Object o = MemoryManager.getFinalizedObject();
089          if (o == null) break;
090          if (verbose >= 2) {
091            VM.sysWrite("FinalizerThread finalizing object at ", Magic.objectAsAddress(o));
092            VM.sysWrite(" of type ");
093            VM.sysWrite(Magic.getObjectType(o).getDescriptor());
094            VM.sysWriteln();
095          }
096          try {
097            java.lang.JikesRVMSupport.invokeFinalize(o);
098          } catch (Throwable e) {
099            if (verbose >= 1) VM.sysWriteln("Throwable exception caught for finalize call");
100          }
101          if (verbose >= 2) {
102            VM.sysWriteln("FinalizerThread done with object at ", Magic.objectAsAddress(o));
103          }
104        }
105        if (verbose >= 1) VM.sysWriteln("FinalizerThread finished finalization");
106
107      }          // while (true)
108    } catch (Throwable e) {
109      VM.sysWriteln("Unexpected exception thrown in finalizer thread: ", e.toString());
110      e.printStackTrace();
111    }
112
113  }  // run
114
115}