1 /*
   2  * Copyright (c) 2015, 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 java.lang.ref;
  27 
  28 import sun.misc.InnocuousThread;
  29 import sun.misc.ManagedLocalsThread;
  30 
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.util.Objects;
  34 import java.util.concurrent.ThreadFactory;
  35 
  36 /**
  37  * Cleaner manages a set of object references and corresponding cleanup functions.
  38  * Each Cleaner operates independently, managing the pending cleanup functions
  39  * and handling threading and termination when the Cleaner is no longer in use.
  40  * Registering an object reference and corresponding cleaning function returns
  41  * allows the cleaning function to be invoked explicitly
  42  * {@link Cleanable#clean invoked} or to be
  43  * {@link Cleanable#clear cleared}.
  44  * The most efficient use is to explicitly invoke the
  45  * {@link Cleanable#clean Cleanable.clean} method when the object
  46  * is closed or no longer needed.
  47  * The cleaning function is invoked at most once when the object is
  48  * no longer reachable unless it has already been explicitly cleaned or cleared.
  49  * Note that the cleaning function must not refer to the object being registered.
  50  * If so, the object will not become unreachable and the cleaning function
  51  * will not be invoked.
  52  * <p>
  53  * Cleaning functions are registered as:
  54  * <ul>
  55  * <li>{@link #phantomCleanable(Object object, Runnable thunk) phantomCleanable}
  56  * registers the Runnable to be run when the object becomes phantom reachable.
  57  * <li>{@link #weakCleanable(Object object, Runnable thunk) weakCleanable}
  58  * registers the Runnable to be run when object becomes weakly reachable.
  59  * <li>{@link #softCleanable(Object object, Runnable thunk) softCleanable}
  60  * registers the Runnable to be run when object becomes softly reachable.
  61  * </ul>
  62  * <p>
  63  * The execution of the cleaning function is performed
  64  * by a thread associated with the Cleaner.
  65  * The thread runs until all registered cleaning functions have
  66  * executed and the Cleaner itself is reclaimed by the garbage collector.
  67  * Cleaning functions should be prepared to be executed concurrently with
  68  * other cleaning functions.
  69  * <p>
  70  * The behavior of the Cleaner during {@link System#exit(int) System.exit}
  71  * is implementation specific. No guarantees are made related
  72  * to whether cleaning functions are executed or not.
  73  *
  74  * @author Roger Riggs
  75  * @author Kim Barrett
  76  * @apiNote Typically the cleaning functions should be very quick to execute
  77  * and not block. If the cleaning function blocks it may delay processing
  78  * other cleaning functions using the same Cleaner. It is up to the application
  79  * to have mutually compatible cleaning functions on a Cleaner.
  80  */
  81 public final class Cleaner {
  82 
  83     /**
  84      * The Cleaner implementation.
  85      */
  86     final CleanerImpl impl;
  87 
  88     /**
  89      * Construct a Cleaner implementation and start it.
  90      */
  91     private Cleaner() {
  92         impl = new CleanerImpl();
  93     }
  94 
  95     /**
  96      * Return a new Cleaner.
  97      * <p>
  98      * The Cleaner creates a daemon thread to process the
  99      * unreachable objects and to invoke cleaning functions.
 100      * <p>
 101      * The Cleaner terminates when it is unreachable and all of the objects
 102      * registered are unreachable and corresponding Runnables are complete.
 103      *
 104      * @return a new Cleaner
 105      */
 106     public static Cleaner create() {
 107         return create(InnocuousThreadFactory.factory());
 108     }
 109 
 110     /**
 111      * Returns a new Cleaner using a ThreadFactory.
 112      * The cleaning functions are processed on a new Thread from the {@link ThreadFactory}.
 113      * The Thread is {@link Thread#start started} to process cleaning functions.
 114      * The factory should set the Thread attributes as needed for
 115      * priority, name, thread group, uncaught exception handler, etc.
 116      * The thread is set to be a {@link Thread#setDaemon(boolean) daemon thread}.
 117      * The Cleaner uses this daemon thread to process the
 118      * unreachable objects and to invoke cleaning functions.
 119      * <p>
 120      * The Cleaner terminates when it is unreachable and all of the objects
 121      * registered are unreachable and corresponding Runnables are complete.
 122      *
 123      * @param threadFactory a Thread factory to return a new Thread to
 124      *                      process cleaning functions
 125      * @return a new Cleaner
 126      */
 127     public static Cleaner create(ThreadFactory threadFactory) {
 128         Cleaner cleaner = new Cleaner();
 129         cleaner.impl.start(cleaner, threadFactory);
 130         return cleaner;
 131     }
 132 
 133     /**
 134      * Registers an object and a Runnable to be run when the object
 135      * becomes phantom reachable.
 136      * Refer to the class javadoc for cautions about the behavior
 137      * of cleaning functions.
 138      *
 139      * @param obj   the object to monitor
 140      * @param thunk a Runnable to invoke when the object becomes phantom reachable
 141      * @return a Cleanable instance
 142      */
 143     public Cleanable phantomCleanable(Object obj, Runnable thunk) {
 144         Objects.requireNonNull(obj, "obj");
 145         Objects.requireNonNull(thunk, "thunk");
 146         return new PhantomCleanableRef(obj, this, thunk);
 147     }
 148 
 149     /**
 150      * Registers an object and a Runnable to be run when the object
 151      * becomes weakly reachable.
 152      * Refer to the class javadoc for cautions about the behavior
 153      * of cleaning functions.
 154      *
 155      * @param obj   the object to monitor
 156      * @param thunk a Runnable to invoke when the object becomes weakly reachable
 157      * @return a Cleanable instance
 158      */
 159     public Cleanable weakCleanable(Object obj, Runnable thunk) {
 160         Objects.requireNonNull(obj, "obj");
 161         Objects.requireNonNull(thunk, "thunk");
 162         return new WeakCleanableRef(obj, this, thunk);
 163     }
 164 
 165     /**
 166      * Registers an object and a Runnable to be run when the object
 167      * becomes softly reachable.
 168      * Refer to the class javadoc for cautions about the behavior
 169      * of cleaning functions.
 170      *
 171      * @param obj   the object to monitorss
 172      * @param thunk a Runnable to invoke when the object becomes softly reachable
 173      * @return a Cleanable instance
 174      */
 175     public Cleanable softCleanable(Object obj, Runnable thunk) {
 176         Objects.requireNonNull(obj, "obj");
 177         Objects.requireNonNull(thunk, "thunk");
 178         return new SoftCleanableRef(obj, this, thunk);
 179     }
 180 
 181     /**
 182      * CleanerImpl manages the thread and the pending cleanup functions.
 183      */
 184     static final class CleanerImpl implements Runnable {
 185         // Head of the Cleanable list
 186         private final CleanableList cleanableList;
 187 
 188         // The queue of pending cleaning functions
 189         final ReferenceQueue<Object> queue;
 190 
 191         // The lock used to insert or remove a cleaning function from the cleanableList.
 192         private final Object lock;
 193 
 194         // Construct a CleanerImpl.
 195         CleanerImpl() {
 196             queue = new ReferenceQueue<>();
 197             lock = new Object();
 198             cleanableList = new CleanableList();
 199         }
 200 
 201         /**
 202          * Starts the Cleaner implementation.
 203          * When started waits for Cleanables to be queued.
 204          */
 205         void start(Cleaner service, ThreadFactory threadFactory) {
 206             // schedule a nop cleaning function for the service, so the associated thread
 207             // will continue to run at least until the service is reclaimable.
 208             new PhantomCleanableReference<Cleaner>(service, service) {
 209                 @Override protected void performCleanup() { }
 210             };
 211 
 212             // now that there's at least one cleaning function, for the service,
 213             // we can start the associated thread, which runs until
 214             // all cleaning functions have been run.
 215             Thread thread = threadFactory.newThread(this);
 216             thread.setPriority(Thread.MAX_PRIORITY);
 217             thread.setDaemon(true);
 218             thread.start();
 219         }
 220 
 221         /**
 222          * Insert given Cleanable after the cleanableList head.
 223          *
 224          * @param c the Cleanable to insert after cleanableList head
 225          */
 226         void insert(Cleanable c) {
 227             synchronized (lock) {
 228                 setPrev(c, cleanableList);
 229                 Cleanable clNext = getNext(cleanableList);
 230                 setNext(c, clNext);
 231                 setPrev(clNext, c);
 232                 setNext(cleanableList, c);
 233             }
 234         }
 235 
 236         /**
 237          * Remove given Cleanable from the cleanableList.
 238          *
 239          * @param c the Cleanable to remove from the cleanableList
 240          * @return true if Cleanable was removed or false if not because
 241          * it had already been removed before
 242          */
 243         boolean remove(Cleanable c) {
 244             synchronized (lock) {
 245                 if (getNext(c) != c) {
 246                     setPrev(getNext(c), getPrev(c));
 247                     setNext(getPrev(c), getNext(c));
 248                     setPrev(c, c);
 249                     setNext(c, c);
 250                     return true;
 251                 }
 252                 return false;
 253             }
 254         }
 255 
 256         // "polymorphic" next/prev field accessors...
 257         // (wish there were package-private interface methods)
 258 
 259         private Cleanable getNext(Cleanable c) {
 260             if (c instanceof WeakCleanableReference) {
 261                 return ((WeakCleanableReference<?>)c).next;
 262             } else if (c instanceof SoftCleanableReference) {
 263                 return ((SoftCleanableReference<?>)c).next;
 264             } else if (c instanceof PhantomCleanableReference) {
 265                 return ((PhantomCleanableReference<?>)c).next;
 266             } else if (c instanceof CleanableList) {
 267                 return ((CleanableList)c).next;
 268             } else {
 269                 throw invalidCleanable(c);
 270             }
 271         }
 272 
 273         private void setNext(Cleanable c, Cleanable next) {
 274             if (c instanceof WeakCleanableReference) {
 275                 ((WeakCleanableReference<?>)c).next = next;
 276             } else if (c instanceof SoftCleanableReference) {
 277                 ((SoftCleanableReference<?>)c).next = next;
 278             } else if (c instanceof PhantomCleanableReference) {
 279                 ((PhantomCleanableReference<?>)c).next = next;
 280             } else if (c instanceof CleanableList) {
 281                 ((CleanableList)c).next = next;
 282             } else {
 283                 throw invalidCleanable(c);
 284             }
 285         }
 286 
 287         private Cleanable getPrev(Cleanable c) {
 288             if (c instanceof WeakCleanableReference) {
 289                 return ((WeakCleanableReference<?>)c).prev;
 290             } else if (c instanceof SoftCleanableReference) {
 291                 return ((SoftCleanableReference<?>)c).prev;
 292             } else if (c instanceof PhantomCleanableReference) {
 293                 return ((PhantomCleanableReference<?>)c).prev;
 294             } else if (c instanceof CleanableList) {
 295                 return ((CleanableList)c).prev;
 296             } else {
 297                 throw invalidCleanable(c);
 298             }
 299         }
 300 
 301         private void setPrev(Cleanable c, Cleanable prev) {
 302             if (c instanceof WeakCleanableReference) {
 303                 ((WeakCleanableReference<?>)c).prev = prev;
 304             } else if (c instanceof SoftCleanableReference) {
 305                 ((SoftCleanableReference<?>)c).prev = prev;
 306             } else if (c instanceof PhantomCleanableReference) {
 307                 ((PhantomCleanableReference<?>)c).prev = prev;
 308             } else if (c instanceof CleanableList) {
 309                 ((CleanableList)c).prev = prev;
 310             } else {
 311                 throw invalidCleanable(c);
 312             }
 313         }
 314 
 315         private static Error invalidCleanable(Cleanable c) {
 316             return new InternalError("Invalid Cleanable class: " +
 317                                     c.getClass().getName());
 318         }
 319 
 320         /**
 321          * Process queued Cleanables as long as the cleanableList is not empty.
 322          * A Cleanable is in the list for each Object and for the Cleaner
 323          * itself.
 324          * Terminates when the Cleaner is no longer reachable and
 325          * has been cleaned and there are no more Cleanable instances
 326          * for which the object is reachable.
 327          * <p>
 328          * If the thread is a ManagedLocalsThread, the threadlocals
 329          * are erased before each cleanup
 330          */
 331         public void run() {
 332             Thread t = Thread.currentThread();
 333             ManagedLocalsThread mlThread = (t instanceof ManagedLocalsThread)
 334                     ? (ManagedLocalsThread)t
 335                     : null;
 336             while (!cleanableList.isEmpty()) {
 337                 if (mlThread != null) {
 338                     // Cleanable the thread locals
 339                     mlThread.eraseThreadLocals();
 340                 }
 341                 try {
 342                     Cleanable ref = (Cleanable) queue.remove();
 343                     ref.clean();
 344                 } catch (InterruptedException i) {
 345                     continue;   // ignore the interruption
 346                 } catch (RuntimeException e) {
 347                     // ignore exceptions from the cleanup thunk
 348                 }
 349             }
 350         }
 351     }
 352 
 353     /**
 354      * Cleanable instances allow a registered cleaning function to be cleaned or cleared.
 355      * Cleanable Runnables are invoked at most once.
 356      */
 357     public interface Cleanable {
 358         /**
 359          * Unregisters the Cleanable.
 360          * Due to inherent concurrency, the cleaning function may still be invoked.
 361          */
 362         void clear();
 363 
 364         /**
 365          * Unregister the Cleanable and invoke the Runnable,
 366          * ensuring at-most-once semantics.
 367          */
 368         void clean();
 369     }
 370 
 371     /**
 372      * Perform cleaning on an unreachable PhantomReference.
 373      */
 374     static final class PhantomCleanableRef extends PhantomCleanableReference<Object> {
 375         private final Runnable thunk;
 376 
 377         PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) {
 378             super(obj, cleaner);
 379             this.thunk = thunk;
 380         }
 381 
 382         @Override
 383         protected void performCleanup() {
 384             thunk.run();
 385         }
 386 
 387         /**
 388          * Prevent access to referent even when it is still alive.
 389          * @throws UnsupportedOperationException always
 390          * @return nothing
 391          */
 392         @Override
 393         public Object get() {
 394             throw new UnsupportedOperationException();
 395         }
 396     }
 397 
 398     /**
 399      * Perform cleaning on an unreachable WeakReference.
 400      */
 401     static final class WeakCleanableRef extends WeakCleanableReference<Object> {
 402         private final Runnable thunk;
 403 
 404         WeakCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) {
 405             super(obj, cleaner);
 406             this.thunk = thunk;
 407         }
 408 
 409         @Override
 410         protected void performCleanup() {
 411             thunk.run();
 412         }
 413 
 414         /**
 415          * Prevent access to referent even when it is still alive.
 416          * @throws UnsupportedOperationException always
 417          * @return nothing
 418          */
 419         @Override
 420         public Object get() {
 421             throw new UnsupportedOperationException();
 422         }
 423     }
 424 
 425     /**
 426      * Perform cleaning on an unreachable SoftReference.
 427      */
 428     static final class SoftCleanableRef extends SoftCleanableReference<Object> {
 429         private final Runnable thunk;
 430 
 431         SoftCleanableRef(Object obj, Cleaner cleaner, Runnable thunk) {
 432             super(obj, cleaner);
 433             this.thunk = thunk;
 434         }
 435 
 436         @Override
 437         protected void performCleanup() {
 438             thunk.run();
 439         }
 440 
 441         /**
 442          * Prevent access to referent even when it is still alive.
 443          * @throws UnsupportedOperationException always
 444          * @return nothing
 445          */
 446         @Override
 447         public Object get() {
 448             throw new UnsupportedOperationException();
 449         }
 450     }
 451 
 452     static final class CleanableList implements Cleanable {
 453 
 454         Cleanable prev = this, next = this;
 455 
 456         boolean isEmpty() {
 457             return next == this;
 458         }
 459 
 460         @Override
 461         public void clear() {
 462             throw new UnsupportedOperationException();
 463         }
 464 
 465         @Override
 466         public void clean() {
 467             throw new UnsupportedOperationException();
 468         }
 469     }
 470 
 471     /**
 472      * A ThreadFactory for InnocuousThreads (the default).
 473      * The factory is a singleton.
 474      */
 475     static class InnocuousThreadFactory implements ThreadFactory {
 476         final static ThreadFactory factory = new InnocuousThreadFactory();
 477         static ThreadFactory factory() {
 478             return factory;
 479         }
 480         public Thread newThread(Runnable r) {
 481             return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
 482                 Thread t = new InnocuousThread(r);
 483                 t.setName("Cleaner-" + t.getId());
 484                 return t;
 485             });
 486         }
 487     }
 488 }