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.Reference;
30 import java.lang.ref.PhantomReference;
31 import java.util.Objects;
32 
33 /**
34  * PhantomCleanable 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 phantom reachable.
42  */
43 public abstract class PhantomCleanable<T> extends PhantomReference<T>
44         implements Cleaner.Cleanable {
45 
46     /**
47      * Links to previous and next in a doubly-linked list.
48      */
49     PhantomCleanable<?> prev = this, next = this;
50 
51     /**
52      * The list of PhantomCleanable; synchronizes insert and remove.
53      */
54     private final PhantomCleanable<?> list;
55 
56     /**
57      * Constructs new {@code PhantomCleanable} with
58      * {@code non-null referent} and {@code non-null cleaner}.
59      * The {@code cleaner} is not retained; it is only used to
60      * register the newly constructed {@link Cleaner.Cleanable Cleanable}.
61      *
62      * @param referent the referent to track
63      * @param cleaner  the {@code Cleaner} to register with
64      */
PhantomCleanable(T referent, Cleaner cleaner)65     public PhantomCleanable(T referent, Cleaner cleaner) {
66         super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
67         this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList;
68         insert();
69 
70         // Ensure referent and cleaner remain accessible
71         Reference.reachabilityFence(referent);
72         Reference.reachabilityFence(cleaner);
73     }
74 
75     /**
76      * Construct a new root of the list; not inserted.
77      */
PhantomCleanable()78     PhantomCleanable() {
79         super(null, null);
80         this.list = this;
81     }
82 
83     /**
84      * Insert this PhantomCleanable after the list head.
85      */
insert()86     private void insert() {
87         synchronized (list) {
88             prev = list;
89             next = list.next;
90             next.prev = this;
91             list.next = this;
92         }
93     }
94 
95     /**
96      * Remove this PhantomCleanable from the list.
97      *
98      * @return true if Cleanable was removed or false if not because
99      * it had already been removed before
100      */
remove()101     private boolean remove() {
102         synchronized (list) {
103             if (next != this) {
104                 next.prev = prev;
105                 prev.next = next;
106                 prev = this;
107                 next = this;
108                 return true;
109             }
110             return false;
111         }
112     }
113 
114     /**
115      * Returns true if the list's next reference refers to itself.
116      *
117      * @return true if the list is empty
118      */
isListEmpty()119     boolean isListEmpty() {
120         synchronized (list) {
121             return list == list.next;
122         }
123     }
124 
125     /**
126      * Unregister this PhantomCleanable and invoke {@link #performCleanup()},
127      * ensuring at-most-once semantics.
128      */
129     @Override
clean()130     public final void clean() {
131         if (remove()) {
132             super.clear();
133             performCleanup();
134         }
135     }
136 
137     /**
138      * Unregister this PhantomCleanable and clear the reference.
139      * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
140      */
141     @Override
clear()142     public void clear() {
143         if (remove()) {
144             super.clear();
145         }
146     }
147 
148     /**
149      * The {@code performCleanup} abstract method is overridden
150      * to implement the cleaning logic.
151      * The {@code performCleanup} method should not be called except
152      * by the {@link #clean} method which ensures at most once semantics.
153      */
performCleanup()154     protected abstract void performCleanup();
155 
156     /**
157      * This method always throws {@link UnsupportedOperationException}.
158      * Enqueuing details of {@link Cleaner.Cleanable}
159      * are a private implementation detail.
160      *
161      * @throws UnsupportedOperationException always
162      */
163     @Override
isEnqueued()164     public final boolean isEnqueued() {
165         throw new UnsupportedOperationException("isEnqueued");
166     }
167 
168     /**
169      * This method always throws {@link UnsupportedOperationException}.
170      * Enqueuing details of {@link Cleaner.Cleanable}
171      * are a private implementation detail.
172      *
173      * @throws UnsupportedOperationException always
174      */
175     @Override
enqueue()176     public final boolean enqueue() {
177         throw new UnsupportedOperationException("enqueue");
178     }
179 }
180