mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[threading] CPP-51261: Handle temporary release of write-intent lock during suspending write action
(cherry picked from commit 5241fb3698fd9caee14555e4bf5a9762f8aef058) (cherry picked from commit d8408b5a7d5e82b72d6cbf60d3aca07fcaa272d5) IJ-MR-219976 GitOrigin-RevId: 4cd9e91df336a1bc9809177ea1752da5b17397ee
This commit is contained in:
committed by
intellij-monorepo-bot
parent
e16aa85075
commit
0d5ce4a978
@@ -1336,6 +1336,10 @@ class NestedLocksThreadingSupport : ThreadingSupport {
|
||||
return object : AccessToken() {
|
||||
override fun finish() {
|
||||
myWriteActionPending.get()[state.level()].incrementAndGet()
|
||||
val newThisLevelPermit = state.getThisThreadPermit()
|
||||
require(newThisLevelPermit is ParallelizablePermit.WriteIntent) {
|
||||
"When suspending write action is finishing, the thread must hold write-intent lock"
|
||||
}
|
||||
val (newWritePermits, newWritePermit) = try {
|
||||
myWriteLockReacquisitionListener.zip(listOfReacquisitionData).forEachGuaranteed { (listener, data) ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -1343,7 +1347,7 @@ class NestedLocksThreadingSupport : ThreadingSupport {
|
||||
castedListener.beforeWriteLockReacquired(data)
|
||||
}
|
||||
val newWritePermit = runSuspendMaybeConsuming(false) {
|
||||
rootWriteIntentPermit.acquireWriteActionPermit()
|
||||
newThisLevelPermit.writeIntentPermit.acquireWriteActionPermit()
|
||||
}
|
||||
myWriteLockReacquisitionListener.zip(listOfReacquisitionData).forEachGuaranteed { (listener, data) ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -1361,7 +1365,7 @@ class NestedLocksThreadingSupport : ThreadingSupport {
|
||||
finally {
|
||||
myWriteActionPending.get()[state.level()].decrementAndGet()
|
||||
}
|
||||
hack_setPublishedPermitData(exposedPermitData.copy(writePermitStack = newWritePermits, finalWritePermit = newWritePermit))
|
||||
hack_setPublishedPermitData(exposedPermitData.copy(writePermitStack = newWritePermits, finalWritePermit = newWritePermit, originalWriteIntentPermit = newThisLevelPermit.writeIntentPermit, oldPermit = newThisLevelPermit.writeIntentPermit))
|
||||
myWriteAcquired = Thread.currentThread()
|
||||
myWriteStackBase = prevBase
|
||||
}
|
||||
|
||||
+25
@@ -2,6 +2,7 @@
|
||||
package com.intellij.openapi.application.impl
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.WriteActionListener
|
||||
import com.intellij.openapi.application.backgroundWriteAction
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
@@ -22,6 +23,7 @@ import com.intellij.openapi.util.use
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.ui.EDT
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -38,6 +40,8 @@ import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
private const val repetitions: Int = 100
|
||||
|
||||
@@ -230,4 +234,25 @@ class SuspendingWriteActionTest {
|
||||
}
|
||||
checkpoint(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `release of WI inside suspending write action does not lead to broken IDE state`(): Unit = timeoutRunBlocking {
|
||||
readAction { } // init internal structures
|
||||
edtWriteAction {
|
||||
assertTrue { application.isWriteAccessAllowed }
|
||||
ApplicationManagerEx.getApplicationEx().threadingSupport!!.executeSuspendingWriteAction {
|
||||
assertFalse { application.isWriteAccessAllowed }
|
||||
assertTrue { application.isWriteIntentLockAcquired }
|
||||
TestOnlyThreading.releaseTheAcquiredWriteIntentLockThenExecuteActionAndTakeWriteIntentLockBack {
|
||||
assertFalse { application.isWriteAccessAllowed }
|
||||
assertFalse { application.isWriteIntentLockAcquired }
|
||||
}
|
||||
assertFalse { application.isWriteAccessAllowed }
|
||||
assertTrue { application.isWriteIntentLockAcquired }
|
||||
}
|
||||
assertTrue { application.isWriteAccessAllowed }
|
||||
assertTrue { application.isWriteIntentLockAcquired }
|
||||
}
|
||||
withContext(Dispatchers.EDT) {} // check that WI can be acquired again
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user