• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.ref;
27 
28 import java.lang.ref.Cleaner;
29 import java.lang.ref.Cleaner.Cleanable;
30 import java.lang.ref.ReferenceQueue;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.function.Function;
36 
37 import jdk.internal.misc.InnocuousThread;
38 
39 /**
40  * CleanerImpl manages a set of object references and corresponding cleaning actions.
41  * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
42  */
43 public final class CleanerImpl implements Runnable {
44 
45     /**
46      * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
47      */
48     private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
49 
50     /**
51      * Heads of a CleanableList for each reference type.
52      */
53     final PhantomCleanable<?> phantomCleanableList;
54 
55     // Android-removed: WeakCleanable and SoftCleanable. b/198792576
56     // final WeakCleanable<?> weakCleanableList;
57 
58     // Android-removed: WeakCleanable and SoftCleanable. b/198792576
59     // final SoftCleanable<?> softCleanableList;
60 
61     // The ReferenceQueue of pending cleaning actions
62     final ReferenceQueue<Object> queue;
63 
64     /**
65      * Called by Cleaner static initialization to provide the function
66      * to map from Cleaner to CleanerImpl.
67      * @param access a function to map from Cleaner to CleanerImpl
68      */
setCleanerImplAccess(Function<Cleaner, CleanerImpl> access)69     public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
70         if (cleanerImplAccess == null) {
71             cleanerImplAccess = access;
72         } else {
73             throw new InternalError("cleanerImplAccess");
74         }
75     }
76 
77     /**
78      * Called to get the CleanerImpl for a Cleaner.
79      * @param cleaner the cleaner
80      * @return the corresponding CleanerImpl
81      */
getCleanerImpl(Cleaner cleaner)82     static CleanerImpl getCleanerImpl(Cleaner cleaner) {
83         return cleanerImplAccess.apply(cleaner);
84     }
85 
86     /**
87      * Constructor for CleanerImpl.
88      */
CleanerImpl()89     public CleanerImpl() {
90         queue = new ReferenceQueue<>();
91         phantomCleanableList = new PhantomCleanableRef();
92         // Android-removed: WeakCleanable and SoftCleanable. b/198792576
93         // weakCleanableList = new WeakCleanableRef();
94         // softCleanableList = new SoftCleanableRef();
95     }
96 
97     /**
98      * Starts the Cleaner implementation.
99      * Ensure this is the CleanerImpl for the Cleaner.
100      * When started waits for Cleanables to be queued.
101      * @param cleaner the cleaner
102      * @param threadFactory the thread factory
103      */
start(Cleaner cleaner, ThreadFactory threadFactory)104     public void start(Cleaner cleaner, ThreadFactory threadFactory) {
105         if (getCleanerImpl(cleaner) != this) {
106             throw new AssertionError("wrong cleaner");
107         }
108         // schedule a nop cleaning action for the cleaner, so the associated thread
109         // will continue to run at least until the cleaner is reclaimable.
110         new CleanerCleanable(cleaner);
111 
112         if (threadFactory == null) {
113             threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
114         }
115 
116         // now that there's at least one cleaning action, for the cleaner,
117         // we can start the associated thread, which runs until
118         // all cleaning actions have been run.
119         Thread thread = threadFactory.newThread(this);
120         thread.setDaemon(true);
121         thread.start();
122     }
123 
124     /**
125      * Process queued Cleanables as long as the cleanable lists are not empty.
126      * A Cleanable is in one of the lists for each Object and for the Cleaner
127      * itself.
128      * Terminates when the Cleaner is no longer reachable and
129      * has been cleaned and there are no more Cleanable instances
130      * for which the object is reachable.
131      * <p>
132      * If the thread is a ManagedLocalsThread, the threadlocals
133      * are erased before each cleanup
134      */
135     @Override
run()136     public void run() {
137         Thread t = Thread.currentThread();
138         InnocuousThread mlThread = (t instanceof InnocuousThread)
139                 ? (InnocuousThread) t
140                 : null;
141         while (!phantomCleanableList.isListEmpty()) {
142             // Android-removed: WeakCleanable and SoftCleanable. b/198792576
143             //     !weakCleanableList.isListEmpty() ||
144             //     !softCleanableList.isListEmpty()) {
145             if (mlThread != null) {
146                 // Clear the thread locals
147                 mlThread.eraseThreadLocals();
148             }
149             try {
150                 // Wait for a Ref, with a timeout to avoid getting hung
151                 // due to a race with clear/clean
152                 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
153                 if (ref != null) {
154                     ref.clean();
155                 }
156             } catch (Throwable e) {
157                 // ignore exceptions from the cleanup action
158                 // (including interruption of cleanup thread)
159             }
160         }
161     }
162 
163     /**
164      * Perform cleaning on an unreachable PhantomReference.
165      */
166     public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
167         private final Runnable action;
168 
169         /**
170          * Constructor for a phantom cleanable reference.
171          * @param obj the object to monitor
172          * @param cleaner the cleaner
173          * @param action the action Runnable
174          */
PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action)175         public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
176             super(obj, cleaner);
177             this.action = action;
178         }
179 
180         /**
181          * Constructor used only for root of phantom cleanable list.
182          */
PhantomCleanableRef()183         PhantomCleanableRef() {
184             super();
185             this.action = null;
186         }
187 
188         @Override
performCleanup()189         protected void performCleanup() {
190             action.run();
191         }
192 
193         /**
194          * Prevent access to referent even when it is still alive.
195          *
196          * @throws UnsupportedOperationException always
197          */
198         @Override
get()199         public Object get() {
200             throw new UnsupportedOperationException("get");
201         }
202 
203         /**
204          * Direct clearing of the referent is not supported.
205          *
206          * @throws UnsupportedOperationException always
207          */
208         @Override
clear()209         public void clear() {
210             throw new UnsupportedOperationException("clear");
211         }
212     }
213 
214     // BEGIN Android-removed: WeakCleanable and SoftCleanable. b/198792576
215     /*
216      * Perform cleaning on an unreachable WeakReference.
217      *
218     public static final class WeakCleanableRef extends WeakCleanable<Object> {
219         private final Runnable action;
220 
221         /**
222          * Constructor for a weak cleanable reference.
223          * @param obj the object to monitor
224          * @param cleaner the cleaner
225          * @param action the action Runnable
226          *
227         WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
228             super(obj, cleaner);
229             this.action = action;
230         }
231 
232         /**
233          * Constructor used only for root of weak cleanable list.
234          *
235         WeakCleanableRef() {
236             super();
237             this.action = null;
238         }
239 
240         @Override
241         protected void performCleanup() {
242             action.run();
243         }
244 
245         /**
246          * Prevent access to referent even when it is still alive.
247          *
248          * @throws UnsupportedOperationException always
249          *
250         @Override
251         public Object get() {
252             throw new UnsupportedOperationException("get");
253         }
254 
255         /**
256          * Direct clearing of the referent is not supported.
257          *
258          * @throws UnsupportedOperationException always
259          *
260         @Override
261         public void clear() {
262             throw new UnsupportedOperationException("clear");
263         }
264     }
265 
266     /**
267      * Perform cleaning on an unreachable SoftReference.
268      *
269     public static final class SoftCleanableRef extends SoftCleanable<Object> {
270         private final Runnable action;
271 
272         /**
273          * Constructor for a soft cleanable reference.
274          * @param obj the object to monitor
275          * @param cleaner the cleaner
276          * @param action the action Runnable
277          *
278         SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
279             super(obj, cleaner);
280             this.action = action;
281         }
282 
283         /**
284          * Constructor used only for root of soft cleanable list.
285          *
286         SoftCleanableRef() {
287             super();
288             this.action = null;
289         }
290 
291         @Override
292         protected void performCleanup() {
293             action.run();
294         }
295 
296         /**
297          * Prevent access to referent even when it is still alive.
298          *
299          * @throws UnsupportedOperationException always
300          *
301         @Override
302         public Object get() {
303             throw new UnsupportedOperationException("get");
304         }
305 
306         /**
307          * Direct clearing of the referent is not supported.
308          *
309          * @throws UnsupportedOperationException always
310          *
311         @Override
312         public void clear() {
313             throw new UnsupportedOperationException("clear");
314         }
315 
316     }
317     */
318     // END Android-removed: WeakCleanable and SoftCleanable. b/198792576
319 
320     /**
321      * A ThreadFactory for InnocuousThreads.
322      * The factory is a singleton.
323      */
324     static final class InnocuousThreadFactory implements ThreadFactory {
325         final static ThreadFactory factory = new InnocuousThreadFactory();
326 
factory()327         static ThreadFactory factory() {
328             return factory;
329         }
330 
331         final AtomicInteger cleanerThreadNumber = new AtomicInteger();
332 
newThread(Runnable r)333         public Thread newThread(Runnable r) {
334             return AccessController.doPrivileged(new PrivilegedAction<>() {
335                 @Override
336                 public Thread run() {
337                     Thread t = InnocuousThread.newThread(r);
338                     t.setPriority(Thread.MAX_PRIORITY - 2);
339                     t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement());
340                     return t;
341                 }
342             });
343         }
344     }
345 
346     /**
347      * A PhantomCleanable implementation for tracking the Cleaner itself.
348      */
349     static final class CleanerCleanable extends PhantomCleanable<Cleaner> {
350         CleanerCleanable(Cleaner cleaner) {
351             super(cleaner, cleaner);
352         }
353 
354         @Override
355         protected void performCleanup() {
356             // no action
357         }
358     }
359 }
360