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     */
013    package org.jikesrvm.scheduler;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.mm.mminterface.MemoryManager;
017    import org.jikesrvm.runtime.Magic;
018    import org.vmmagic.pragma.Uninterruptible;
019    import 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
035    public 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    }