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
26package jdk.internal.ref;
27
28import java.lang.ref.Cleaner;
29import java.lang.ref.Reference;
30import java.lang.ref.SoftReference;
31import java.util.Objects;
32
33/**
34 * SoftCleanable 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 softly reachable.
42 */
43public abstract class SoftCleanable<T> extends SoftReference<T>
44        implements Cleaner.Cleanable {
45
46    /**
47     * Links to previous and next in a doubly-linked list.
48     */
49    SoftCleanable<?> prev = this, next = this;
50
51    /**
52     * The list of SoftCleanable; synchronizes insert and remove.
53     */
54    private final SoftCleanable<?> list;
55
56    /**
57     * Constructs new {@code SoftCleanableReference} 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 with
64     */
65    public SoftCleanable(T referent, Cleaner cleaner) {
66        super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
67        list = CleanerImpl.getCleanerImpl(cleaner).softCleanableList;
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     */
78    SoftCleanable() {
79        super(null, null);
80        this.list = this;
81    }
82
83    /**
84     * Insert this SoftCleanableReference after the list head.
85     */
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 SoftCleanableReference from the list.
97     *
98     * @return true if Cleanable was removed or false if not because
99     * it had already been removed before
100     */
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     */
119    boolean isListEmpty() {
120        synchronized (list) {
121            return list == list.next;
122        }
123    }
124
125    /**
126     * Unregister this SoftCleanable reference and invoke {@link #performCleanup()},
127     * ensuring at-most-once semantics.
128     */
129    @Override
130    public final void clean() {
131        if (remove()) {
132            super.clear();
133            performCleanup();
134        }
135    }
136
137    /**
138     * Unregister this SoftCleanable and clear the reference.
139     * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
140     */
141    @Override
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     */
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
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
176    public final boolean enqueue() {
177        throw new UnsupportedOperationException("enqueue");
178    }
179}
180