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
17package java.lang.ref;
18
19import dalvik.annotation.optimization.FastNative;
20
21/**
22 * @hide
23 */
24public 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
43    public FinalizerReference(T r, ReferenceQueue<? super T> q) {
44        super(r, q);
45    }
46
47    @Override public T get() {
48        return zombie;
49    }
50
51    @Override public void clear() {
52        zombie = null;
53    }
54
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
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     */
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
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
135    private final native T getReferent();
136    @FastNative
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
147        @Override protected synchronized void finalize() throws Throwable {
148            if (finalized) {
149                throw new AssertionError();
150            }
151            finalized = true;
152            notifyAll();
153        }
154
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