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 java.security.PrivilegedAction;
  29 import java.security.AccessController;
  30 import java.util.concurrent.ThreadLocalRandom;
  31 import sun.misc.ManagedLocalsThread;
  32 import sun.misc.SharedSecrets;
  33 import sun.misc.VM;
  34 
  35 /* Package-private; must be in same package as the Reference class */
  36 class Finalizer<T> extends FinalReference<T> implements Runnable {
  37     /**
  38      * Finalizers are registered in a doubly-linked list so that they are kept
  39      * alive until discovered by VM, processed by ReferenceHandling pool and then
  40      * unlinked. There are several lists to distribute Finalizers randomly into
  41      * to reduce contention among concurrent threads trying to link/unlink them.
  42      */
  43     static final FinalizerList[] unfinalized;
  44     static {
  45         int cpus = Runtime.getRuntime().availableProcessors();
  46         // smallest power of two equal or greater than 2 * # of CPUs
  47         int lists = (cpus <= 1) ? 2 : Integer.highestOneBit(cpus - 1) << 2;
  48         unfinalized = new FinalizerList[lists];
  49         for (int i = 0; i < lists; i++) {
  50             unfinalized[i] = new FinalizerList();
  51         }
  52     }
  53 
  54     volatile Finalizer prev;
  55     volatile Finalizer next;
  56     private final int listIndex;
  57 
  58     Finalizer(T finalizee, int listIndex) {
  59         super(finalizee, ReferenceQueue.NULL);
  60         this.listIndex = listIndex;
  61     }
  62 
  63     /** A constructor used for special Finalizer instances in FinalizerList */
  64     Finalizer() {
  65         super(null, ReferenceQueue.NULL);
  66         listIndex = -1; // never registered in any list
  67     }
  68 
  69     /** Invoked by VM for objects overriding finalize() method */
  70     static void register(Object finalizee) {
  71         int rnd = nextSecondarySeed();
  72         int index = (rnd >>> 1) & (unfinalized.length - 1);
  73         unfinalized[index].link(new Finalizer<>(finalizee, index), (rnd & 1) == 0);
  74     }
  75 
  76     @Override
  77     public void run() {
  78         T finalizee = delete();
  79         if (finalizee == null) {
  80             return;
  81         }
  82         unfinalized[listIndex].unlink(this);
  83         try {
  84             if (!(finalizee instanceof java.lang.Enum)) {
  85                 invokeFinalizee(finalizee);
  86 
  87                 /* Clear stack slot containing this variable, to decrease
  88                    the chances of false retention with a conservative GC */
  89                 finalizee = null;
  90             }
  91         } catch (Throwable x) { }
  92     }
  93 
  94     /* Invoke the finalize() method on the finalizee (overridden by Finalizator) */
  95     void invokeFinalizee(T finalizee) throws Throwable {
  96         SharedSecrets.getJavaLangAccess().invokeFinalize(finalizee);
  97         finalizee = null;
  98     }
  99 
 100     @Override
 101     public void clear() {
 102         T finalizee = delete();
 103         if (finalizee == null) {
 104             return;
 105         }
 106         unfinalized[listIndex].unlink(this);
 107         /* Clear stack slot containing this variable, to decrease
 108            the chances of false retention with a conservative GC */
 109         finalizee = null;
 110     }
 111 
 112     /* Create a privileged secondary finalizer thread in the system thread
 113            group for the given Runnable, and wait for it to complete.
 114 
 115            This method is used by both runFinalization and runFinalizersOnExit.
 116            The former method invokes all pending finalizers, while the latter
 117            invokes all uninvoked finalizers if on-exit finalization has been
 118            enabled.
 119 
 120            These two methods could have been implemented by offloading their work
 121            to the regular finalizer thread and waiting for that thread to finish.
 122            The advantage of creating a fresh thread, however, is that it insulates
 123            invokers of these methods from a stalled or deadlocked finalizer thread.
 124          */
 125     private static void forkSecondaryFinalizer(final Runnable proc) {
 126         AccessController.doPrivileged(
 127             new PrivilegedAction<>() {
 128                 public Void run() {
 129                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
 130                     for (ThreadGroup tgn = tg;
 131                          tgn != null;
 132                          tg = tgn, tgn = tg.getParent());
 133                     Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer");
 134                     sft.start();
 135                     try {
 136                         sft.join();
 137                     } catch (InterruptedException x) {
 138                         Thread.currentThread().interrupt();
 139                     }
 140                     return null;
 141                 }});
 142     }
 143 
 144     /* Called by Runtime.runFinalization() */
 145     static void runFinalization() {
 146         if (!VM.isBooted()) {
 147             return;
 148         }
 149 
 150         forkSecondaryFinalizer(new Runnable() {
 151             private volatile boolean running;
 152             public void run() {
 153                 // in case of recursive call to run()
 154                 if (running)
 155                     return;
 156                 running = true;
 157                 ReferenceHandling.runFinalization();
 158             }
 159         });
 160     }
 161 
 162     /* Invoked by java.lang.Shutdown */
 163     static void runAllFinalizers() {
 164         if (!VM.isBooted()) {
 165             return;
 166         }
 167 
 168         forkSecondaryFinalizer(new Runnable() {
 169             private volatile boolean running;
 170             public void run() {
 171                 // in case of recursive call to run()
 172                 if (running)
 173                     return;
 174                 running = true;
 175                 for (FinalizerList uflist : unfinalized)
 176                     for (Finalizer<?> f = uflist.first(); f != null; f = uflist.succ(f)) {
 177                         f.run();
 178                 }}});
 179     }
 180 
 181     // Unsafe mechanics
 182 
 183     /**
 184      * Returns the pseudo-randomly initialized or updated secondary seed.
 185      * Copied from ThreadLocalRandom due to package access restrictions.
 186      */
 187     static int nextSecondarySeed() {
 188         int r;
 189         Thread t = Thread.currentThread();
 190         if ((r = UNSAFE.getInt(t, threadLocalRandomSecondarySeedOffset)) != 0) {
 191             r ^= r << 13;   // xorshift
 192             r ^= r >>> 17;
 193             r ^= r << 5;
 194         }
 195         else if ((r = ThreadLocalRandom.current().nextInt()) == 0)
 196             r = 1; // avoid zero
 197         UNSAFE.putInt(t, threadLocalRandomSecondarySeedOffset, r);
 198         return r;
 199     }
 200 
 201     boolean isAlive() {
 202         return getReferentVolatile() != null;
 203     }
 204 
 205     boolean isDeleted() {
 206         return getReferentVolatile() == null;
 207     }
 208 
 209     private T delete() {
 210         T referent = getReferentVolatile();
 211         return (referent != null) && casReferent(referent, null)
 212             ? referent : null;
 213     }
 214 
 215     void lazySetNext(Finalizer<?> val) {
 216         UNSAFE.putOrderedObject(this, nextOffset, val);
 217     }
 218 
 219     boolean casNext(Finalizer<?> cmp, Finalizer<?> val) {
 220         return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
 221     }
 222 
 223     void lazySetPrev(Finalizer<?> val) {
 224         UNSAFE.putOrderedObject(this, prevOffset, val);
 225     }
 226 
 227     boolean casPrev(Finalizer<?> cmp, Finalizer<?> val) {
 228         return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);
 229     }
 230 
 231     private static final sun.misc.Unsafe UNSAFE;
 232     private static final long prevOffset;
 233     private static final long nextOffset;
 234     private static final long threadLocalRandomSecondarySeedOffset;
 235 
 236     static {
 237         try {
 238             UNSAFE = sun.misc.Unsafe.getUnsafe();
 239             Class<Finalizer> fc = Finalizer.class;
 240             prevOffset = UNSAFE.objectFieldOffset(fc.getDeclaredField("prev"));
 241             nextOffset = UNSAFE.objectFieldOffset(fc.getDeclaredField("next"));
 242             Class<Thread> tc = Thread.class;
 243             threadLocalRandomSecondarySeedOffset = UNSAFE.objectFieldOffset
 244                 (tc.getDeclaredField("threadLocalRandomSecondarySeed"));
 245         } catch (Exception e) {
 246             throw new Error(e);
 247         }
 248     }
 249 }