From b2163c0e574519bb427df9f7518697f42f0c5edd Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 14 May 2013 13:52:50 +0400 Subject: [PATCH] concurrency: use refcount to control liveness instead of flag --- .../daemon/impl/RefCountHolder.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java index f0ac84d94ab3..6fd6ba54a888 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java @@ -38,6 +38,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class RefCountHolder { @@ -56,19 +57,26 @@ public class RefCountHolder { private static class HolderReference extends SoftReference { @SuppressWarnings("UnusedDeclaration") private volatile RefCountHolder myHardRef; // to prevent gc + // number of live references to RefCountHolder. Once it reaches zero, hard ref is cleared + // the counter is used instead of a flag because multiple passes can be running simultaneously (one actual and several canceled winding down) + // and there is a chance they overlap the usage of RCH + private final AtomicInteger myRefCount = new AtomicInteger(); public HolderReference(@NotNull RefCountHolder holder) { super(holder); myHardRef = holder; } - - private void makeHardReachable(boolean isHard) { - RefCountHolder holder = get(); - assert !isHard || holder != null : "hard: "+isHard +"; holder="+holder; - myHardRef = isHard ? holder : null; + + private void changeLivenessBy(int delta) { + if (myRefCount.addAndGet(delta) == 0) { + myHardRef = null; + } + else if (myHardRef == null) { + myHardRef = get(); + } } } - + private static final Key REF_COUNT_HOLDER_IN_FILE_KEY = Key.create("REF_COUNT_HOLDER_IN_FILE_KEY"); @NotNull private static Pair getInstance(@NotNull PsiFile file, boolean create) { @@ -98,7 +106,7 @@ public class RefCountHolder { public static RefCountHolder startUsing(@NotNull PsiFile file) { Pair pair = getInstance(file, true); HolderReference reference = pair.second; - reference.makeHardReachable(true); // make sure RefCountHolder won't be gced during highlighting + reference.changeLivenessBy(1); // make sure RefCountHolder won't be gced during highlighting log("startUsing: " + pair.first.myState+" for "+file); return pair.first; } @@ -107,12 +115,12 @@ public class RefCountHolder { public static RefCountHolder endUsing(@NotNull PsiFile file) { Pair pair = getInstance(file, false); HolderReference reference = pair.second; - reference.makeHardReachable(false); // no longer needed, can be cleared + reference.changeLivenessBy(-1); // no longer needed, can be cleared RefCountHolder holder = pair.first; log("endUsing: " + (holder == null ? null : holder.myState)+" for "+file); return holder; } - + private RefCountHolder(@NotNull PsiFile file) { myFile = file; log("c: created: " + myState.get()+" for "+file);