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 import dalvik.annotation.optimization.FastNative; 20 21 /** 22 * @hide 23 */ 24 public final class FinalizerReference<T> extends Reference<T> { 25 // This queue contains those objects eligible for finalization. 26 public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 27 28 // Guards the list (not the queue). 29 private static final Object LIST_LOCK = new Object(); 30 31 // This list contains a FinalizerReference for every finalizable object in the heap. 32 // Objects in this list may or may not be eligible for finalization yet. 33 private static FinalizerReference<?> head = null; 34 35 // The links used to construct the list. 36 private FinalizerReference<?> prev; 37 private FinalizerReference<?> next; 38 39 // When the GC wants something finalized, it moves it from the 'referent' field to 40 // the 'zombie' field instead. 41 private T zombie; 42 FinalizerReference(T r, ReferenceQueue<? super T> q)43 public FinalizerReference(T r, ReferenceQueue<? super T> q) { 44 super(r, q); 45 } 46 get()47 @Override public T get() { 48 return zombie; 49 } 50 clear()51 @Override public void clear() { 52 zombie = null; 53 } 54 add(Object referent)55 public static void add(Object referent) { 56 FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue); 57 synchronized (LIST_LOCK) { 58 reference.prev = null; 59 reference.next = head; 60 if (head != null) { 61 head.prev = reference; 62 } 63 head = reference; 64 } 65 } 66 remove(FinalizerReference<?> reference)67 public static void remove(FinalizerReference<?> reference) { 68 synchronized (LIST_LOCK) { 69 FinalizerReference<?> next = reference.next; 70 FinalizerReference<?> prev = reference.prev; 71 reference.next = null; 72 reference.prev = null; 73 if (prev != null) { 74 prev.next = next; 75 } else { 76 head = next; 77 } 78 if (next != null) { 79 next.prev = prev; 80 } 81 } 82 } 83 84 /** 85 * Waits for all currently-enqueued references to be finalized. 86 */ finalizeAllEnqueued(long timeout)87 public static void finalizeAllEnqueued(long timeout) throws InterruptedException { 88 // Alloate a new sentinel, this creates a FinalizerReference. 89 Sentinel sentinel; 90 // Keep looping until we safely enqueue our sentinel FinalizerReference. 91 // This is done to prevent races where the GC updates the pendingNext 92 // before we get the chance. 93 do { 94 sentinel = new Sentinel(); 95 } while (!enqueueSentinelReference(sentinel)); 96 sentinel.awaitFinalization(timeout); 97 } 98 enqueueSentinelReference(Sentinel sentinel)99 private static boolean enqueueSentinelReference(Sentinel sentinel) { 100 synchronized (LIST_LOCK) { 101 // When a finalizable object is allocated, a FinalizerReference is added to the list. 102 // We search the list for that FinalizerReference (it should be at or near the head), 103 // and then put it on the queue so that it can be finalized. 104 for (FinalizerReference<?> r = head; r != null; r = r.next) { 105 // Use getReferent() instead of directly accessing the referent field not to race 106 // with GC reference processing. Can't use get() either because it's overridden to 107 // return the zombie. 108 if (r.getReferent() == sentinel) { 109 FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r; 110 sentinelReference.clearReferent(); 111 sentinelReference.zombie = sentinel; 112 // Make a single element list, then enqueue the reference on the daemon unenqueued 113 // list. This is required instead of enqueuing directly on the finalizer queue 114 // since there could be recently freed objects in the unqueued list which are not 115 // yet on the finalizer queue. This could cause the sentinel to run before the 116 // objects are finalized. b/17381967 117 // Make circular list if unenqueued goes through native so that we can prevent 118 // races where the GC updates the pendingNext before we do. If it is non null, then 119 // we update the pending next to make a circular list while holding a lock. 120 // b/17462553 121 if (!sentinelReference.makeCircularListIfUnenqueued()) { 122 return false; 123 } 124 ReferenceQueue.add(sentinelReference); 125 return true; 126 } 127 } 128 } 129 // We just created a finalizable object and still hold a reference to it. 130 // It must be on the list. 131 throw new AssertionError("newly-created live Sentinel not on list!"); 132 } 133 134 @FastNative getReferent()135 private final native T getReferent(); 136 @FastNative makeCircularListIfUnenqueued()137 private native boolean makeCircularListIfUnenqueued(); 138 139 /** 140 * A marker object that we can immediately enqueue. When this object's 141 * finalize() method is called, we know all previously-enqueued finalizable 142 * references have been finalized. 143 */ 144 private static class Sentinel { 145 boolean finalized = false; 146 finalize()147 @Override protected synchronized void finalize() throws Throwable { 148 if (finalized) { 149 throw new AssertionError(); 150 } 151 finalized = true; 152 notifyAll(); 153 } 154 awaitFinalization(long timeout)155 synchronized void awaitFinalization(long timeout) throws InterruptedException { 156 final long startTime = System.nanoTime(); 157 final long endTime = startTime + timeout; 158 while (!finalized) { 159 // 0 signifies no timeout. 160 if (timeout != 0) { 161 final long currentTime = System.nanoTime(); 162 if (currentTime >= endTime) { 163 break; 164 } else { 165 final long deltaTime = endTime - currentTime; 166 wait(deltaTime / 1000000, (int)(deltaTime % 1000000)); 167 } 168 } else { 169 wait(); 170 } 171 } 172 } 173 } 174 } 175