| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.lang.ref; |
| |
| import dalvik.annotation.optimization.FastNative; |
| |
| /** |
| * @hide |
| */ |
| public final class FinalizerReference<T> extends Reference<T> { |
| // This queue contains those objects eligible for finalization. |
| public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); |
| |
| // Guards the list (not the queue). |
| private static final Object LIST_LOCK = new Object(); |
| |
| // This list contains a FinalizerReference for every finalizable object in the heap. |
| // Objects in this list may or may not be eligible for finalization yet. |
| private static FinalizerReference<?> head = null; |
| |
| // The links used to construct the list. |
| private FinalizerReference<?> prev; |
| private FinalizerReference<?> next; |
| |
| // When the GC wants something finalized, it moves it from the 'referent' field to |
| // the 'zombie' field instead. |
| private T zombie; |
| |
| public FinalizerReference(T r, ReferenceQueue<? super T> q) { |
| super(r, q); |
| } |
| |
| @Override public T get() { |
| return zombie; |
| } |
| |
| @Override public void clear() { |
| zombie = null; |
| } |
| |
| public static void add(Object referent) { |
| FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue); |
| synchronized (LIST_LOCK) { |
| reference.prev = null; |
| reference.next = head; |
| if (head != null) { |
| head.prev = reference; |
| } |
| head = reference; |
| } |
| } |
| |
| public static void remove(FinalizerReference<?> reference) { |
| synchronized (LIST_LOCK) { |
| FinalizerReference<?> next = reference.next; |
| FinalizerReference<?> prev = reference.prev; |
| reference.next = null; |
| reference.prev = null; |
| if (prev != null) { |
| prev.next = next; |
| } else { |
| head = next; |
| } |
| if (next != null) { |
| next.prev = prev; |
| } |
| } |
| } |
| |
| /** |
| * Waits for all currently-enqueued references to be finalized. |
| */ |
| public static void finalizeAllEnqueued(long timeout) throws InterruptedException { |
| // Alloate a new sentinel, this creates a FinalizerReference. |
| Sentinel sentinel; |
| // Keep looping until we safely enqueue our sentinel FinalizerReference. |
| // This is done to prevent races where the GC updates the pendingNext |
| // before we get the chance. |
| do { |
| sentinel = new Sentinel(); |
| } while (!enqueueSentinelReference(sentinel)); |
| sentinel.awaitFinalization(timeout); |
| } |
| |
| private static boolean enqueueSentinelReference(Sentinel sentinel) { |
| synchronized (LIST_LOCK) { |
| // When a finalizable object is allocated, a FinalizerReference is added to the list. |
| // We search the list for that FinalizerReference (it should be at or near the head), |
| // and then put it on the queue so that it can be finalized. |
| for (FinalizerReference<?> r = head; r != null; r = r.next) { |
| // Use getReferent() instead of directly accessing the referent field not to race |
| // with GC reference processing. Can't use get() either because it's overridden to |
| // return the zombie. |
| if (r.getReferent() == sentinel) { |
| FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r; |
| sentinelReference.clearReferent(); |
| sentinelReference.zombie = sentinel; |
| // Make a single element list, then enqueue the reference on the daemon unenqueued |
| // list. This is required instead of enqueuing directly on the finalizer queue |
| // since there could be recently freed objects in the unqueued list which are not |
| // yet on the finalizer queue. This could cause the sentinel to run before the |
| // objects are finalized. b/17381967 |
| // Make circular list if unenqueued goes through native so that we can prevent |
| // races where the GC updates the pendingNext before we do. If it is non null, then |
| // we update the pending next to make a circular list while holding a lock. |
| // b/17462553 |
| if (!sentinelReference.makeCircularListIfUnenqueued()) { |
| return false; |
| } |
| ReferenceQueue.add(sentinelReference); |
| return true; |
| } |
| } |
| } |
| // We just created a finalizable object and still hold a reference to it. |
| // It must be on the list. |
| throw new AssertionError("newly-created live Sentinel not on list!"); |
| } |
| |
| @FastNative |
| private final native T getReferent(); |
| @FastNative |
| private native boolean makeCircularListIfUnenqueued(); |
| |
| /** |
| * A marker object that we can immediately enqueue. When this object's |
| * finalize() method is called, we know all previously-enqueued finalizable |
| * references have been finalized. |
| */ |
| private static class Sentinel { |
| boolean finalized = false; |
| |
| @Override protected synchronized void finalize() throws Throwable { |
| if (finalized) { |
| throw new AssertionError(); |
| } |
| finalized = true; |
| notifyAll(); |
| } |
| |
| synchronized void awaitFinalization(long timeout) throws InterruptedException { |
| final long startTime = System.nanoTime(); |
| final long endTime = startTime + timeout; |
| while (!finalized) { |
| // 0 signifies no timeout. |
| if (timeout != 0) { |
| final long currentTime = System.nanoTime(); |
| if (currentTime >= endTime) { |
| break; |
| } else { |
| final long deltaTime = endTime - currentTime; |
| wait(deltaTime / 1000000, (int)(deltaTime % 1000000)); |
| } |
| } else { |
| wait(); |
| } |
| } |
| } |
| } |
| } |