diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java
index f40a20e7ad3..874fbb9719f 100644
--- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java
+++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java
@@ -17,6 +17,7 @@ import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
@@ -37,26 +38,30 @@ public class ASTCacheTests extends BaseTestCase {
private static int fgReconcilerCount;
public class MockReconciler extends Thread {
- private ITranslationUnit fTU;
- private ASTCache fCache;
+ private final ITranslationUnit fTU;
+ private final ASTCache fCache;
public volatile boolean fStopped;
- private IASTTranslationUnit fAST;
+ public IASTTranslationUnit fAST;
public MockReconciler(ITranslationUnit tu, ASTCache cache) {
super("MockReconciler-"+fgReconcilerCount++);
fTU= tu;
fCache= cache;
+ setDaemon(true);
}
public void run() {
while (!fStopped) {
try {
- Thread.sleep(200);
- fCache.aboutToBeReconciled(fTU);
synchronized (this) {
- notifyAll();
+ fCache.aboutToBeReconciled(fTU);
+ fAST= null;
+ notify();
+ }
+ Thread.sleep(100);
+ synchronized (this) {
+ fAST= fCache.createAST(fTU, fIndex, null);
+ fCache.reconciled(fAST, fTU);
}
- fAST= fCache.createAST(fTU, fIndex, null);
- fCache.reconciled(fAST, fTU);
} catch (InterruptedException exc) {
fStopped= true;
break;
@@ -84,17 +89,18 @@ public class ASTCacheTests extends BaseTestCase {
public void setUp() throws Exception {
super.setUp();
+ IProgressMonitor npm= new NullProgressMonitor();
fProject= createProject("ASTCacheTest");
assertNotNull(fProject);
IFile file1= createFile(fProject.getProject(), "source1.cpp", SOURCE1);
assertNotNull(file1);
- fTU1= CProjectHelper.findTranslationUnit(fProject, file1.getName());
- assertNotNull(fTU1);
IFile file2= createFile(fProject.getProject(), "source2.cpp", SOURCE2);
assertNotNull(file2);
- fTU2= CProjectHelper.findTranslationUnit(fProject, file2.getName());
+ fTU1= (ITranslationUnit) CoreModel.getDefault().create(file1);
+ assertNotNull(fTU1);
+ fTU2= (ITranslationUnit) CoreModel.getDefault().create(file2);
assertNotNull(fTU2);
- CCorePlugin.getIndexManager().joinIndexer(5000, new NullProgressMonitor());
+ CCorePlugin.getIndexManager().joinIndexer(5000, npm);
fIndex= CCorePlugin.getIndexManager().getIndex(fProject);
fIndex.acquireReadLock();
}
@@ -153,37 +159,47 @@ public class ASTCacheTests extends BaseTestCase {
private void checkAccessWithSequentialReconciler() throws Exception {
ASTCache cache= new ASTCache();
- cache.setActiveElement(fTU1);
MockReconciler reconciler1= new MockReconciler(fTU1, cache);
- MockReconciler reconciler2= null;
+ MockReconciler reconciler2= new MockReconciler(fTU2, cache);
try {
+ cache.setActiveElement(fTU1);
assertFalse(cache.isReconciling(fTU1));
synchronized (reconciler1) {
reconciler1.start();
reconciler1.wait();
+ assertNull(reconciler1.fAST);
+ assertTrue(cache.isActiveElement(fTU1));
+ assertTrue(cache.isReconciling(fTU1));
}
+ reconciler1.fStopped= true;
IASTTranslationUnit ast;
ast= cache.getAST(fTU1, fIndex, true, null);
assertNotNull(ast);
+ assertTrue(cache.isActiveElement(fTU1));
+ assertFalse(cache.isReconciling(fTU1));
assertSame(ast, reconciler1.fAST);
// change active element
cache.setActiveElement(fTU2);
- reconciler2= new MockReconciler(fTU2, cache);
+ assertFalse(cache.isReconciling(fTU2));
synchronized (reconciler2) {
reconciler2.start();
reconciler2.wait();
+ assertNull(reconciler2.fAST);
+ assertTrue(cache.isActiveElement(fTU2));
+ assertTrue(cache.isReconciling(fTU2));
}
+ reconciler2.fStopped= true;
ast= cache.getAST(fTU2, fIndex, true, null);
assertNotNull(ast);
+ assertTrue(cache.isActiveElement(fTU2));
+ assertFalse(cache.isReconciling(fTU2));
assertSame(ast, reconciler2.fAST);
} finally {
reconciler1.fStopped= true;
reconciler1.join(1000);
- if (reconciler2 != null) {
- reconciler2.fStopped= true;
- reconciler2.join(1000);
- }
+ reconciler2.fStopped= true;
+ reconciler2.join(1000);
}
}
@@ -192,37 +208,44 @@ public class ASTCacheTests extends BaseTestCase {
MockReconciler reconciler1= new MockReconciler(fTU1, cache);
MockReconciler reconciler2= new MockReconciler(fTU2, cache);
reconciler1.start();
- Thread.sleep(100);
+ Thread.sleep(50);
reconciler2.start();
try {
- for (int i= 0; i < 10; i++) {
+ int cacheHits= 0;
+ int iterations= 0;
+ while (cacheHits < 4 && iterations < 10) {
+ ++iterations;
IASTTranslationUnit ast;
cache.setActiveElement(fTU1);
+ Thread.sleep(100);
ast= cache.getAST(fTU1, fIndex, false, null);
if (ast != null) {
assertSame(ast, reconciler1.fAST);
+ ++cacheHits;
+ } else {
+ ast= cache.getAST(fTU1, fIndex, true, null);
+ assertNotNull(ast);
+ assertEquals("void foo1() {}", ast.getDeclarations()[0].getRawSignature());
}
- ast= cache.getAST(fTU1, fIndex, true, null);
- assertNotNull(ast);
- assertEquals("void foo1() {}", ast.getDeclarations()[0].getRawSignature());
-
+
// change active element
cache.setActiveElement(fTU2);
+ Thread.sleep(100);
ast= cache.getAST(fTU1, fIndex, false, null);
if (ast != null) {
assertSame(ast, reconciler2.fAST);
+ ++cacheHits;
+ } else {
+ ast= cache.getAST(fTU2, fIndex, true, null);
+ assertNotNull(ast);
+ assertEquals("void foo2() {}", ast.getDeclarations()[0].getRawSignature());
}
- ast= cache.getAST(fTU2, fIndex, true, null);
- assertNotNull(ast);
- assertEquals("void foo2() {}", ast.getDeclarations()[0].getRawSignature());
}
} finally {
reconciler1.fStopped= true;
reconciler1.join(1000);
- if (reconciler2 != null) {
- reconciler2.fStopped= true;
- reconciler2.join(1000);
- }
+ reconciler2.fStopped= true;
+ reconciler2.join(1000);
}
}
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java
index b66d0214bf0..f50e9b9b7b1 100644
--- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java
@@ -13,7 +13,6 @@ import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
-import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -70,7 +69,7 @@ public class ASTCache {
*/
private long fLastWriteOnIndex;
/** Inidicates whether the AST is currenty being computed */
- private volatile boolean fIsReconciling;
+ private boolean fIsReconciling;
/**
* Create a new AST cache.
@@ -133,7 +132,7 @@ public class ASTCache {
if (DEBUG)
System.out.println(DEBUG_PREFIX + getThreadName() + "waiting for AST for: " + tUnit.getElementName()); //$NON-NLS-1$
fCacheMutex.wait();
- // Check whether active element is still valid (
+ // Check whether active element is still valid
if (fAST != null) {
if (DEBUG)
System.out.println(DEBUG_PREFIX + getThreadName() + "...got AST for: " + tUnit.getElementName()); //$NON-NLS-1$
@@ -219,25 +218,24 @@ public class ASTCache {
* @param tUnit the translation unit
*/
private void cache(IASTTranslationUnit ast, ITranslationUnit tUnit) {
- synchronized (fCacheMutex) {
- if (fActiveTU != null && !fActiveTU.equals(tUnit)) {
- if (DEBUG && tUnit != null) // don't report call from disposeAST()
- System.out.println(DEBUG_PREFIX + getThreadName() + "don't cache AST for inactive: " + toString(tUnit)); //$NON-NLS-1$
- return;
- }
-
- if (DEBUG && (tUnit != null || ast != null)) // don't report call from disposeAST()
- System.out.println(DEBUG_PREFIX + getThreadName() + "caching AST: " + toString(ast) + " for: " + toString(tUnit)); //$NON-NLS-1$ //$NON-NLS-2$
-
- if (fAST != null)
- disposeAST();
-
- fAST= ast;
- fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess();
-
- // Signal AST change
- fCacheMutex.notifyAll();
+ assert Thread.holdsLock(fCacheMutex);
+ if (fActiveTU != null && !fActiveTU.equals(tUnit)) {
+ if (DEBUG && tUnit != null) // don't report call from disposeAST()
+ System.out.println(DEBUG_PREFIX + getThreadName() + "don't cache AST for inactive: " + toString(tUnit)); //$NON-NLS-1$
+ return;
}
+
+ if (DEBUG && (tUnit != null || ast != null)) // don't report call from disposeAST()
+ System.out.println(DEBUG_PREFIX + getThreadName() + "caching AST: " + toString(ast) + " for: " + toString(tUnit)); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (fAST != null)
+ disposeAST();
+
+ fAST= ast;
+ fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess();
+
+ // Signal AST change
+ fCacheMutex.notifyAll();
}
/**
@@ -259,10 +257,10 @@ public class ASTCache {
/**
* Creates a new translation unit AST.
*
- * @param tUnit the C element for which to create the AST
- * @param index for AST generation, needs to be read-locked.
- * @param progressMonitor the progress monitor
- * @return AST
+ * @param tUnit the translation unit for which to create the AST
+ * @param index the index for AST generation, needs to be read-locked.
+ * @param progressMonitor a progress monitor, may be null
+ * @return an AST for the translation unit, or null
if the operation was cancelled
*/
public IASTTranslationUnit createAST(final ITranslationUnit tUnit, final IIndex index, final IProgressMonitor progressMonitor) {
if (progressMonitor != null && progressMonitor.isCanceled())
@@ -294,14 +292,14 @@ public class ASTCache {
/**
* Set the given translation unit as active element to cache an AST for.
*
- * @param tUnit
+ * @param tUnit the translation unit
*/
public void setActiveElement(ITranslationUnit tUnit) {
if (tUnit == fActiveTU) {
return;
}
- fIsReconciling= false;
synchronized (fCacheMutex) {
+ fIsReconciling= false;
fActiveTU= tUnit;
cache(null, tUnit);
}
@@ -312,7 +310,7 @@ public class ASTCache {
/**
* Check whether the given translation unit is the active element of this cache.
*
- * @param tUnit
+ * @param tUnit the translation unit
* @return true
, if this cache manages the given translation unit
*/
public boolean isActiveElement(ITranslationUnit tUnit) {
@@ -325,43 +323,42 @@ public class ASTCache {
* Informs that reconciling (computation of the AST) for the given element
* is about to be started.
*
- * @param tUnit the C element
- * @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
+ * @param tUnit the translation unit
*/
public void aboutToBeReconciled(ITranslationUnit tUnit) {
if (tUnit == null)
return;
- if (fActiveTU == null || !fActiveTU.equals(tUnit)) {
- return;
+
+ synchronized (fCacheMutex) {
+ if (fActiveTU == null || !fActiveTU.equals(tUnit)) {
+ return;
+ }
+
+ if (DEBUG)
+ System.out.println(DEBUG_PREFIX + getThreadName() + "about to reconcile: " + toString(tUnit)); //$NON-NLS-1$
+
+ fIsReconciling= true;
+ cache(null, tUnit);
}
-
- if (DEBUG)
- System.out.println(DEBUG_PREFIX + getThreadName() + "about to reconcile: " + toString(tUnit)); //$NON-NLS-1$
-
- fIsReconciling= true;
- cache(null, tUnit);
}
/**
* Informs that reconciling of the AST of the given translation unit has finished.
*
- * @param ast
- * @param tUnit
+ * @param ast the translation unit AST
+ * @param tUnit the translation unit
*/
public void reconciled(IASTTranslationUnit ast, ITranslationUnit tUnit) {
synchronized (fCacheMutex) {
+ if (tUnit == null || !tUnit.equals(fActiveTU)) {
+ if (DEBUG)
+ System.out.println(DEBUG_PREFIX + getThreadName() + "ignoring AST of out-dated element"); //$NON-NLS-1$
+ return;
+ }
if (DEBUG)
System.out.println(DEBUG_PREFIX + getThreadName() + "reconciled: " + toString(tUnit) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$
fIsReconciling= false;
- if (tUnit == null || !tUnit.equals(fActiveTU)) {
- if (DEBUG)
- System.out.println(DEBUG_PREFIX + getThreadName() + " ignoring AST of out-dated element"); //$NON-NLS-1$
-
- // Signal - threads might wait for wrong element
- fCacheMutex.notifyAll();
- return;
- }
cache(ast, tUnit);
}
}
@@ -370,7 +367,7 @@ public class ASTCache {
* Tells whether the given C element is the one
* reported as currently being reconciled.
*
- * @param tUnit the C element
+ * @param tUnit the translation unit
* @return true
if reported as currently being reconciled
*/
public boolean isReconciling(ITranslationUnit tUnit) {
@@ -393,21 +390,21 @@ public class ASTCache {
/**
* Returns a string for the given C element used for debugging.
*
- * @param cElement the translation unit AST
+ * @param tUnit the translation unit
* @return a string used for debugging
*/
- private static String toString(ICElement cElement) {
- if (cElement == null)
+ private static String toString(ITranslationUnit tUnit) {
+ if (tUnit == null)
return "null"; //$NON-NLS-1$
else
- return cElement.getElementName();
+ return tUnit.getElementName();
}
/**
* Returns a string for the given AST used for debugging.
*
- * @param ast the translation unit AST
+ * @param ast the translation unit AST
* @return a string used for debugging
*/
private static String toString(IASTTranslationUnit ast) {