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.Cleaner.Cleanable;
30 import java.lang.ref.ReferenceQueue;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.function.Function;
36
37 import jdk.internal.misc.InnocuousThread;
38
39 /**
40 * CleanerImpl manages a set of object references and corresponding cleaning actions.
41 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
42 */
43 public final class CleanerImpl implements Runnable {
44
45 /**
46 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
47 */
48 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
49
50 /**
51 * Heads of a CleanableList for each reference type.
52 */
53 final PhantomCleanable<?> phantomCleanableList;
54
55 final WeakCleanable<?> weakCleanableList;
56
57 final SoftCleanable<?> softCleanableList;
58
59 // The ReferenceQueue of pending cleaning actions
60 final ReferenceQueue<Object> queue;
61
62 /**
63 * Called by Cleaner static initialization to provide the function
64 * to map from Cleaner to CleanerImpl.
65 * @param access a function to map from Cleaner to CleanerImpl
66 */
67 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
68 if (cleanerImplAccess == null) {
69 cleanerImplAccess = access;
70 } else {
71 throw new InternalError("cleanerImplAccess");
72 }
73 }
74
75 /**
76 * Called to get the CleanerImpl for a Cleaner.
77 * @param cleaner the cleaner
78 * @return the corresponding CleanerImpl
79 */
80 static CleanerImpl getCleanerImpl(Cleaner cleaner) {
81 return cleanerImplAccess.apply(cleaner);
82 }
83
84 /**
85 * Constructor for CleanerImpl.
86 */
87 public CleanerImpl() {
88 queue = new ReferenceQueue<>();
89 phantomCleanableList = new PhantomCleanableRef();
90 weakCleanableList = new WeakCleanableRef();
91 softCleanableList = new SoftCleanableRef();
92 }
93
94 /**
95 * Starts the Cleaner implementation.
96 * Ensure this is the CleanerImpl for the Cleaner.
97 * When started waits for Cleanables to be queued.
98 * @param cleaner the cleaner
99 * @param threadFactory the thread factory
100 */
101 public void start(Cleaner cleaner, ThreadFactory threadFactory) {
102 if (getCleanerImpl(cleaner) != this) {
103 throw new AssertionError("wrong cleaner");
104 }
105 // schedule a nop cleaning action for the cleaner, so the associated thread
106 // will continue to run at least until the cleaner is reclaimable.
107 new CleanerCleanable(cleaner);
108
109 if (threadFactory == null) {
110 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
111 }
112
113 // now that there's at least one cleaning action, for the cleaner,
114 // we can start the associated thread, which runs until
115 // all cleaning actions have been run.
116 Thread thread = threadFactory.newThread(this);
117 thread.setDaemon(true);
118 thread.start();
119 }
120
121 /**
122 * Process queued Cleanables as long as the cleanable lists are not empty.
135 InnocuousThread mlThread = (t instanceof InnocuousThread)
136 ? (InnocuousThread) t
137 : null;
138 while (!phantomCleanableList.isListEmpty() ||
139 !weakCleanableList.isListEmpty() ||
140 !softCleanableList.isListEmpty()) {
141 if (mlThread != null) {
142 // Clear the thread locals
143 mlThread.eraseThreadLocals();
144 }
145 try {
146 // Wait for a Ref, with a timeout to avoid getting hung
147 // due to a race with clear/clean
148 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
149 if (ref != null) {
150 ref.clean();
151 }
152 } catch (Throwable e) {
153 // ignore exceptions from the cleanup action
154 // (including interruption of cleanup thread)
155 }
156 }
157 }
158
159 /**
160 * Perform cleaning on an unreachable PhantomReference.
161 */
162 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
163 private final Runnable action;
164
165 /**
166 * Constructor for a phantom cleanable reference.
167 * @param obj the object to monitor
168 * @param cleaner the cleaner
169 * @param action the action Runnable
170 */
171 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
172 super(obj, cleaner);
173 this.action = action;
174 }
|
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 jdk.internal.misc.InnocuousThread;
29
30 import java.lang.ref.Cleaner;
31 import java.lang.ref.ReferenceQueue;
32 import java.security.AccessController;
33 import java.security.PrivilegedAction;
34 import java.util.Objects;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.concurrent.atomic.AtomicInteger;
37
38 /**
39 * CleanerImpl is the implementation of {@link Cleaner}.
40 */
41 public class CleanerImpl implements Cleaner {
42
43 final Task task;
44
45 public CleanerImpl(ThreadFactory threadFactory) {
46 task = new Task();
47 task.start(this, threadFactory);
48 }
49
50 @Override
51 public Cleanable register(Object obj, Runnable action) {
52 Objects.requireNonNull(obj, "obj");
53 Objects.requireNonNull(action, "action");
54 return new CleanerImpl.PhantomCleanableRef(obj, this, action);
55 }
56
57 // package-private access to Task's state
58 PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; }
59 WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; }
60 SoftCleanable<?> softCleanableList() { return task.softCleanableList; }
61 ReferenceQueue<Object> queue() { return task.queue; }
62
63 /**
64 * CleanerImpl.Task manages a set of object references and corresponding
65 * cleaning actions and executes them after they are enqueued.
66 */
67 private static final class Task implements Runnable {
68 /**
69 * Heads of a CleanableList for each reference type.
70 */
71 final PhantomCleanable<?> phantomCleanableList;
72
73 final WeakCleanable<?> weakCleanableList;
74
75 final SoftCleanable<?> softCleanableList;
76
77 // The ReferenceQueue of pending cleaning actions
78 final ReferenceQueue<Object> queue;
79
80 /**
81 * Constructor for Task.
82 */
83 Task() {
84 queue = new ReferenceQueue<>();
85 phantomCleanableList = new PhantomCleanableRef();
86 weakCleanableList = new WeakCleanableRef();
87 softCleanableList = new SoftCleanableRef();
88 }
89
90 /**
91 * Starts the Cleaner implementation.
92 * Ensure this is the CleanerImpl for the Cleaner.
93 * When started waits for Cleanables to be queued.
94 * @param cleaner the cleaner
95 * @param threadFactory the thread factory
96 */
97 void start(CleanerImpl cleaner, ThreadFactory threadFactory) {
98 if (cleaner.task != this) {
99 throw new AssertionError("wrong cleaner");
100 }
101 // schedule a nop cleaning action for the cleaner, so the associated thread
102 // will continue to run at least until the cleaner is reclaimable.
103 new CleanerCleanable(cleaner);
104
105 if (threadFactory == null) {
106 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
107 }
108
109 // now that there's at least one cleaning action, for the cleaner,
110 // we can start the associated thread, which runs until
111 // all cleaning actions have been run.
112 Thread thread = threadFactory.newThread(this);
113 thread.setDaemon(true);
114 thread.start();
115 }
116
117 /**
118 * Process queued Cleanables as long as the cleanable lists are not empty.
131 InnocuousThread mlThread = (t instanceof InnocuousThread)
132 ? (InnocuousThread) t
133 : null;
134 while (!phantomCleanableList.isListEmpty() ||
135 !weakCleanableList.isListEmpty() ||
136 !softCleanableList.isListEmpty()) {
137 if (mlThread != null) {
138 // Clear the thread locals
139 mlThread.eraseThreadLocals();
140 }
141 try {
142 // Wait for a Ref, with a timeout to avoid getting hung
143 // due to a race with clear/clean
144 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
145 if (ref != null) {
146 ref.clean();
147 }
148 } catch (Throwable e) {
149 // ignore exceptions from the cleanup action
150 // (including interruption of cleanup thread)
151 }
152 }
153 }
154 }
155
156 /**
157 * Perform cleaning on an unreachable PhantomReference.
158 */
159 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
160 private final Runnable action;
161
162 /**
163 * Constructor for a phantom cleanable reference.
164 * @param obj the object to monitor
165 * @param cleaner the cleaner
166 * @param action the action Runnable
167 */
168 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
169 super(obj, cleaner);
170 this.action = action;
171 }
|