[LL FIR] try to check for PCE in ValueWithPostCompute to avoid possible deadlocks

This commit is contained in:
Ilya Kirillov
2022-12-13 14:02:59 +01:00
committed by Space Team
parent de7383ff15
commit f9298d8e85
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.lockWithPCECheck
import org.jetbrains.kotlin.util.shouldIjPlatformExceptionBeRethrown
import java.util.concurrent.locks.ReentrantLock
/**
* Lazily calculated value which runs postCompute in the same thread,
@@ -24,6 +26,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
) {
private var _calculate: ((KEY) -> Pair<VALUE, DATA>)? = calculate
private var _postCompute: ((KEY, VALUE, DATA) -> Unit)? = postCompute
private val lock = ReentrantLock()
/**
* can be in one of the following three states:
@@ -58,7 +61,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
if (stateSnapshot.threadId == Thread.currentThread().id) {
return stateSnapshot.value as VALUE
} else {
synchronized(this) { // wait until other thread which holds the lock now computes the value
lock.lockWithPCECheck(LOCKING_INTERVAL_MS) { // wait until other thread which holds the lock now computes the value
when (val newStateSnapshot = value) {
ValueIsNotComputed -> {
// if we have a PCE during value computation, then we will enter the critical section with `value == ValueIsNotComputed`
@@ -77,7 +80,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
}
}
}
ValueIsNotComputed -> synchronized(this) {
ValueIsNotComputed -> lock.lockWithPCECheck(LOCKING_INTERVAL_MS) {
return computeValueWithoutLock()
}
is ExceptionWasThrownDuringValueComputation -> {
@@ -92,7 +95,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
@Suppress("UNCHECKED_CAST")
// should be called under a synchronized section
private fun computeValueWithoutLock(): VALUE {
require(Thread.holdsLock(this))
require(lock.isHeldByCurrentThread)
// if we entered synchronized section that's mean that the value is not yet calculated and was not started to be calculated
// or the some other thread calculated the value while we were waiting to acquire the lock
@@ -146,4 +149,6 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
private class ValueIsPostComputingNow(val value: Any?, val threadId: Long)
private class ExceptionWasThrownDuringValueComputation(val error: Throwable)
private object ValueIsNotComputed
}
}
private const val LOCKING_INTERVAL_MS = 50L