Community
Participate
Working Groups
Build 20020416 While running a benchmark, we encountered a deadlock between a refresh of the ProblemTreeViewer (presumably for the packages view) and the reconciler. We have not seen this occur in regular use, just when running the benchmark. The benchmark does the following: - open workbench - close all open editors - create 100 .java files (opening them in editors) - exit - repeat Note that the files are never deleted, so the packages view will get larger and larger. It consistently deadlocks early on the 21st iteration on Windows (around 2000 files), and at a different iteration on Linux. There were 3 threads blocked, 2 of which were deadlocked. The 3rd was waiting for one of the locks, but was not involved in the deadlocked. Here are the threads, annotated with where the locks are obtained (see ***). Read them bottom up. Note that the first two threads involve the same WorkingCopy. The third thread is for a different WorkingCopy. Note that it looks like the Java model cache is trying to remove a WorkingCopy which is still being used by the reconciler. This may be another problem. Thread [main] (Suspended) (*** attempt to obtain lock on WorkingCopy, id=93) org.eclipse.jdt.internal.core.ElementCache.close (org.eclipse.jdt.internal.core.util.LRUCache$LRUCacheEntry) line: 38 org.eclipse.jdt.internal.core.ElementCache (org.eclipse.jdt.internal.core.OverflowingLRUCache).privateRemoveEntry (org.eclipse.jdt.internal.core.util.LRUCache$LRUCacheEntry, boolean, boolean) line: 278 org.eclipse.jdt.internal.core.ElementCache (org.eclipse.jdt.internal.core.OverflowingLRUCache).makeSpace(int) line: 169 org.eclipse.jdt.internal.core.ElementCache (org.eclipse.jdt.internal.core.OverflowingLRUCache).put(java.lang.Object, java.lang.Object) line: 345 org.eclipse.jdt.internal.core.JavaModelCache.putInfo (org.eclipse.jdt.core.IJavaElement, java.lang.Object) line: 136 org.eclipse.jdt.internal.core.JavaModelManager.putInfo (org.eclipse.jdt.core.IJavaElement, java.lang.Object) line: 948 org.eclipse.jdt.internal.core.CompilationUnit.generateInfos (org.eclipse.jdt.internal.core.OpenableElementInfo, org.eclipse.core.runtime.IProgressMonitor, java.util.Map, org.eclipse.core.resources.IResource) line: 295 org.eclipse.jdt.internal.core.CompilationUnit.buildStructure (org.eclipse.jdt.internal.core.OpenableElementInfo, org.eclipse.core.runtime.IProgressMonitor) line: 68 org.eclipse.jdt.internal.core.CompilationUnit (org.eclipse.jdt.internal.core.Openable).openWhenClosed (org.eclipse.core.runtime.IProgressMonitor, org.eclipse.jdt.core.IBuffer) line: 394 org.eclipse.jdt.internal.core.CompilationUnit (org.eclipse.jdt.internal.core.JavaElement).openHierarchy() line: 497 (*** lock obtained on JavaModelManager) org.eclipse.jdt.internal.core.CompilationUnit (org.eclipse.jdt.internal.core.JavaElement).getElementInfo() line: 287 org.eclipse.jdt.internal.core.CompilationUnit.getSourceRange() line: 512 org.eclipse.jdt.internal.ui.viewsupport.ErrorTickAdornmentProvider.comp uteAdornmentFlags(java.lang.Object) line: 60 org.eclipse.jdt.internal.ui.viewsupport.StandardJavaUILabelProvider (org.eclipse.jdt.internal.ui.viewsupport.JavaUILabelProvider).getImage (java.lang.Object) line: 82 org.eclipse.jface.viewers.DecoratingLabelProvider.getImage (java.lang.Object) line: 65 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.StructuredViewer).getLabel(java.lang.Object, org.eclipse.jface.viewers.ILabelProvider) line: 1089 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.TreeViewer).doUpdateItem (org.eclipse.swt.widgets.Item, java.lang.Object) line: 88 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.AbstractTreeViewer).doUpdateItem (org.eclipse.swt.widgets.Widget, java.lang.Object, boolean) line: 352 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.StructuredViewer).updateItem (org.eclipse.swt.widgets.Widget, java.lang.Object) line: 1044 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.AbstractTreeViewer).internalRefresh (org.eclipse.swt.widgets.Widget, java.lang.Object, boolean) line: 846 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.AbstractTreeViewer).internalRefresh (org.eclipse.swt.widgets.Widget, java.lang.Object, boolean) line: 860 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.AbstractTreeViewer).internalRefresh (java.lang.Object) line: 829 org.eclipse.jface.viewers.StructuredViewer$1.run() line: 676 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.StructuredViewer).preservingSelection (java.lang.Runnable) line: 616 org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer (org.eclipse.jface.viewers.StructuredViewer).refresh(java.lang.Object) line: 674 org.eclipse.jdt.ui.JavaElementContentProvider$2.run() line: 255 org.eclipse.swt.widgets.RunnableLock.run() line: 29 org.eclipse.ui.internal.UISynchronizer (org.eclipse.swt.widgets.Synchronizer).runAsyncMessages() line: 93 org.eclipse.swt.widgets.Display.runAsyncMessages() line: 1389 org.eclipse.swt.widgets.Display.readAndDispatch() line: 1211 org.eclipse.benchmarks.startupshutdown.BenchmarkWorkbench.clearEventLoo p() line: 77 org.eclipse.benchmarks.startupshutdown.BenchmarkWorkbench.create100Clas ses() line: 150 org.eclipse.benchmarks.startupshutdown.BenchmarkWorkbench.runProc(int) line: 116 org.eclipse.benchmarks.startupshutdown.BenchmarkWorkbench.runEventLoop () line: 62 org.eclipse.benchmarks.startupshutdown.BenchmarkWorkbench (org.eclipse.ui.internal.Workbench).run(java.lang.Object) line: 819 org.eclipse.core.internal.boot.InternalBootLoader.run (java.lang.String, java.net.URL, java.lang.String, java.lang.String[]) line: 777 org.eclipse.core.boot.BootLoader.run(java.lang.String, java.net.URL, java.lang.String, java.lang.String[]) line: 319 java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) line: not available [native method] org.eclipse.core.launcher.Main.basicRun(java.lang.String[]) line: 190 org.eclipse.core.launcher.Main.run(java.lang.String[]) line: 549 org.eclipse.core.launcher.Main.main(java.lang.String[]) line: 390 Thread [org.eclipse.jface.text.reconciler.MonoReconciler] (Suspended) (*** attempt to obtain lock on JavaModelManager) org.eclipse.jdt.internal.core.SourceType (org.eclipse.jdt.internal.core.JavaElement).getElementInfo() line: 284 org.eclipse.jdt.internal.core.JavaElementDeltaBuilder.recordNewPosition s(org.eclipse.jdt.core.IJavaElement, int) line: 395 org.eclipse.jdt.internal.core.JavaElementDeltaBuilder.recordNewPosition s(org.eclipse.jdt.core.IJavaElement, int) line: 404 org.eclipse.jdt.internal.core.JavaElementDeltaBuilder.buildDeltas() line: 125 org.eclipse.jdt.internal.core.WorkingCopy.reconcile() line: 333 (*** lock obtained on WorkingCopy id=93) org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile () line: 62 org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile (org.eclipse.jface.text.IRegion) line: 80 org.eclipse.jface.text.reconciler.MonoReconciler.process (org.eclipse.jface.text.reconciler.DirtyRegion) line: 66 org.eclipse.jface.text.reconciler.AbstractReconciler$BackgroundThread.r un() line: 153 Thread [org.eclipse.jface.text.reconciler.MonoReconciler] (Suspended) (*** attempt to obtain lock on JavaModelManager) org.eclipse.jdt.internal.core.WorkingCopy (org.eclipse.jdt.internal.core.JavaElement).getElementInfo() line: 284 org.eclipse.jdt.internal.core.JavaElementDeltaBuilder.recordNewPosition s(org.eclipse.jdt.core.IJavaElement, int) line: 395 org.eclipse.jdt.internal.core.JavaElementDeltaBuilder.buildDeltas() line: 125 org.eclipse.jdt.internal.core.WorkingCopy.reconcile() line: 333 (*** lock obtained on WorkingCopy id=150) org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile () line: 62 org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile (org.eclipse.jface.text.IRegion) line: 80 org.eclipse.jface.text.reconciler.MonoReconciler.process (org.eclipse.jface.text.reconciler.DirtyRegion) line: 66 org.eclipse.jface.text.reconciler.AbstractReconciler$BackgroundThread.r un() line: 153
One possible fix would be for JavaReconcilingStrategy.reconcile() to obtain a lock on the JavaModelManager before the lock on the working copy. If a lock on the JavaModelManager is always obtained first, there seems to be little need for locking on the working copy (although you'd still want to synchronize on the manager in the same places as currently done for the working copies). This solution may limit concurrency, but is probably the safest approach.
Problem should still be around. Why is the reconciling strategy taking a lock on the working copy ? Now, given this is a public object, we might want to avoid also synchronizing internally onto it...
There is no point for us locking on the working copy before flushing it, indeed the internal cache removal is done by Openable#close which is synchronized already on the model manager. Removing this unnecessary lock. Same pattern was found onto the BufferCache.
Fixed - will need JDT/UI to verify symptoms are gone