[threading] RUBY-34356: Throw PCE if lock acquisition was promptly canceled in blocking context

GitOrigin-RevId: dd0b5331b316033255115dc3ba65785ca3f534ba
This commit is contained in:
Konstantin Nisht
2025-06-18 11:07:07 +00:00
committed by intellij-monorepo-bot
parent d0a4e16b0b
commit 881963a0a8
2 changed files with 43 additions and 2 deletions
@@ -8,6 +8,7 @@ import com.intellij.core.rwmutex.*
import com.intellij.openapi.application.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.Cancellation
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.text.StringUtil
import com.intellij.platform.locking.impl.listeners.ErrorHandler
import com.intellij.platform.locking.impl.listeners.LegacyProgressIndicatorProvider
@@ -925,8 +926,16 @@ class NestedLocksThreadingSupport : ThreadingSupport {
finally {
writeLockInitResult.release()
}
} catch (e : Throwable) {
throw e
}
catch (e: CancellationException) {
val job = currentThreadContext()[Job]
if (job != null && job.isCancelled && e !is ProcessCanceledException) {
// the lock acquisition was promptly canceled, so we need to rethrow a PCE from here to comply with blocking context
throw ProcessCanceledException(e)
}
else {
throw e
}
}
finally {
writeIntentInitResult.release()
@@ -15,6 +15,7 @@ import com.intellij.openapi.application.impl.assertReferenced
import com.intellij.openapi.application.impl.pumpEDT
import com.intellij.openapi.application.impl.withModality
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.progress.*
import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.Conditions
@@ -28,6 +29,7 @@ import com.intellij.util.application
import com.intellij.util.getValue
import com.intellij.util.setValue
import kotlinx.coroutines.*
import kotlinx.coroutines.future.asCompletableFuture
import org.jetbrains.concurrency.AsyncPromise
import org.jetbrains.concurrency.asCancellablePromise
import org.junit.jupiter.api.Assertions.*
@@ -873,6 +875,36 @@ class CancellationPropagationTest {
job.cancel()
}
@Test
fun `invokeAndWait propagates cancellation 2`(): Unit = timeoutRunBlocking(context = Dispatchers.Default) {
val job1 = Job(coroutineContext.job)
val job2 = Job(coroutineContext.job)
val job3 = Job(coroutineContext.job)
launch {
readAction {
job1.complete()
job2.asCompletableFuture().join()
}
}
job1.join()
val job = launch(Dispatchers.Default) {
blockingContext {
application.invokeAndWait {
job3.complete()
runWriteAction {
}
}
}
}
job3.join()
delay(100)
job.cancelAndJoin()
job2.cancelAndJoin()
}
@Test
fun `coroutine non-cancellable section coherence`() = timeoutRunBlocking {
withContext(Dispatchers.Default) {