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