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