1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 
  28 import java.security.PrivilegedAction;
  29 import java.security.AccessController;
  30 import jdk.internal.misc.JavaLangAccess;
  31 import jdk.internal.misc.SharedSecrets;
  32 import jdk.internal.misc.VM;
  33 
  34 final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
  35                                                           same package as the Reference
  36                                                           class */
  37 
  38     private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
  39 
  40     /** Head of doubly linked list of Finalizers awaiting finalization. */
  41     private static Finalizer unfinalized = null;
  42 
  43     /** Lock guarding access to unfinalized list. */
  44     private static final Object lock = new Object();
  45 
  46     private Finalizer next, prev;
  47 
  48     private Finalizer(Object finalizee) {
  49         super(finalizee, queue);
  50         // push onto unfinalized
  51         synchronized (lock) {
  52             if (unfinalized != null) {
  53                 this.next = unfinalized;
  54                 unfinalized.prev = this;
  55             }
  56             unfinalized = this;
  57         }
  58     }
  59 
  60     static ReferenceQueue<Object> getQueue() {
  61         return queue;
  62     }
  63 
  64     /* Invoked by VM */
  65     static void register(Object finalizee) {
  66         new Finalizer(finalizee);
  67     }
  68 
  69     private void runFinalizer(JavaLangAccess jla) {
  70         synchronized (lock) {
  71             if (this.next == this)      // already finalized
  72                 return;
  73             // unlink from unfinalized
  74             if (unfinalized == this)
  75                 unfinalized = this.next;
  76             else
  77                 this.prev.next = this.next;
  78             if (this.next != null)
  79                 this.next.prev = this.prev;
  80             this.prev = null;
  81             this.next = this;           // mark as finalized
  82         }
  83 
  84         try {
  85             Object finalizee = this.get();
  86             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
  87                 jla.invokeFinalize(finalizee);
  88 
  89                 // Clear stack slot containing this variable, to decrease
  90                 // the chances of false retention with a conservative GC
  91                 finalizee = null;
  92             }
  93         } catch (Throwable x) { }
  94         super.clear();
  95     }
  96 
  97     /* Create a privileged secondary finalizer thread in the system thread
  98      * group for the given Runnable, and wait for it to complete.
  99      *
 100      * This method is used by runFinalization.
 101      *
 102      * It could have been implemented by offloading the work to the
 103      * regular finalizer thread and waiting for that thread to finish.
 104      * The advantage of creating a fresh thread, however, is that it insulates
 105      * invokers of that method from a stalled or deadlocked finalizer thread.
 106      */
 107     private static void forkSecondaryFinalizer(final Runnable proc) {
 108         AccessController.doPrivileged(
 109             new PrivilegedAction<>() {
 110                 public Void run() {
 111                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
 112                     for (ThreadGroup tgn = tg;
 113                          tgn != null;
 114                          tg = tgn, tgn = tg.getParent());
 115                     Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
 116                     sft.start();
 117                     try {
 118                         sft.join();
 119                     } catch (InterruptedException x) {
 120                         Thread.currentThread().interrupt();
 121                     }
 122                     return null;
 123                 }});
 124     }
 125 
 126     /* Called by Runtime.runFinalization() */
 127     static void runFinalization() {
 128         if (VM.initLevel() == 0) {
 129             return;
 130         }
 131 
 132         forkSecondaryFinalizer(new Runnable() {
 133             private volatile boolean running;
 134             public void run() {
 135                 // in case of recursive call to run()
 136                 if (running)
 137                     return;
 138                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 139                 running = true;
 140                 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
 141                     f.runFinalizer(jla);
 142             }
 143         });
 144     }
 145 
 146     private static class FinalizerThread extends Thread {
 147         private volatile boolean running;
 148         FinalizerThread(ThreadGroup g) {
 149             super(g, null, "Finalizer", 0, false);
 150         }
 151         public void run() {
 152             // in case of recursive call to run()
 153             if (running)
 154                 return;
 155 
 156             // Finalizer thread starts before System.initializeSystemClass
 157             // is called.  Wait until JavaLangAccess is available
 158             while (VM.initLevel() == 0) {
 159                 // delay until VM completes initialization
 160                 try {
 161                     VM.awaitInitLevel(1);
 162                 } catch (InterruptedException x) {
 163                     // ignore and continue
 164                 }
 165             }
 166             final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 167             running = true;
 168             for (;;) {
 169                 try {
 170                     Finalizer f = (Finalizer)queue.remove();
 171                     f.runFinalizer(jla);
 172                 } catch (InterruptedException x) {
 173                     // ignore and continue
 174                 }
 175             }
 176         }
 177     }
 178 
 179     static {
 180         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 181         for (ThreadGroup tgn = tg;
 182              tgn != null;
 183              tg = tgn, tgn = tg.getParent());
 184         Thread finalizer = new FinalizerThread(tg);
 185         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 186         finalizer.setDaemon(true);
 187         finalizer.start();
 188     }
 189 
 190 }