1 /*
   2  * Copyright (c) 2003, 2013, 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 sun.misc;
  27 
  28 import java.lang.ref.*;
  29 import java.security.AccessController;
  30 import java.security.PrivilegedAction;
  31 
  32 
  33 /**
  34  * General-purpose phantom-reference-based cleaners.
  35  *
  36  * <p> Cleaners are a lightweight and more robust alternative to finalization.
  37  * They are lightweight because they are not created by the VM and thus do not
  38  * require a JNI upcall to be created, and because their cleanup code is
  39  * invoked directly by the reference-handler thread rather than by the
  40  * finalizer thread.  They are more robust because they use phantom references,
  41  * the weakest type of reference object, thereby avoiding the nasty ordering
  42  * problems inherent to finalization.
  43  *
  44  * <p> A cleaner tracks a referent object and encapsulates a thunk of arbitrary
  45  * cleanup code.  Some time after the GC detects that a cleaner's referent has
  46  * become phantom-reachable, the reference-handler thread will run the cleaner.
  47  * Cleaners may also be invoked directly; they are thread safe and ensure that
  48  * they run their thunks at most once.
  49  *
  50  * <p> Cleaners are not a replacement for finalization.  They should be used
  51  * only when the cleanup code is extremely simple and straightforward.
  52  * Nontrivial cleaners are inadvisable since they risk blocking the
  53  * reference-handler thread and delaying further cleanup and finalization.
  54  *
  55  *
  56  * @author Mark Reinhold
  57  */
  58 
  59 public class Cleaner
  60     extends PhantomReference<Object>
  61 {
  62 
  63     // Dummy reference queue, needed because the PhantomReference constructor
  64     // insists that we pass a queue.  Nothing will ever be placed on this queue
  65     // since the reference handler invokes cleaners explicitly.
  66     //
  67     private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();
  68 
  69     // Doubly-linked list of live cleaners, which prevents the cleaners
  70     // themselves from being GC'd before their referents
  71     //
  72     private static Cleaner first = null;
  73 
  74     private Cleaner
  75         next = null,
  76         prev = null;
  77 
  78     private static synchronized Cleaner add(Cleaner cl) {
  79         if (first != null) {
  80             cl.next = first;
  81             first.prev = cl;
  82         }
  83         first = cl;
  84         return cl;
  85     }
  86 
  87     private static synchronized boolean remove(Cleaner cl) {
  88 
  89         // If already removed, do nothing
  90         if (cl.next == cl)
  91             return false;
  92 
  93         // Update list
  94         if (first == cl) {
  95             if (cl.next != null)
  96                 first = cl.next;
  97             else
  98                 first = cl.prev;
  99         }
 100         if (cl.next != null)
 101             cl.next.prev = cl.prev;
 102         if (cl.prev != null)
 103             cl.prev.next = cl.next;
 104 
 105         // Indicate removal by pointing the cleaner to itself
 106         cl.next = cl;
 107         cl.prev = cl;
 108         return true;
 109 
 110     }
 111 
 112     private final Runnable thunk;
 113 
 114     private Cleaner(Object referent, Runnable thunk) {
 115         super(referent, dummyQueue);
 116         this.thunk = thunk;
 117     }
 118 
 119     /**
 120      * Creates a new cleaner.
 121      *
 122      * @param  ob the referent object to be cleaned
 123      * @param  thunk
 124      *         The cleanup code to be run when the cleaner is invoked.  The
 125      *         cleanup code is run directly from the reference-handler thread,
 126      *         so it should be as simple and straightforward as possible.
 127      *
 128      * @return  The new cleaner
 129      */
 130     public static Cleaner create(Object ob, Runnable thunk) {
 131         if (thunk == null)
 132             return null;
 133         return add(new Cleaner(ob, thunk));
 134     }
 135 
 136     /**
 137      * Runs this cleaner, if it has not been run before.
 138      */
 139     public void clean() {
 140         if (!remove(this))
 141             return;
 142         try {
 143             thunk.run();
 144         } catch (final Throwable x) {
 145             AccessController.doPrivileged(new PrivilegedAction<>() {
 146                     public Void run() {
 147                         if (System.err != null)
 148                             new Error("Cleaner terminated abnormally", x)
 149                                 .printStackTrace();
 150                         System.exit(1);
 151                         return null;
 152                     }});
 153         }
 154     }
 155 
 156 }