1 /*
   2  * Copyright (c) 1997, 2013, 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 sun.misc.ManagedLocalsThread;
  29 import sun.misc.SharedSecrets;
  30 import sun.misc.VM;
  31 
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;
  34 
  35 /* Package-private; must be in same package as the Reference class */
  36 class Finalizer<T> extends FinalReference<T> implements Cleaner {
  37 
  38     Finalizer(T finalizee) {
  39         super(finalizee, null);
  40     }
  41 
  42     /** Invoked by VM for objects overriding finalize() method */
  43     static void register(Object finalizee) {
  44         Finalizer<?> finalizer = new Finalizer<>(finalizee);
  45         finalizer.link();
  46     }
  47 
  48     @Override
  49     public void clean() {
  50         T finalizee = delete();
  51         if (finalizee == null) {
  52             return;
  53         }
  54         unlink();
  55         try {
  56             if (!(finalizee instanceof java.lang.Enum)) {
  57                 invokeFinalizee(finalizee);
  58             }
  59         } catch (Throwable x) { }
  60         finalizee = null;
  61     }
  62 
  63     /* Invoke the finalize() method on the finalizee (overridden by Finalizator) */
  64     void invokeFinalizee(T finalizee) throws Throwable {
  65         SharedSecrets.getJavaLangAccess().invokeFinalize(finalizee);
  66         finalizee = null;
  67     }
  68 
  69     @Override
  70     public void clear() {
  71         T finalizee = delete();
  72         if (finalizee == null) {
  73             return;
  74         }
  75         unlink();
  76         /* Clear stack slot containing this variable, to decrease
  77            the chances of false retention with a conservative GC */
  78         finalizee = null;
  79     }
  80 
  81     /* Create a privileged secondary finalizer thread in the system thread
  82        group for the given Runnable, and wait for it to complete.
  83 
  84        This method is used by both runFinalization and runFinalizersOnExit.
  85        The former method invokes all pending finalizers, while the latter
  86        invokes all uninvoked finalizers if on-exit finalization has been
  87        enabled.
  88 
  89        These two methods could have been implemented by offloading their work
  90        to the regular finalizer thread and waiting for that thread to finish.
  91        The advantage of creating a fresh thread, however, is that it insulates
  92        invokers of these methods from a stalled or deadlocked finalizer thread.
  93      */
  94     private static void forkSecondaryFinalizer(final Runnable proc) {
  95         AccessController.doPrivileged(
  96             new PrivilegedAction<>() {
  97                 public Void run() {
  98                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
  99                     for (ThreadGroup tgn = tg;
 100                          tgn != null;
 101                          tg = tgn, tgn = tg.getParent());
 102                     Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer");
 103                     sft.start();
 104                     try {
 105                         sft.join();
 106                     } catch (InterruptedException x) {
 107                         Thread.currentThread().interrupt();
 108                     }
 109                     return null;
 110                 }});
 111     }
 112 
 113     /* Called by Runtime.runFinalization() */
 114     static void runFinalization() {
 115         if (!VM.isBooted()) {
 116             return;
 117         }
 118 
 119         forkSecondaryFinalizer(new Runnable() {
 120             private volatile boolean running;
 121             public void run() {
 122                 // in case of recursive call to run()
 123                 if (running)
 124                     return;
 125                 running = true;
 126                 ReferenceHandling.runFinalization();
 127             }
 128         });
 129     }
 130 
 131     /* Invoked by java.lang.Shutdown */
 132     static void runAllFinalizers() {
 133         if (!VM.isBooted()) {
 134             return;
 135         }
 136 
 137         forkSecondaryFinalizer(new Runnable() {
 138             private volatile boolean running;
 139             public void run() {
 140                 // in case of recursive call to run()
 141                 if (running)
 142                     return;
 143                 running = true;
 144                 for (DLList ucList : uncleanedLists)
 145                     for (Reference<?> f = ucList.first(); f != null; f = ucList.succ(f)) {
 146                         ((Cleaner)f).clean();
 147                 }}});
 148     }
 149 
 150     /**
 151      * Atomically clear the Finalizer and return the finalizee.
 152      *
 153      * @return the finalizee or null
 154      */
 155     private T delete() {
 156         T referent = getReferentVolatile();
 157         return (referent != null) && casReferent(referent, null)
 158                ? referent : null;
 159     }
 160 
 161     // Methods and state that enable Finalizer to be an element of DLList
 162 
 163     /** A constructor used for special Reference instances used in DLList */
 164     Finalizer(boolean setPrevToSelf, boolean setNextToSelf) {
 165         super(null, null);
 166         if (setPrevToSelf) prevDll = this;
 167         if (setNextToSelf) nextDll = this;
 168     }
 169 
 170     @SuppressWarnings("unused") // assigned through Unsafe
 171     private volatile Reference<?> prevDll, nextDll;
 172 
 173     boolean isDeletedDll() {
 174         return getReferentVolatile() == null;
 175     }
 176 
 177     Reference<?> getPrevDll() {
 178         return prevDll;
 179     }
 180 
 181     void lazySetPrevDll(Reference<?> val) {
 182         UNSAFE.putOrderedObject(this, PREV_DLL, val);
 183     }
 184 
 185     boolean casPrevDll(Reference<?> cmp, Reference<?> val) {
 186         return UNSAFE.compareAndSwapObject(this, PREV_DLL, cmp, val);
 187     }
 188 
 189     Reference<?> getNextDll() {
 190         return nextDll;
 191     }
 192 
 193     void lazySetNextDll(Reference<?> val) {
 194         UNSAFE.putOrderedObject(this, NEXT_DLL, val);
 195     }
 196 
 197     boolean casNextDll(Reference<?> cmp, Reference<?> val) {
 198         return UNSAFE.compareAndSwapObject(this, NEXT_DLL, cmp, val);
 199     }
 200 
 201     // Unsafe machinery
 202 
 203     private static final sun.misc.Unsafe UNSAFE;
 204     private static final long PREV_DLL;
 205     private static final long NEXT_DLL;
 206 
 207     static {
 208         try {
 209             UNSAFE = sun.misc.Unsafe.getUnsafe();
 210             Class<Finalizer> fc = Finalizer.class;
 211             PREV_DLL = UNSAFE.objectFieldOffset(fc.getDeclaredField("prevDll"));
 212             NEXT_DLL = UNSAFE.objectFieldOffset(fc.getDeclaredField("nextDll"));
 213         } catch (Exception e) {
 214             throw new Error(e);
 215         }
 216     }
 217 }