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 
FinalizerReference(T r, ReferenceQueue<? super T> q)41     public FinalizerReference(T r, ReferenceQueue<? super T> q) {
42         super(r, q);
43     }
44 
get()45     @Override public T get() {
46         return zombie;
47     }
48 
clear()49     @Override public void clear() {
50         zombie = null;
51     }
52 
add(Object referent)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 
remove(FinalizerReference<?> reference)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      */
finalizeAllEnqueued(long timeout)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 
enqueueSentinelReference(Sentinel sentinel)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 
makeCircularListIfUnenqueued()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 
finalize()139         @Override protected synchronized void finalize() throws Throwable {
140             if (finalized) {
141                 throw new AssertionError();
142             }
143             finalized = true;
144             notifyAll();
145         }
146 
awaitFinalization(long timeout)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