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