1 package jdk.internal.ref;
   2 
   3 /*
   4  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 
  28 import java.lang.ref.Cleaner;
  29 import java.lang.ref.Reference;
  30 import java.lang.ref.WeakReference;
  31 import java.util.Objects;
  32 
  33 /**
  34  * WeakCleanable subclasses efficiently encapsulate cleanup state and
  35  * the cleaning action.
  36  * Subclasses implement the abstract {@link #performCleanup()}  method
  37  * to provide the cleaning action.
  38  * When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable}
  39  * are registered with the {@link Cleaner}.
  40  * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
  41  * referent becomes weakly reachable.
  42  */
  43 public abstract class WeakCleanable<T> extends WeakReference<T>
  44         implements Cleaner.Cleanable {
  45 
  46     /**
  47      * Links to previous and next in a doubly-linked list.
  48      */
  49     WeakCleanable<?> prev = this, next = this;
  50 
  51     /**
  52      * The list of WeakCleanable; synchronizes insert and remove.
  53      */
  54     private final WeakCleanable<?> list;
  55 
  56     /**
  57      * Constructs new {@code WeakCleanableReference} with
  58      * {@code non-null referent} and {@code non-null cleaner}.
  59      * The {@code cleaner} is not retained by this reference; it is only used
  60      * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
  61      *
  62      * @param referent the referent to track
  63      * @param cleaner  the {@code Cleaner} to register new reference with
  64      */
  65     public WeakCleanable(T referent, Cleaner cleaner) {
  66         super(Objects.requireNonNull(referent), ((CleanerImpl)cleaner).queue());
  67         list = ((CleanerImpl)cleaner).weakCleanableList();
  68         insert();
  69 
  70         // Ensure referent and cleaner remain accessible
  71         Reference.reachabilityFence(referent);
  72         Reference.reachabilityFence(cleaner);
  73 
  74     }
  75 
  76     /**
  77      * Construct a new root of the list; not inserted.
  78      */
  79     WeakCleanable() {
  80         super(null, null);
  81         this.list = this;
  82     }
  83 
  84     /**
  85      * Insert this WeakCleanableReference after the list head.
  86      */
  87     private void insert() {
  88         synchronized (list) {
  89             prev = list;
  90             next = list.next;
  91             next.prev = this;
  92             list.next = this;
  93         }
  94     }
  95 
  96     /**
  97      * Remove this WeakCleanableReference from the list.
  98      *
  99      * @return true if Cleanable was removed or false if not because
 100      * it had already been removed before
 101      */
 102     private boolean remove() {
 103         synchronized (list) {
 104             if (next != this) {
 105                 next.prev = prev;
 106                 prev.next = next;
 107                 prev = this;
 108                 next = this;
 109                 return true;
 110             }
 111             return false;
 112         }
 113     }
 114 
 115     /**
 116      * Returns true if the list's next reference refers to itself.
 117      *
 118      * @return true if the list is empty
 119      */
 120     boolean isListEmpty() {
 121         synchronized (list) {
 122             return list == list.next;
 123         }
 124     }
 125 
 126     /**
 127      * Unregister this WeakCleanable reference and invoke {@link #performCleanup()},
 128      * ensuring at-most-once semantics.
 129      */
 130     @Override
 131     public final void clean() {
 132         if (remove()) {
 133             super.clear();
 134             performCleanup();
 135         }
 136     }
 137 
 138     /**
 139      * Unregister this WeakCleanable and clear the reference.
 140      * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
 141      */
 142     @Override
 143     public void clear() {
 144         if (remove()) {
 145             super.clear();
 146         }
 147     }
 148 
 149     /**
 150      * The {@code performCleanup} abstract method is overridden
 151      * to implement the cleaning logic.
 152      * The {@code performCleanup} method should not be called except
 153      * by the {@link #clean} method which ensures at most once semantics.
 154      */
 155     protected abstract void performCleanup();
 156 
 157     /**
 158      * This method always throws {@link UnsupportedOperationException}.
 159      * Enqueuing details of {@link Cleaner.Cleanable}
 160      * are a private implementation detail.
 161      *
 162      * @throws UnsupportedOperationException always
 163      */
 164     @Override
 165     public final boolean isEnqueued() {
 166         throw new UnsupportedOperationException("isEnqueued");
 167     }
 168 
 169     /**
 170      * This method always throws {@link UnsupportedOperationException}.
 171      * Enqueuing details of {@link Cleaner.Cleanable}
 172      * are a private implementation detail.
 173      *
 174      * @throws UnsupportedOperationException always
 175      */
 176     @Override
 177     public final boolean enqueue() {
 178         throw new UnsupportedOperationException("enqueue");
 179     }
 180 }