Home | History | Annotate | Download | only in ref
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package java.lang.ref;
     18 
     19 /**
     20  * @hide
     21  */
     22 public final class FinalizerReference<T> extends Reference<T> {
     23     // This queue contains those objects eligible for finalization.
     24     public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
     25 
     26     // Guards the list (not the queue).
     27     private static final Object LIST_LOCK = new Object();
     28 
     29     // This list contains a FinalizerReference for every finalizable object in the heap.
     30     // Objects in this list may or may not be eligible for finalization yet.
     31     private static FinalizerReference<?> head = null;
     32 
     33     // The links used to construct the list.
     34     private FinalizerReference<?> prev;
     35     private FinalizerReference<?> next;
     36 
     37     // When the GC wants something finalized, it moves it from the 'referent' field to
     38     // the 'zombie' field instead.
     39     private T zombie;
     40 
     41     public FinalizerReference(T r, ReferenceQueue<? super T> q) {
     42         super(r, q);
     43     }
     44 
     45     @Override public T get() {
     46         return zombie;
     47     }
     48 
     49     @Override public void clear() {
     50         zombie = null;
     51     }
     52 
     53     public static void add(Object referent) {
     54         FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue);
     55         synchronized (LIST_LOCK) {
     56             reference.prev = null;
     57             reference.next = head;
     58             if (head != null) {
     59                 head.prev = reference;
     60             }
     61             head = reference;
     62         }
     63     }
     64 
     65     public static void remove(FinalizerReference<?> reference) {
     66         synchronized (LIST_LOCK) {
     67             FinalizerReference<?> next = reference.next;
     68             FinalizerReference<?> prev = reference.prev;
     69             reference.next = null;
     70             reference.prev = null;
     71             if (prev != null) {
     72                 prev.next = next;
     73             } else {
     74                 head = next;
     75             }
     76             if (next != null) {
     77                 next.prev = prev;
     78             }
     79         }
     80     }
     81 
     82     /**
     83      * Waits for all currently-enqueued references to be finalized.
     84      */
     85     public static void finalizeAllEnqueued(long timeout) throws InterruptedException {
     86         // Alloate a new sentinel, this creates a FinalizerReference.
     87         Sentinel sentinel;
     88         // Keep looping until we safely enqueue our sentinel FinalizerReference.
     89         // This is done to prevent races where the GC updates the pendingNext
     90         // before we get the chance.
     91         do {
     92             sentinel = new Sentinel();
     93         } while (!enqueueSentinelReference(sentinel));
     94         sentinel.awaitFinalization(timeout);
     95     }
     96 
     97     private static boolean enqueueSentinelReference(Sentinel sentinel) {
     98         synchronized (LIST_LOCK) {
     99             // When a finalizable object is allocated, a FinalizerReference is added to the list.
    100             // We search the list for that FinalizerReference (it should be at or near the head),
    101             // and then put it on the queue so that it can be finalized.
    102             for (FinalizerReference<?> r = head; r != null; r = r.next) {
    103                 if (r.referent == sentinel) {
    104                     FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
    105                     sentinelReference.referent = null;
    106                     sentinelReference.zombie = sentinel;
    107                     // Make a single element list, then enqueue the reference on the daemon unenqueued
    108                     // list. This is required instead of enqueuing directly on the finalizer queue
    109                     // since there could be recently freed objects in the unqueued list which are not
    110                     // yet on the finalizer queue. This could cause the sentinel to run before the
    111                     // objects are finalized. b/17381967
    112                     // Make circular list if unenqueued goes through native so that we can prevent
    113                     // races where the GC updates the pendingNext before we do. If it is non null, then
    114                     // we update the pending next to make a circular list while holding a lock.
    115                     // b/17462553
    116                     if (!sentinelReference.makeCircularListIfUnenqueued()) {
    117                         return false;
    118                     }
    119                     ReferenceQueue.add(sentinelReference);
    120                     return true;
    121                 }
    122             }
    123         }
    124         // We just created a finalizable object and still hold a reference to it.
    125         // It must be on the list.
    126         throw new AssertionError("newly-created live Sentinel not on list!");
    127     }
    128 
    129     private native boolean makeCircularListIfUnenqueued();
    130 
    131     /**
    132      * A marker object that we can immediately enqueue. When this object's
    133      * finalize() method is called, we know all previously-enqueued finalizable
    134      * references have been finalized.
    135      */
    136     private static class Sentinel {
    137         boolean finalized = false;
    138 
    139         @Override protected synchronized void finalize() throws Throwable {
    140             if (finalized) {
    141                 throw new AssertionError();
    142             }
    143             finalized = true;
    144             notifyAll();
    145         }
    146 
    147         synchronized void awaitFinalization(long timeout) throws InterruptedException {
    148             final long startTime = System.nanoTime();
    149             final long endTime = startTime + timeout;
    150             while (!finalized) {
    151                 // 0 signifies no timeout.
    152                 if (timeout != 0) {
    153                     final long currentTime = System.nanoTime();
    154                     if (currentTime >= endTime) {
    155                         break;
    156                     } else {
    157                         final long deltaTime = endTime - currentTime;
    158                         wait(deltaTime / 1000000, (int)(deltaTime % 1000000));
    159                     }
    160                 } else {
    161                     wait();
    162                 }
    163             }
    164         }
    165     }
    166 }
    167