How to avoid a race condition when a file is being opened in the Editor (Intellij)

Answered

Hi,

I am trying to solve what appears to be a race condition where FileEditorManagerOpenFileListener#fileOpened is called, the listener closes the file that was just opened using FileEditorManager#closeFile, which results in an exception com.intellij.openapi.util.TraceableDisposable$DisposalException: Editor is already disposed

Background:  I am writing a plugin that will allow students to use intellij as a test platform for programming tests.  The plugin monitors for disallowed files being opened during the test (using the above listener).  When a disallowed file is opened, the file is closed by the listener and the student is notified.

Occasionally, the following exception results when the file is closed:

2024-11-21 15:41:32,283 [  59227] SEVERE - #c.i.i.p.PluginManager - Editor is already disposed
com.intellij.openapi.util.TraceableDisposable$DisposalException: Editor is already disposed
	at com.intellij.openapi.util.TraceableDisposable.throwDisposalError(TraceableDisposable.java:44)
	at com.intellij.openapi.editor.impl.EditorImpl.throwDisposalError(EditorImpl.java:1020)
	at com.intellij.openapi.editor.impl.view.LogicalPositionCache.checkDisposed(LogicalPositionCache.java:193)
	at com.intellij.openapi.editor.impl.view.LogicalPositionCache.getLineInfo(LogicalPositionCache.java:178)
	at com.intellij.openapi.editor.impl.view.LogicalPositionCache.offsetToLogicalPosition(LogicalPositionCache.java:90)
	at com.intellij.openapi.editor.impl.view.EditorCoordinateMapper.offsetToLogicalPosition(EditorCoordinateMapper.java:91)
	at com.intellij.openapi.editor.impl.view.EditorView.offsetToLogicalPosition(EditorView.java:172)
	at com.intellij.openapi.editor.impl.EditorImpl.lambda$offsetToLogicalPosition$21(EditorImpl.java:1494)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:923)
	at com.intellij.openapi.application.ReadAction.compute(ReadAction.java:76)
	at com.intellij.openapi.editor.impl.EditorImpl.offsetToLogicalPosition(EditorImpl.java:1494)
	at com.intellij.openapi.editor.impl.CaretImpl.lambda$moveToOffset$0(CaretImpl.java:106)
	at com.intellij.openapi.editor.impl.CaretModelImpl.doWithCaretMerging(CaretModelImpl.java:419)
	at com.intellij.openapi.editor.impl.CaretImpl.moveToOffset(CaretImpl.java:105)
	at com.intellij.openapi.editor.CaretModel.moveToOffset(CaretModel.java:91)
	at com.intellij.openapi.editor.CaretModel.moveToOffset(CaretModel.java:77)
	at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigateInEditor(OpenFileDescriptor.java:114)
	at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigateIn(OpenFileDescriptor.java:97)
	at com.intellij.openapi.fileEditor.impl.text.TextEditorImpl.navigateTo(TextEditorImpl.kt:173)
	at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.navigateAndSelectEditor(FileEditorManagerImpl.kt:1321)
	at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openEditorImpl(FileEditorManagerImpl.kt:1310)
	at com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl.openFileEditor(FileEditorManagerImpl.kt:1258)
	at com.intellij.openapi.fileEditor.FileNavigatorImplKt.navigateInAnyFileEditor(FileNavigatorImpl.kt:109)
	at com.intellij.openapi.fileEditor.FileNavigatorImplKt.access$navigateInAnyFileEditor(FileNavigatorImpl.kt:1)
	at com.intellij.openapi.fileEditor.FileNavigatorImpl.navigateInEditor(FileNavigatorImpl.kt:57)
	at com.intellij.openapi.fileEditor.FileNavigatorImpl.navigateInEditorOrNativeApp(FileNavigatorImpl.kt:52)
	at com.intellij.openapi.fileEditor.FileNavigatorImpl.navigate(FileNavigatorImpl.kt:32)
	at com.intellij.openapi.fileEditor.OpenFileDescriptor.navigate(OpenFileDescriptor.java:88)
	at com.intellij.platform.ide.navigation.impl.IdeNavigationServiceKt$navigateToSource$4$1.invoke(IdeNavigationService.kt:171)
	at com.intellij.platform.ide.navigation.impl.IdeNavigationServiceKt$navigateToSource$4$1.invoke(IdeNavigationService.kt:170)
	at com.intellij.openapi.progress.CoroutinesKt.blockingContext(coroutines.kt:248)
	at com.intellij.openapi.progress.CoroutinesKt.blockingContext(coroutines.kt:199)
	at com.intellij.platform.ide.navigation.impl.IdeNavigationServiceKt$navigateToSource$4.invokeSuspend(IdeNavigationService.kt:170)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at com.intellij.openapi.application.impl.DispatchedRunnable.run(DispatchedRunnable.kt:43)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:208)
	at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:190)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:861)
	at com.intellij.openapi.application.impl.ApplicationImpl$4.run(ApplicationImpl.java:478)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:79)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:121)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:41)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:761)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:690)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$10(IdeEventQueue.kt:593)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWithoutImplicitRead(ApplicationImpl.java:1485)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:593)
	at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:67)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:369)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:368)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:787)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:368)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:363)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:997)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:113)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:997)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:363)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:861)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:405)
	at com.intellij.openapi.progress.impl.PlatformTaskSupportKt.pumpEventsForHierarchy(PlatformTaskSupport.kt:379)
	at com.intellij.openapi.progress.impl.PlatformTaskSupportKt.access$pumpEventsForHierarchy(PlatformTaskSupport.kt:1)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport$runWithModalProgressBlockingInternal$2.invoke(PlatformTaskSupport.kt:157)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport$runWithModalProgressBlockingInternal$2.invoke(PlatformTaskSupport.kt:135)
	at com.intellij.openapi.application.impl.ModalityKt.inModalContext(modality.kt:12)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport.runWithModalProgressBlockingInternal(PlatformTaskSupport.kt:135)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport.access$runWithModalProgressBlockingInternal(PlatformTaskSupport.kt:41)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport$runWithModalProgressBlockingInternal$1.invoke(PlatformTaskSupport.kt:123)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport$runWithModalProgressBlockingInternal$1.invoke(PlatformTaskSupport.kt:119)
	at com.intellij.openapi.progress.ContextKt.prepareThreadContext(context.kt:94)
	at com.intellij.openapi.progress.impl.PlatformTaskSupport.runWithModalProgressBlockingInternal(PlatformTaskSupport.kt:119)
	at com.intellij.openapi.progress.TasksKt.runWithModalProgressBlocking(tasks.kt:167)
	at com.intellij.openapi.progress.TasksKt.runWithModalProgressBlocking(tasks.kt:99)
	at com.intellij.util.OpenSourceUtilKt.openSourcesFrom(OpenSourceUtil.kt:24)
	at com.intellij.util.OpenSourceUtil.openSourcesFrom(OpenSourceUtil.java:22)
	at com.intellij.util.EditSourceOnDoubleClickHandler$TreeMouseListener.processDoubleClick(EditSourceOnDoubleClickHandler.kt:188)
	at com.intellij.util.EditSourceOnDoubleClickHandler$TreeMouseListener.onDoubleClick(EditSourceOnDoubleClickHandler.kt:176)
	at com.intellij.ui.DoubleClickListener.onClick(DoubleClickListener.java:30)
	at com.intellij.ui.ClickListener$1.mouseReleased(ClickListener.java:58)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:298)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
	at java.desktop/java.awt.Component.processMouseEvent(Component.java:6657)
	at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3385)
	at com.intellij.ui.treeStructure.Tree.processMouseEvent(Tree.java:437)

Diagnosis (guess):  I suspect that there is a race condition between my listener and another thread which calls FileEditorManagerListener#fileOpenedSync(FileEditorManager, VirtualFile, List).   Essentially, my listener closes the file while the other thread is still working on it.

Question 1: Is this the problem or is it another problem?

Question 2: If this is the problem, how can I avoid the race condition?  I.e., perhaps by waiting until the other thread completes before the window is closed?

Thank you for your time.

Sincerely,
Alex

0
2 comments

Hi,

Try scheduling closing files with com.intellij.openapi.fileEditor.FileEditorManager#runWhenLoaded.

0

Hi Karol,

Thanks!  That seemed to fix the problem.   I did need to wrap the  call to FileEditorManager#closeFile with a ApplicationManager#invokeLater to make it work.

Thanks for your help!

Sincerely,
Alex

0

Please sign in to leave a comment.