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.function.Function;
35
36 import sun.misc.InnocuousThread;
37
38 /**
39 * CleanerImpl manages a set of object references and corresponding cleaning actions.
40 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
41 */
42 public final class CleanerImpl {
43
44 /**
45 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
46 */
47 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
48
49 /**
50 * Heads of a CleanableList for each reference type.
51 */
52 final PhantomCleanable<?> phantomCleanableList;
53
54 final WeakCleanable<?> weakCleanableList;
55
56 final SoftCleanable<?> softCleanableList;
57
59 final ReferenceQueue<Object> queue;
60
61 /**
62 * Called by Cleaner static initialization to provide the function
63 * to map from Cleaner to CleanerImpl.
64 * @param access a function to map from Cleaner to CleanerImpl
65 */
66 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
67 if (cleanerImplAccess == null) {
68 cleanerImplAccess = access;
69 } else {
70 throw new InternalError("cleanerImplAccess");
71 }
72 }
73
74 /**
75 * Called to get the CleanerImpl for a Cleaner.
76 * @param cleaner the cleaner
77 * @return the corresponding CleanerImpl
78 */
79 static CleanerImpl getCleanerImpl(Cleaner cleaner) {
80 return cleanerImplAccess.apply(cleaner);
81 }
82
83 /**
84 * Constructor for CleanerImpl.
85 */
86 public CleanerImpl() {
87 queue = new ReferenceQueue<>();
88 phantomCleanableList = new PhantomCleanableRef();
89 weakCleanableList = new WeakCleanableRef();
90 softCleanableList = new SoftCleanableRef();
91 }
92
93 /**
94 * Starts the Cleaner implementation.
95 * Ensure this is the CleanerImpl for the Cleaner.
96 * When started waits for Cleanables to be queued.
97 * @param cleaner the cleaner
98 * @param threadFactory the thread factory
99 */
100 public void start(Cleaner cleaner, ThreadFactory threadFactory) {
101 if (getCleanerImpl(cleaner) != this) {
102 throw new AssertionError("wrong cleaner");
103 }
104 // schedule a nop cleaning action for the cleaner, so the associated thread
105 // will continue to run at least until the cleaner is reclaimable.
106 new PhantomCleanableRef(cleaner, cleaner, () -> {});
107
108 if (threadFactory == null) {
109 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
110 }
111
112 // now that there's at least one cleaning action, for the cleaner,
113 // we can start the associated thread, which runs until
114 // all cleaning actions have been run.
115 Thread thread = threadFactory.newThread(this::run);
116 thread.setDaemon(true);
117 thread.start();
118 }
119
120 /**
121 * Process queued Cleanables as long as the cleanable lists are not empty.
122 * A Cleanable is in one of the lists for each Object and for the Cleaner
123 * itself.
124 * Terminates when the Cleaner is no longer reachable and
125 * has been cleaned and there are no more Cleanable instances
126 * for which the object is reachable.
127 * <p>
128 * If the thread is a ManagedLocalsThread, the threadlocals
129 * are erased before each cleanup
130 */
131 private void run() {
132 Thread t = Thread.currentThread();
133 InnocuousThread mlThread = (t instanceof InnocuousThread)
134 ? (InnocuousThread) t
135 : null;
136 while (!phantomCleanableList.isListEmpty() ||
137 !weakCleanableList.isListEmpty() ||
138 !softCleanableList.isListEmpty()) {
139 if (mlThread != null) {
140 // Clear the thread locals
141 mlThread.eraseThreadLocals();
142 }
143 try {
144 // Wait for a Ref, with a timeout to avoid getting hung
145 // due to a race with clear/clean
146 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
147 if (ref != null) {
148 ref.clean();
149 }
150 } catch (InterruptedException i) {
151 continue; // ignore the interruption
152 } catch (Throwable e) {
153 // ignore exceptions from the cleanup action
154 }
155 }
156 }
157
158 /**
159 * Perform cleaning on an unreachable PhantomReference.
160 */
161 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
162 private final Runnable action;
163
164 /**
165 * Constructor for a phantom cleanable reference.
166 * @param obj the object to monitor
167 * @param cleaner the cleaner
168 * @param action the action Runnable
169 */
170 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
171 super(obj, cleaner);
172 this.action = action;
173 }
174
175 /**
176 * Constructor used only for root of phantom cleanable list.
177 */
178 PhantomCleanableRef() {
304 */
305 @Override
306 public void clear() {
307 throw new UnsupportedOperationException("clear");
308 }
309
310 }
311
312 /**
313 * A ThreadFactory for InnocuousThreads.
314 * The factory is a singleton.
315 */
316 static final class InnocuousThreadFactory implements ThreadFactory {
317 final static ThreadFactory factory = new InnocuousThreadFactory();
318
319 static ThreadFactory factory() {
320 return factory;
321 }
322
323 public Thread newThread(Runnable r) {
324 return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
325 Thread t = new InnocuousThread(r);
326 t.setPriority(Thread.MAX_PRIORITY - 2);
327 t.setName("Cleaner-" + t.getId());
328 return t;
329 });
330 }
331 }
332
333 }
|
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 sun.misc.InnocuousThread;
29
30 import java.lang.ref.Cleaner;
31 import java.lang.ref.Cleaner.Cleanable;
32 import java.lang.ref.ReferenceQueue;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.function.Function;
37
38 /**
39 * CleanerImpl manages a set of object references and corresponding cleaning actions.
40 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
41 */
42 public final class CleanerImpl {
43
44 /**
45 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
46 */
47 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
48
49 /**
50 * Heads of a CleanableList for each reference type.
51 */
52 final PhantomCleanable<?> phantomCleanableList;
53
54 final WeakCleanable<?> weakCleanableList;
55
56 final SoftCleanable<?> softCleanableList;
57
59 final ReferenceQueue<Object> queue;
60
61 /**
62 * Called by Cleaner static initialization to provide the function
63 * to map from Cleaner to CleanerImpl.
64 * @param access a function to map from Cleaner to CleanerImpl
65 */
66 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
67 if (cleanerImplAccess == null) {
68 cleanerImplAccess = access;
69 } else {
70 throw new InternalError("cleanerImplAccess");
71 }
72 }
73
74 /**
75 * Called to get the CleanerImpl for a Cleaner.
76 * @param cleaner the cleaner
77 * @return the corresponding CleanerImpl
78 */
79 public static CleanerImpl getCleanerImpl(Cleaner cleaner) {
80 return cleanerImplAccess.apply(cleaner);
81 }
82
83 /**
84 * Constructor for CleanerImpl.
85 */
86 public CleanerImpl() {
87 queue = new ReferenceQueue<>();
88 phantomCleanableList = new PhantomCleanableRef();
89 weakCleanableList = new WeakCleanableRef();
90 softCleanableList = new SoftCleanableRef();
91 }
92
93 /**
94 * Starts the Cleaner implementation.
95 * Ensure this is the CleanerImpl for the Cleaner.
96 * When started waits for Cleanables to be queued.
97 * @param cleaner the cleaner
98 * @param threadFactory the thread factory
99 */
100 public void start(Cleaner cleaner, ThreadFactory threadFactory) {
101 if (getCleanerImpl(cleaner) != this) {
102 throw new AssertionError("wrong cleaner");
103 }
104 // schedule a nop cleaning action for the cleaner, so the associated thread
105 // will continue to run at least until the cleaner is reclaimable.
106 new CleanerCleanable(cleaner);
107
108 if (threadFactory == null) {
109 threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
110 }
111
112 // now that there's at least one cleaning action, for the cleaner,
113 // we can start the associated thread, which runs until
114 // all cleaning actions have been run.
115 Thread thread = threadFactory.newThread(new Runnable() {
116 @Override
117 public void run() {
118 CleanerImpl.this.run();
119 }
120 });
121 thread.setDaemon(true);
122 thread.start();
123 }
124
125 /**
126 * Process queued Cleanables as long as the cleanable lists are not empty.
127 * A Cleanable is in one of the lists for each Object and for the Cleaner
128 * itself.
129 * Terminates when the Cleaner is no longer reachable and
130 * has been cleaned and there are no more Cleanable instances
131 * for which the object is reachable.
132 * <p>
133 * If the thread is a ManagedLocalsThread, the threadlocals
134 * are erased before each cleanup
135 */
136 void run() {
137 Thread t = Thread.currentThread();
138 InnocuousThread mlThread = (t instanceof InnocuousThread)
139 ? (InnocuousThread) t
140 : null;
141 while (!phantomCleanableList.isListEmpty() ||
142 !weakCleanableList.isListEmpty() ||
143 !softCleanableList.isListEmpty()) {
144 if (mlThread != null) {
145 // Clear the thread locals
146 mlThread.eraseThreadLocals();
147 }
148 try {
149 // Wait for a Ref, with a timeout to avoid getting hung
150 // due to a race with clear/clean
151 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
152 if (ref != null) {
153 ref.clean();
154 }
155 } catch (Throwable e) {
156 // ignore exceptions from the cleanup action
157 // (including interruption of cleanup thread)
158 }
159 }
160 }
161
162 /**
163 * Processes all Cleanable(s) that have been waiting in the queue.
164 *
165 * @return {@code true} if any Cleanable was found in the queue and
166 * was processed or {@code false} if the queue was empty.
167 */
168 public boolean drainQueue() {
169 boolean cleaned = false;
170 Cleanable ref;
171 while ((ref = (Cleanable) queue.poll()) != null) {
172 try {
173 ref.clean();
174 } catch (Throwable t) {
175 // ignore exceptions from the cleanup action
176 }
177 cleaned = true;
178 }
179 return cleaned;
180 }
181
182 /**
183 * Perform cleaning on an unreachable PhantomReference.
184 */
185 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
186 private final Runnable action;
187
188 /**
189 * Constructor for a phantom cleanable reference.
190 * @param obj the object to monitor
191 * @param cleaner the cleaner
192 * @param action the action Runnable
193 */
194 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
195 super(obj, cleaner);
196 this.action = action;
197 }
198
199 /**
200 * Constructor used only for root of phantom cleanable list.
201 */
202 PhantomCleanableRef() {
328 */
329 @Override
330 public void clear() {
331 throw new UnsupportedOperationException("clear");
332 }
333
334 }
335
336 /**
337 * A ThreadFactory for InnocuousThreads.
338 * The factory is a singleton.
339 */
340 static final class InnocuousThreadFactory implements ThreadFactory {
341 final static ThreadFactory factory = new InnocuousThreadFactory();
342
343 static ThreadFactory factory() {
344 return factory;
345 }
346
347 public Thread newThread(Runnable r) {
348 return AccessController.doPrivileged(new PrivilegedAction<Thread>() {
349 @Override
350 public Thread run() {
351 Thread t = new InnocuousThread(r);
352 t.setPriority(Thread.MAX_PRIORITY - 2);
353 t.setName("Cleaner-" + t.getId());
354 return t;
355 }
356 });
357 }
358 }
359
360 /**
361 * A PhantomCleanable implementation for tracking the Cleaner itself.
362 */
363 static final class CleanerCleanable extends PhantomCleanable<Cleaner> {
364 CleanerCleanable(Cleaner cleaner) {
365 super(cleaner, cleaner);
366 }
367
368 @Override
369 protected void performCleanup() {
370 // no action
371 }
372 }
373 }
|