IJPL-149317 More explicit locks.

GitOrigin-RevId: 95f64ac7da5066d2efb212d4e7cfc2cb98543ac1
This commit is contained in:
Lev Serebryakov
2024-09-08 21:54:24 +02:00
committed by intellij-monorepo-bot
parent 0f67676709
commit 0b6ba6a94d
12 changed files with 72 additions and 131 deletions

View File

@@ -11,6 +11,7 @@ import com.intellij.collaboration.ui.util.DimensionRestrictions
import com.intellij.collaboration.util.HashingUtil
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.editor.*
@@ -85,7 +86,9 @@ private suspend fun <VM : EditorMapped> EditorEx.doRenderInlays(
vmsFlow.map {
createCustomHashingStrategySet(vmHashingStrategy).apply { addAll(it) }
}.collect {
positionKeeper.savePosition()
writeIntentReadAction {
positionKeeper.savePosition()
}
// remove missing
val iter = controllersByVmKey.iterator()
@@ -105,10 +108,12 @@ private suspend fun <VM : EditorMapped> EditorEx.doRenderInlays(
}
}
// immediately validate the editor to recalculate the size with inlays
editor.contentComponent.validate()
positionKeeper.restorePosition(true)
editor.contentComponent.repaint()
writeIntentReadAction {
// immediately validate the editor to recalculate the size with inlays
editor.contentComponent.validate()
positionKeeper.restorePosition(true)
editor.contentComponent.repaint()
}
}
awaitCancellation()
}
@@ -128,19 +133,21 @@ private suspend fun <VM : EditorMapped> controlInlay(vm: VM, editor: EditorEx, r
combine(lineFlow, visibleFlow, ::Pair)
}.distinctUntilChanged()
.collect { (line, isVisible) ->
val currentInlay = inlay
if (line != null && isVisible) {
runCatching {
val offset = editor.document.getLineEndOffset(line)
if (currentInlay == null || !currentInlay.isValid || currentInlay.offset != offset) {
currentInlay?.let(Disposer::dispose)
inlay = insertComponent(vm, rendererFactory, editor, offset)
}
}.getOrLogException(LOG)
}
else if (currentInlay != null) {
Disposer.dispose(currentInlay)
inlay = null
writeIntentReadAction {
val currentInlay = inlay
if (line != null && isVisible) {
runCatching {
val offset = editor.document.getLineEndOffset(line)
if (currentInlay == null || !currentInlay.isValid || currentInlay.offset != offset) {
currentInlay?.let(Disposer::dispose)
inlay = insertComponent(vm, rendererFactory, editor, offset)
}
}.getOrLogException(LOG)
}
else if (currentInlay != null) {
Disposer.dispose(currentInlay)
inlay = null
}
}
}
awaitCancellation()

View File

@@ -6244,8 +6244,6 @@ f:com.intellij.util.concurrency.ThreadingAssertions
- s:assertReadAccess():V
- s:assertWriteAccess():V
- s:assertWriteIntentReadAccess():V
- s:isImplicitLockOnEDT():Z
- s:setImplicitLockOnEDT(Z):V
- s:softAssertBackgroundThread():V
- s:softAssertEventDispatchThread():V
- s:softAssertReadAccess():V

View File

@@ -32,16 +32,12 @@ public final class ThreadingAssertions {
@VisibleForTesting
public static final String MUST_EXECUTE_IN_READ_ACTION =
"Read access is allowed from inside read-action only (see Application.runReadAction())";
private static final String MUST_EXECUTE_IN_READ_ACTION_EXPLICIT =
"Read access is allowed from inside explicit read-action only (see Application.runReadAction()). Now implicit WriteIntentReadAction.run() is used.";
@Internal
@VisibleForTesting
public static final String MUST_NOT_EXECUTE_IN_READ_ACTION =
"Must not execute inside read action";
private static final String MUST_EXECUTE_IN_WRITE_INTENT_READ_ACTION =
"Access is allowed from write thread only";
private static final String MUST_EXECUTE_IN_WRITE_INTENT_READ_ACTION_EXPLICIT =
"Access is allowed from write thread only with explicit WriteIntentReadAction.run(). Now implicit WriteIntentReadAction.run() is used.";
@Internal
@VisibleForTesting
public static final String MUST_EXECUTE_IN_WRITE_ACTION =
@@ -57,8 +53,6 @@ public final class ThreadingAssertions {
private static final String DOCUMENTATION_URL = "https://jb.gg/ij-platform-threading";
private static boolean implicitLock = false;
/**
* Asserts that the current thread is the event dispatch thread.
*
@@ -117,17 +111,6 @@ public final class ThreadingAssertions {
if (!ApplicationManager.getApplication().isReadAccessAllowed()) {
throwThreadAccessException(MUST_EXECUTE_IN_READ_ACTION);
}
else if (isImplicitLockOnEDT()) {
reportImplicitRead();
}
}
/**
* Reports message about implicit read to logger at error level
*/
@Internal
public static void reportImplicitRead() {
getLogger().error(createThreadAccessException(MUST_EXECUTE_IN_READ_ACTION_EXPLICIT));
}
/**
@@ -165,17 +148,6 @@ public final class ThreadingAssertions {
if (!ApplicationManager.getApplication().isWriteIntentLockAcquired()) {
throwWriteIntentReadAccess();
}
else if (isImplicitLockOnEDT()) {
reportImplicitWriteIntent();
}
}
/**
* Reports message about implicit read to logger at error level
*/
@Internal
public static void reportImplicitWriteIntent() {
getLogger().error(createThreadAccessException(MUST_EXECUTE_IN_WRITE_INTENT_READ_ACTION_EXPLICIT));
}
/**
@@ -216,16 +188,4 @@ public final class ThreadingAssertions {
private static @NotNull String describe(@Nullable Thread o) {
return o == null ? "null" : o + " " + System.identityHashCode(o);
}
public static boolean isImplicitLockOnEDT() {
if (!EDT.isCurrentThreadEdt())
return false;
return implicitLock;
}
public static void setImplicitLockOnEDT(boolean implicitLock) {
if (!EDT.isCurrentThreadEdt())
return;
ThreadingAssertions.implicitLock = implicitLock;
}
}

View File

@@ -526,7 +526,9 @@ class InlineCompletionHandler(
@RequiresEdt
private fun traceBlocking(event: InlineCompletionEventType) {
ThreadingAssertions.assertEventDispatchThread()
eventListeners.getMulticaster().on(event)
WriteIntentReadAction.run {
eventListeners.getMulticaster().on(event)
}
}
@RequiresEdt

View File

@@ -1041,14 +1041,7 @@ internal fun performActivity(e: AWTEvent, needWIL: Boolean, runnable: () -> Unit
else {
val runnableWithWIL =
if (needWIL) {
{
ThreadingAssertions.setImplicitLockOnEDT(true)
try {
WriteIntentReadAction.run(runnable)
} finally {
ThreadingAssertions.setImplicitLockOnEDT(false)
}
}
{ WriteIntentReadAction.run(runnable) }
}
else {
runnable

View File

@@ -81,13 +81,10 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
is WriteIntentPermit, is WritePermit -> release = false
}
val prevImplicitLock = ThreadingAssertions.isImplicitLockOnEDT()
try {
ThreadingAssertions.setImplicitLockOnEDT(false)
return computation.compute()
}
finally {
ThreadingAssertions.setImplicitLockOnEDT(prevImplicitLock)
if (release) {
ts.release()
}
@@ -109,21 +106,10 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
override fun isWriteIntentLocked(): Boolean {
val ts = myState.get()
// check for implicit
if (ts.hasWriteIntent && ThreadingAssertions.isImplicitLockOnEDT()) {
ThreadingAssertions.reportImplicitWriteIntent()
}
return ts.hasWrite || ts.hasWriteIntent
}
override fun isReadAccessAllowed(): Boolean {
val ts = myState.get()
// check for implicit
if (ts.hasWriteIntent && ThreadingAssertions.isImplicitLockOnEDT()) {
ThreadingAssertions.reportImplicitRead()
}
return ts.hasPermit
}
override fun isReadAccessAllowed(): Boolean = myState.get().hasPermit
override fun executeOnPooledThread(action: Runnable, expired: BooleanSupplier): Future<*> {
val actionDecorated = decorateRunnable(action)
@@ -235,17 +221,10 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
fireBeforeReadActionStart(clazz)
val ts = myState.get()
if (ts.hasPermit) {
val prevImplicitLock = ThreadingAssertions.isImplicitLockOnEDT()
ThreadingAssertions.setImplicitLockOnEDT(false)
try {
fireReadActionStarted(clazz)
val rv = block.compute()
fireReadActionFinished(clazz)
return rv
}
finally {
ThreadingAssertions.setImplicitLockOnEDT(prevImplicitLock)
}
fireReadActionStarted(clazz)
val rv = block.compute()
fireReadActionFinished(clazz)
return rv
}
else {
ts.permit = tryGetReadPermit()
@@ -277,8 +256,6 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
} while (ts.permit == null)
}
}
val prevImplicitLock = ThreadingAssertions.isImplicitLockOnEDT()
ThreadingAssertions.setImplicitLockOnEDT(false)
try {
fireReadActionStarted(clazz)
val rv = block.compute()
@@ -286,7 +263,6 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
return rv
}
finally {
ThreadingAssertions.setImplicitLockOnEDT(prevImplicitLock)
ts.release()
fireAfterReadActionFinished(clazz)
}
@@ -296,16 +272,9 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
override fun tryRunReadAction(action: Runnable): Boolean {
val ts = myState.get()
if (ts.hasPermit) {
val prevImplicitLock = ThreadingAssertions.isImplicitLockOnEDT()
ThreadingAssertions.setImplicitLockOnEDT(false)
try {
fireReadActionStarted(action.javaClass)
action.run()
fireReadActionFinished(action.javaClass)
}
finally {
ThreadingAssertions.setImplicitLockOnEDT(prevImplicitLock)
}
fireReadActionStarted(action.javaClass)
action.run()
fireReadActionFinished(action.javaClass)
return true
}
else {
@@ -314,8 +283,6 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
if (!ts.hasPermit) {
return false
}
val prevImplicitLock = ThreadingAssertions.isImplicitLockOnEDT()
ThreadingAssertions.setImplicitLockOnEDT(false)
try {
fireReadActionStarted(action.javaClass)
action.run()
@@ -323,7 +290,6 @@ internal object AnyThreadWriteThreadingSupport: ThreadingSupport {
return true
}
finally {
ThreadingAssertions.setImplicitLockOnEDT(prevImplicitLock)
ts.release()
fireAfterReadActionFinished(action.javaClass)
}

View File

@@ -3733,7 +3733,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
mouseSelectionStateAlarm.cancel();
if (myMouseSelectionState != MOUSE_SELECTION_STATE_NONE) {
if (mouseSelectionStateResetRunnable == null) {
mouseSelectionStateResetRunnable = () -> resetMouseSelectionState(null, null);
mouseSelectionStateResetRunnable = () -> WriteIntentReadAction.run((Runnable)() -> resetMouseSelectionState(null, null));
}
mouseSelectionStateAlarm.request(Registry.intValue("editor.mouseSelectionStateResetTimeout"),
ModalityState.stateForComponent(myEditorComponent),

View File

@@ -2,6 +2,7 @@
package com.intellij.testFramework.junit5.showcase
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.testFramework.junit5.TestApplication
import com.intellij.testFramework.junit5.fixture.*
import kotlinx.coroutines.Dispatchers
@@ -32,8 +33,10 @@ class JUnit5EditorFixtureTest {
fun `caret position in editors`() {
runBlocking {
withContext(Dispatchers.EDT) {
localEditor.get().caretModel.moveToOffset(2)
Assertions.assertEquals(2, localEditor.get().caretModel.offset)
writeIntentReadAction {
localEditor.get().caretModel.moveToOffset(2)
Assertions.assertEquals(2, localEditor.get().caretModel.offset)
}
}
}
}
@@ -42,8 +45,10 @@ class JUnit5EditorFixtureTest {
fun `selection in editors`() {
runBlocking {
withContext(Dispatchers.EDT) {
localEditor.get().selectionModel.setSelection(1, 3)
Assertions.assertEquals("bc", localEditor.get().selectionModel.selectedText)
writeIntentReadAction {
localEditor.get().selectionModel.setSelection(1, 3)
Assertions.assertEquals("bc", localEditor.get().selectionModel.selectedText)
}
}
}
}

View File

@@ -85,7 +85,9 @@ class InlineCompletionLifecycleTestDSL(val fixture: CodeInsightTestFixture) {
withContext(Dispatchers.EDT) {
val lookup = fixture.lookup as? LookupImpl
assertThat(lookup).isNotNull()
lookup!!.hideLookup(false)
writeIntentReadAction {
lookup!!.hideLookup(false)
}
}
}

View File

@@ -6,6 +6,7 @@ import com.intellij.coverage.CoverageIntegrationBaseTest
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.editor.colors.CodeInsightColors
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.editor.markup.FillingLineMarkerRenderer
@@ -187,7 +188,9 @@ internal suspend fun findEditor(project: Project, className: String): EditorImpl
internal suspend fun closeEditor(project: Project, className: String) {
val psiClass = getPsiClass(project, className)
withContext(Dispatchers.EDT) {
FileEditorManager.getInstance(project).closeFile(psiClass.containingFile.virtualFile)
writeIntentReadAction {
FileEditorManager.getInstance(project).closeFile(psiClass.containingFile.virtualFile)
}
}
}

View File

@@ -90,21 +90,23 @@ abstract class AbstractGradleMultiFileQuickFixTest : MultiplePluginVersionGradle
refreshRecursively(projectVFile)
withContext(Dispatchers.EDT) {
PlatformTestUtil.assertDirectoriesEqual(
expected,
projectVFile,
fun(vFile: VirtualFile): Boolean {
if (vFile.parent == projectVFile) {
when (vFile.name) {
".gradle", "gradle", "build", "gradle.properties", "gradlew", "gradlew.bat", ".kotlin" -> return false
writeIntentReadAction {
PlatformTestUtil.assertDirectoriesEqual(
expected,
projectVFile,
fun(vFile: VirtualFile): Boolean {
if (vFile.parent == projectVFile) {
when (vFile.name) {
".gradle", "gradle", "build", "gradle.properties", "gradlew", "gradlew.bat", ".kotlin" -> return false
}
}
}
if (ignoreChangesInBuildScriptFiles && ".gradle" in vFile.name) return false
if (ignoreChangesInBuildScriptFiles && ".gradle" in vFile.name) return false
return additionalResultFileFilter(vFile)
},
)
return additionalResultFileFilter(vFile)
},
)
}
}
}

View File

@@ -3,6 +3,7 @@ package com.intellij.pycharm.community.ide.impl.newProject.impl.emptyProject
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.vfs.VirtualFile
@@ -19,7 +20,9 @@ class PyV3EmptyProjectSettings(var generateWelcomeScript: Boolean = false) : PyV
PyWelcome.prepareFile(module.project, baseDir)
}
withContext(Dispatchers.EDT) {
file.navigate(true)
writeIntentReadAction {
file.navigate(true)
}
}
}