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