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.Objects;
34 import java.util.concurrent.ThreadFactory;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.function.Function;
37 
38 import jdk.internal.misc.InnocuousThread;
39 
40 /**
41  * CleanerImpl manages a set of object references and corresponding cleaning actions.
42  * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
43  */
44 public final class CleanerImpl implements Runnable {
45 
46     /**
47      * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
48      */
49     private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
50 
51     /**
52      * Heads of a CleanableList for each reference type.
53      */
54     final PhantomCleanable<?> phantomCleanableList;
55 
56     // Android-removed: WeakCleanable and SoftCleanable. b/198792576
57     // final WeakCleanable<?> weakCleanableList;
58 
59     // Android-removed: WeakCleanable and SoftCleanable. b/198792576
60     // final SoftCleanable<?> softCleanableList;
61 
62     // The ReferenceQueue of pending cleaning actions
63     final ReferenceQueue<Object> queue;
64 
65     /**
66      * Called by Cleaner static initialization to provide the function
67      * to map from Cleaner to CleanerImpl.
68      * @param access a function to map from Cleaner to CleanerImpl
69      */
setCleanerImplAccess(Function<Cleaner, CleanerImpl> access)70     public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
71         if (cleanerImplAccess == null) {
72             cleanerImplAccess = access;
73         } else {
74             throw new InternalError("cleanerImplAccess");
75         }
76     }
77 
78     /**
79      * Called to get the CleanerImpl for a Cleaner.
80      * @param cleaner the cleaner
81      * @return the corresponding CleanerImpl
82      */
getCleanerImpl(Cleaner cleaner)83     static CleanerImpl getCleanerImpl(Cleaner cleaner) {
84         return cleanerImplAccess.apply(cleaner);
85     }
86 
87     /**
88      * Constructor for CleanerImpl.
89      */
CleanerImpl()90     public CleanerImpl() {
91         queue = new ReferenceQueue<>();
92         phantomCleanableList = new PhantomCleanableRef();
93         // Android-removed: WeakCleanable and SoftCleanable. b/198792576
94         // weakCleanableList = new WeakCleanableRef();
95         // softCleanableList = new SoftCleanableRef();
96     }
97 
98     /**
99      * @hide
100      */
CleanerImpl(ReferenceQueue<Object> queue)101     public CleanerImpl(ReferenceQueue<Object> queue) {
102         this.queue = queue;
103         this.phantomCleanableList = new PhantomCleanableRef();
104     }
105 
106     /**
107      * Starts the Cleaner implementation.
108      * Ensure this is the CleanerImpl for the Cleaner.
109      * When started waits for Cleanables to be queued.
110      * @param cleaner the cleaner
111      * @param threadFactory the thread factory
112      */
start(Cleaner cleaner, ThreadFactory threadFactory)113     public void start(Cleaner cleaner, ThreadFactory threadFactory) {
114         if (getCleanerImpl(cleaner) != this) {
115             throw new AssertionError("wrong cleaner");
116         }
117         // schedule a nop cleaning action for the cleaner, so the associated thread
118         // will continue to run at least until the cleaner is reclaimable.
119         new CleanerCleanable(cleaner);
120 
121         if (threadFactory == null) {
122             threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
123         }
124 
125         // now that there's at least one cleaning action, for the cleaner,
126         // we can start the associated thread, which runs until
127         // all cleaning actions have been run.
128         Thread thread = threadFactory.newThread(this);
129         thread.setDaemon(true);
130         thread.start();
131     }
132 
133     // Android-added: start system cleaner which does not need a thread factory.
134     /**
135      * Starts the Cleaner implementation. Does not need a thread factory as it
136      * should be used in the system cleaner only.
137      * @param cleaner the cleaner
138      * @hide
139      */
start(Cleaner cleaner)140     public void start(Cleaner cleaner) {
141         if (getCleanerImpl(cleaner) != this) {
142             throw new AssertionError("wrong cleaner");
143         }
144     }
145 
146     /**
147      * Process queued Cleanables as long as the cleanable lists are not empty.
148      * A Cleanable is in one of the lists for each Object and for the Cleaner
149      * itself.
150      * Terminates when the Cleaner is no longer reachable and
151      * has been cleaned and there are no more Cleanable instances
152      * for which the object is reachable.
153      * <p>
154      * If the thread is a ManagedLocalsThread, the threadlocals
155      * are erased before each cleanup
156      */
157     @Override
run()158     public void run() {
159         Thread t = Thread.currentThread();
160         InnocuousThread mlThread = (t instanceof InnocuousThread)
161                 ? (InnocuousThread) t
162                 : null;
163         while (!phantomCleanableList.isListEmpty()) {
164             // Android-removed: WeakCleanable and SoftCleanable. b/198792576
165             //     !weakCleanableList.isListEmpty() ||
166             //     !softCleanableList.isListEmpty()) {
167             if (mlThread != null) {
168                 // Clear the thread locals
169                 mlThread.eraseThreadLocals();
170             }
171             try {
172                 // Wait for a Ref, with a timeout to avoid getting hung
173                 // due to a race with clear/clean
174                 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
175                 if (ref != null) {
176                     ref.clean();
177                 }
178             } catch (Throwable e) {
179                 // ignore exceptions from the cleanup action
180                 // (including interruption of cleanup thread)
181             }
182         }
183     }
184 
185     /**
186      * Perform cleaning on an unreachable PhantomReference.
187      */
188     public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
189         private final Runnable action;
190 
191         /**
192          * Constructor for a phantom cleanable reference.
193          * @param obj the object to monitor
194          * @param cleaner the cleaner
195          * @param action the action Runnable
196          */
PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action)197         public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
198             super(obj, cleaner);
199             this.action = action;
200         }
201 
202         /**
203          * Constructor used only for root of phantom cleanable list.
204          */
PhantomCleanableRef()205         PhantomCleanableRef() {
206             super();
207             this.action = null;
208         }
209 
210         @Override
performCleanup()211         protected void performCleanup() {
212             action.run();
213         }
214 
215         /**
216          * Prevent access to referent even when it is still alive.
217          *
218          * @throws UnsupportedOperationException always
219          */
220         @Override
get()221         public Object get() {
222             throw new UnsupportedOperationException("get");
223         }
224 
225         /**
226          * Direct clearing of the referent is not supported.
227          *
228          * @throws UnsupportedOperationException always
229          */
230         @Override
clear()231         public void clear() {
232             throw new UnsupportedOperationException("clear");
233         }
234     }
235 
236     // BEGIN Android-removed: WeakCleanable and SoftCleanable. b/198792576
237     /*
238      * Perform cleaning on an unreachable WeakReference.
239      *
240     public static final class WeakCleanableRef extends WeakCleanable<Object> {
241         private final Runnable action;
242 
243         /**
244          * Constructor for a weak cleanable reference.
245          * @param obj the object to monitor
246          * @param cleaner the cleaner
247          * @param action the action Runnable
248          *
249         WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
250             super(obj, cleaner);
251             this.action = action;
252         }
253 
254         /**
255          * Constructor used only for root of weak cleanable list.
256          *
257         WeakCleanableRef() {
258             super();
259             this.action = null;
260         }
261 
262         @Override
263         protected void performCleanup() {
264             action.run();
265         }
266 
267         /**
268          * Prevent access to referent even when it is still alive.
269          *
270          * @throws UnsupportedOperationException always
271          *
272         @Override
273         public Object get() {
274             throw new UnsupportedOperationException("get");
275         }
276 
277         /**
278          * Direct clearing of the referent is not supported.
279          *
280          * @throws UnsupportedOperationException always
281          *
282         @Override
283         public void clear() {
284             throw new UnsupportedOperationException("clear");
285         }
286     }
287 
288     /**
289      * Perform cleaning on an unreachable SoftReference.
290      *
291     public static final class SoftCleanableRef extends SoftCleanable<Object> {
292         private final Runnable action;
293 
294         /**
295          * Constructor for a soft cleanable reference.
296          * @param obj the object to monitor
297          * @param cleaner the cleaner
298          * @param action the action Runnable
299          *
300         SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
301             super(obj, cleaner);
302             this.action = action;
303         }
304 
305         /**
306          * Constructor used only for root of soft cleanable list.
307          *
308         SoftCleanableRef() {
309             super();
310             this.action = null;
311         }
312 
313         @Override
314         protected void performCleanup() {
315             action.run();
316         }
317 
318         /**
319          * Prevent access to referent even when it is still alive.
320          *
321          * @throws UnsupportedOperationException always
322          *
323         @Override
324         public Object get() {
325             throw new UnsupportedOperationException("get");
326         }
327 
328         /**
329          * Direct clearing of the referent is not supported.
330          *
331          * @throws UnsupportedOperationException always
332          *
333         @Override
334         public void clear() {
335             throw new UnsupportedOperationException("clear");
336         }
337 
338     }
339     */
340     // END Android-removed: WeakCleanable and SoftCleanable. b/198792576
341 
342     /**
343      * A ThreadFactory for InnocuousThreads.
344      * The factory is a singleton.
345      */
346     static final class InnocuousThreadFactory implements ThreadFactory {
347         final static ThreadFactory factory = new InnocuousThreadFactory();
348 
factory()349         static ThreadFactory factory() {
350             return factory;
351         }
352 
353         final AtomicInteger cleanerThreadNumber = new AtomicInteger();
354 
newThread(Runnable r)355         public Thread newThread(Runnable r) {
356             return AccessController.doPrivileged(new PrivilegedAction<>() {
357                 @Override
358                 public Thread run() {
359                     Thread t = InnocuousThread.newThread(r);
360                     t.setPriority(Thread.MAX_PRIORITY - 2);
361                     t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement());
362                     return t;
363                 }
364             });
365         }
366     }
367 
368     /**
369      * A PhantomCleanable implementation for tracking the Cleaner itself.
370      */
371     static final class CleanerCleanable extends PhantomCleanable<Cleaner> {
372         CleanerCleanable(Cleaner cleaner) {
373             super(cleaner, cleaner);
374         }
375 
376         @Override
377         protected void performCleanup() {
378             // no action
379         }
380     }
381 }
382