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 import jdk.internal.misc.JavaLangRefAccess; 30 import jdk.internal.misc.SharedSecrets; 31 import jdk.internal.vm.annotation.ReservedStackAccess; 32 33 import java.lang.ref.Cleaner; 34 import java.lang.ref.ReferenceQueue; 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 import java.util.Objects; 38 import java.util.concurrent.ThreadFactory; 39 import java.util.concurrent.atomic.AtomicInteger; 40 import java.util.concurrent.locks.StampedLock; 41 import java.util.function.BooleanSupplier; 42 43 /** 44 * CleanerImpl is the implementation of {@link Cleaner}. 45 */ 46 public class CleanerImpl implements Cleaner { 47 48 final Task task; 49 50 public CleanerImpl(ThreadFactory threadFactory) { 51 task = new Task(); 52 task.start(this, threadFactory); 53 } 54 55 @Override 56 public Cleanable register(Object obj, Runnable action) { 57 Objects.requireNonNull(obj, "obj"); 58 Objects.requireNonNull(action, "action"); 59 return new CleanerImpl.PhantomCleanableRef(obj, this, action); 60 } 61 62 /** 63 * CleanerImpl.ExtendedImpl is the implementation of {@link ExtendedCleaner}. 64 */ 65 static class ExtendedImpl extends CleanerImpl implements ExtendedCleaner { 66 67 ExtendedImpl(ThreadFactory threadFactory) { 68 super(threadFactory); 69 } 70 71 // A fair lock for threads that retry actions to queue after 72 // 1st optimistic try fails so that only a single thread at a time is 73 // retrying actions while helping the Cleaner execute Cleanable(s) 74 // and trigger new Reference discovery before finally giving up. 75 private final StampedLock helpingLock = new StampedLock(); 76 77 public boolean retryWhileHelpingClean(BooleanSupplier retriableAction) { 78 // 1st optimistic try - allow concurrent execution of actions 79 // until helping is necessary 80 long stamp = helpingLock.tryReadLock(); 81 if (stamp != 0) try { 82 if (retriableAction.getAsBoolean()) { 83 return true; 84 } 85 } finally { 86 helpingLock.unlockRead(stamp); 87 } 88 89 // retrials with helping are exclusive 90 stamp = helpingLock.writeLock(); 91 try { 92 // retry actions while executing enqueued Cleanable(s) until the 93 // queue drains out 94 do { 95 if (retriableAction.getAsBoolean()) { 96 return true; 97 } 98 } while (task.cleanNextEnqueued()); 99 100 // the queue is now empty but there may have been a long time 101 // since last Reference discovery has been performed. 102 JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess(); 103 // trigger Reference(s) discovery 104 int discoveryPhase = jlra.discoverReferences(); 105 // wait for newly discovered Reference(s) to be enqueued 106 boolean interrupted = false; 107 try { 108 while (true) { 109 try { 110 jlra.awaitReferencesEnqueued(discoveryPhase); 111 break; 112 } catch (InterruptedException e) { 113 // ignore interrupts but don't swallow them 114 interrupted = true; 115 } 116 } 117 } finally { 118 if (interrupted) { 119 Thread.currentThread().interrupt(); 120 } 121 } 122 123 // the queue is now hopefully filled with some freshly discovered 124 // Cleanable(s) so retry operation while executing enqueued Cleanable(s) 125 // until the queue drains out 126 do { 127 if (retriableAction.getAsBoolean()) { 128 return true; 129 } 130 } while (task.cleanNextEnqueued()); 131 132 // give up finally 133 return false; 134 } finally { 135 helpingLock.unlockWrite(stamp); 136 } 137 } 138 } 139 140 // package-private access to Task's state 141 PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; } 142 WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; } 143 SoftCleanable<?> softCleanableList() { return task.softCleanableList; } 144 ReferenceQueue<Object> queue() { return task.queue; } 145 146 /** 147 * CleanerImpl.Task manages a set of object references and corresponding 148 * cleaning actions and executes them after they are enqueued. 149 */ 150 private static final class Task implements Runnable { 151 /** 152 * Heads of a CleanableList for each reference type. 153 */ | 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 import jdk.internal.misc.JavaLangRefAccess; 30 import jdk.internal.misc.SharedSecrets; 31 import jdk.internal.vm.annotation.ReservedStackAccess; 32 33 import java.lang.ref.Cleaner; 34 import java.lang.ref.ReferenceQueue; 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 import java.util.Objects; 38 import java.util.concurrent.ThreadFactory; 39 import java.util.concurrent.atomic.AtomicInteger; 40 import java.util.concurrent.locks.StampedLock; 41 import java.util.function.Supplier; 42 43 /** 44 * CleanerImpl is the implementation of {@link Cleaner}. 45 */ 46 public class CleanerImpl implements Cleaner { 47 48 final Task task; 49 50 public CleanerImpl(ThreadFactory threadFactory) { 51 task = new Task(); 52 task.start(this, threadFactory); 53 } 54 55 @Override 56 public Cleanable register(Object obj, Runnable action) { 57 Objects.requireNonNull(obj, "obj"); 58 Objects.requireNonNull(action, "action"); 59 return new CleanerImpl.PhantomCleanableRef(obj, this, action); 60 } 61 62 /** 63 * CleanerImpl.ExtendedImpl is the implementation of {@link ExtendedCleaner}. 64 */ 65 static class ExtendedImpl extends CleanerImpl implements ExtendedCleaner { 66 67 ExtendedImpl(ThreadFactory threadFactory) { 68 super(threadFactory); 69 } 70 71 // A fair lock for threads that retry actions to queue after 72 // 1st optimistic try fails so that only a single thread at a time is 73 // retrying actions while helping the Cleaner execute Cleanable(s) 74 // and trigger new Reference discovery before finally giving up. 75 private final StampedLock helpingLock = new StampedLock(); 76 77 @Override 78 public <T> T retryWhileHelpingClean(Supplier<T> retriableAction) { 79 T result; 80 // 1st optimistic try - allow concurrent execution of actions 81 // until helping is necessary 82 long stamp = helpingLock.tryReadLock(); 83 if (stamp != 0) try { 84 if ((result = retriableAction.get()) != null) { 85 return result; 86 } 87 } finally { 88 helpingLock.unlockRead(stamp); 89 } 90 91 // retrials with helping are exclusive 92 stamp = helpingLock.writeLock(); 93 try { 94 // retry action while executing enqueued Cleanable(s) until the 95 // queue drains out 96 do { 97 if ((result = retriableAction.get()) != null) { 98 return result; 99 } 100 } while (task.cleanNextEnqueued()); 101 102 // the queue is now empty but there may have been a long time 103 // since last Reference discovery has been performed. 104 JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess(); 105 // trigger Reference(s) discovery 106 int discoveryPhase = jlra.discoverReferences(); 107 // wait for newly discovered Reference(s) to be enqueued 108 boolean interrupted = false; 109 try { 110 while (true) { 111 try { 112 jlra.awaitReferencesEnqueued(discoveryPhase); 113 break; 114 } catch (InterruptedException e) { 115 // ignore interrupts but don't swallow them 116 interrupted = true; 117 } 118 } 119 } finally { 120 if (interrupted) { 121 Thread.currentThread().interrupt(); 122 } 123 } 124 125 // the queue is now hopefully filled with some freshly discovered 126 // Cleanable(s) so retry operation while executing enqueued Cleanable(s) 127 // until the queue drains out 128 do { 129 if ((result = retriableAction.get()) != null) { 130 return result; 131 } 132 } while (task.cleanNextEnqueued()); 133 134 // give up finally 135 return null; 136 } finally { 137 helpingLock.unlockWrite(stamp); 138 } 139 } 140 } 141 142 // package-private access to Task's state 143 PhantomCleanable<?> phantomCleanableList() { return task.phantomCleanableList; } 144 WeakCleanable<?> weakCleanableList() { return task.weakCleanableList; } 145 SoftCleanable<?> softCleanableList() { return task.softCleanableList; } 146 ReferenceQueue<Object> queue() { return task.queue; } 147 148 /** 149 * CleanerImpl.Task manages a set of object references and corresponding 150 * cleaning actions and executes them after they are enqueued. 151 */ 152 private static final class Task implements Runnable { 153 /** 154 * Heads of a CleanableList for each reference type. 155 */ |