| /* |
| * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package jdk.internal.ref; |
| |
| import java.lang.ref.Cleaner; |
| import java.lang.ref.Cleaner.Cleanable; |
| import java.lang.ref.ReferenceQueue; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.concurrent.ThreadFactory; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.function.Function; |
| |
| import jdk.internal.misc.InnocuousThread; |
| |
| /** |
| * CleanerImpl manages a set of object references and corresponding cleaning actions. |
| * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. |
| */ |
| public final class CleanerImpl implements Runnable { |
| |
| /** |
| * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. |
| */ |
| private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null; |
| |
| /** |
| * Heads of a CleanableList for each reference type. |
| */ |
| final PhantomCleanable<?> phantomCleanableList; |
| |
| final WeakCleanable<?> weakCleanableList; |
| |
| final SoftCleanable<?> softCleanableList; |
| |
| // The ReferenceQueue of pending cleaning actions |
| final ReferenceQueue<Object> queue; |
| |
| /** |
| * Called by Cleaner static initialization to provide the function |
| * to map from Cleaner to CleanerImpl. |
| * @param access a function to map from Cleaner to CleanerImpl |
| */ |
| public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) { |
| if (cleanerImplAccess == null) { |
| cleanerImplAccess = access; |
| } else { |
| throw new InternalError("cleanerImplAccess"); |
| } |
| } |
| |
| /** |
| * Called to get the CleanerImpl for a Cleaner. |
| * @param cleaner the cleaner |
| * @return the corresponding CleanerImpl |
| */ |
| static CleanerImpl getCleanerImpl(Cleaner cleaner) { |
| return cleanerImplAccess.apply(cleaner); |
| } |
| |
| /** |
| * Constructor for CleanerImpl. |
| */ |
| public CleanerImpl() { |
| queue = new ReferenceQueue<>(); |
| phantomCleanableList = new PhantomCleanableRef(); |
| weakCleanableList = new WeakCleanableRef(); |
| softCleanableList = new SoftCleanableRef(); |
| } |
| |
| /** |
| * Starts the Cleaner implementation. |
| * Ensure this is the CleanerImpl for the Cleaner. |
| * When started waits for Cleanables to be queued. |
| * @param cleaner the cleaner |
| * @param threadFactory the thread factory |
| */ |
| public void start(Cleaner cleaner, ThreadFactory threadFactory) { |
| if (getCleanerImpl(cleaner) != this) { |
| throw new AssertionError("wrong cleaner"); |
| } |
| // schedule a nop cleaning action for the cleaner, so the associated thread |
| // will continue to run at least until the cleaner is reclaimable. |
| new CleanerCleanable(cleaner); |
| |
| if (threadFactory == null) { |
| threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); |
| } |
| |
| // now that there's at least one cleaning action, for the cleaner, |
| // we can start the associated thread, which runs until |
| // all cleaning actions have been run. |
| Thread thread = threadFactory.newThread(this); |
| thread.setDaemon(true); |
| thread.start(); |
| } |
| |
| /** |
| * Process queued Cleanables as long as the cleanable lists are not empty. |
| * A Cleanable is in one of the lists for each Object and for the Cleaner |
| * itself. |
| * Terminates when the Cleaner is no longer reachable and |
| * has been cleaned and there are no more Cleanable instances |
| * for which the object is reachable. |
| * <p> |
| * If the thread is a ManagedLocalsThread, the threadlocals |
| * are erased before each cleanup |
| */ |
| @Override |
| public void run() { |
| Thread t = Thread.currentThread(); |
| InnocuousThread mlThread = (t instanceof InnocuousThread) |
| ? (InnocuousThread) t |
| : null; |
| while (!phantomCleanableList.isListEmpty() || |
| !weakCleanableList.isListEmpty() || |
| !softCleanableList.isListEmpty()) { |
| if (mlThread != null) { |
| // Clear the thread locals |
| mlThread.eraseThreadLocals(); |
| } |
| try { |
| // Wait for a Ref, with a timeout to avoid getting hung |
| // due to a race with clear/clean |
| Cleanable ref = (Cleanable) queue.remove(60 * 1000L); |
| if (ref != null) { |
| ref.clean(); |
| } |
| } catch (Throwable e) { |
| // ignore exceptions from the cleanup action |
| // (including interruption of cleanup thread) |
| } |
| } |
| } |
| |
| /** |
| * Perform cleaning on an unreachable PhantomReference. |
| */ |
| public static final class PhantomCleanableRef extends PhantomCleanable<Object> { |
| private final Runnable action; |
| |
| /** |
| * Constructor for a phantom cleanable reference. |
| * @param obj the object to monitor |
| * @param cleaner the cleaner |
| * @param action the action Runnable |
| */ |
| public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { |
| super(obj, cleaner); |
| this.action = action; |
| } |
| |
| /** |
| * Constructor used only for root of phantom cleanable list. |
| */ |
| PhantomCleanableRef() { |
| super(); |
| this.action = null; |
| } |
| |
| @Override |
| protected void performCleanup() { |
| action.run(); |
| } |
| |
| /** |
| * Prevent access to referent even when it is still alive. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public Object get() { |
| throw new UnsupportedOperationException("get"); |
| } |
| |
| /** |
| * Direct clearing of the referent is not supported. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public void clear() { |
| throw new UnsupportedOperationException("clear"); |
| } |
| } |
| |
| /** |
| * Perform cleaning on an unreachable WeakReference. |
| */ |
| public static final class WeakCleanableRef extends WeakCleanable<Object> { |
| private final Runnable action; |
| |
| /** |
| * Constructor for a weak cleanable reference. |
| * @param obj the object to monitor |
| * @param cleaner the cleaner |
| * @param action the action Runnable |
| */ |
| WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) { |
| super(obj, cleaner); |
| this.action = action; |
| } |
| |
| /** |
| * Constructor used only for root of weak cleanable list. |
| */ |
| WeakCleanableRef() { |
| super(); |
| this.action = null; |
| } |
| |
| @Override |
| protected void performCleanup() { |
| action.run(); |
| } |
| |
| /** |
| * Prevent access to referent even when it is still alive. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public Object get() { |
| throw new UnsupportedOperationException("get"); |
| } |
| |
| /** |
| * Direct clearing of the referent is not supported. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public void clear() { |
| throw new UnsupportedOperationException("clear"); |
| } |
| } |
| |
| /** |
| * Perform cleaning on an unreachable SoftReference. |
| */ |
| public static final class SoftCleanableRef extends SoftCleanable<Object> { |
| private final Runnable action; |
| |
| /** |
| * Constructor for a soft cleanable reference. |
| * @param obj the object to monitor |
| * @param cleaner the cleaner |
| * @param action the action Runnable |
| */ |
| SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) { |
| super(obj, cleaner); |
| this.action = action; |
| } |
| |
| /** |
| * Constructor used only for root of soft cleanable list. |
| */ |
| SoftCleanableRef() { |
| super(); |
| this.action = null; |
| } |
| |
| @Override |
| protected void performCleanup() { |
| action.run(); |
| } |
| |
| /** |
| * Prevent access to referent even when it is still alive. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public Object get() { |
| throw new UnsupportedOperationException("get"); |
| } |
| |
| /** |
| * Direct clearing of the referent is not supported. |
| * |
| * @throws UnsupportedOperationException always |
| */ |
| @Override |
| public void clear() { |
| throw new UnsupportedOperationException("clear"); |
| } |
| |
| } |
| |
| /** |
| * A ThreadFactory for InnocuousThreads. |
| * The factory is a singleton. |
| */ |
| static final class InnocuousThreadFactory implements ThreadFactory { |
| final static ThreadFactory factory = new InnocuousThreadFactory(); |
| |
| static ThreadFactory factory() { |
| return factory; |
| } |
| |
| final AtomicInteger cleanerThreadNumber = new AtomicInteger(); |
| |
| public Thread newThread(Runnable r) { |
| return AccessController.doPrivileged(new PrivilegedAction<>() { |
| @Override |
| public Thread run() { |
| Thread t = InnocuousThread.newThread(r); |
| t.setPriority(Thread.MAX_PRIORITY - 2); |
| t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement()); |
| return t; |
| } |
| }); |
| } |
| } |
| |
| /** |
| * A PhantomCleanable implementation for tracking the Cleaner itself. |
| */ |
| static final class CleanerCleanable extends PhantomCleanable<Cleaner> { |
| CleanerCleanable(Cleaner cleaner) { |
| super(cleaner, cleaner); |
| } |
| |
| @Override |
| protected void performCleanup() { |
| // no action |
| } |
| } |
| } |