[LL FIR] try to check for PCE in ValueWithPostCompute to avoid possible deadlocks
This commit is contained in:
committed by
Space Team
parent
de7383ff15
commit
f9298d8e85
+9
-4
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches
|
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 org.jetbrains.kotlin.util.shouldIjPlatformExceptionBeRethrown
|
||||||
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazily calculated value which runs postCompute in the same thread,
|
* 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 _calculate: ((KEY) -> Pair<VALUE, DATA>)? = calculate
|
||||||
private var _postCompute: ((KEY, VALUE, DATA) -> Unit)? = postCompute
|
private var _postCompute: ((KEY, VALUE, DATA) -> Unit)? = postCompute
|
||||||
|
private val lock = ReentrantLock()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* can be in one of the following three states:
|
* 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) {
|
if (stateSnapshot.threadId == Thread.currentThread().id) {
|
||||||
return stateSnapshot.value as VALUE
|
return stateSnapshot.value as VALUE
|
||||||
} else {
|
} 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) {
|
when (val newStateSnapshot = value) {
|
||||||
ValueIsNotComputed -> {
|
ValueIsNotComputed -> {
|
||||||
// if we have a PCE during value computation, then we will enter the critical section with `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()
|
return computeValueWithoutLock()
|
||||||
}
|
}
|
||||||
is ExceptionWasThrownDuringValueComputation -> {
|
is ExceptionWasThrownDuringValueComputation -> {
|
||||||
@@ -92,7 +95,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
// should be called under a synchronized section
|
// should be called under a synchronized section
|
||||||
private fun computeValueWithoutLock(): VALUE {
|
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
|
// 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
|
// 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 ValueIsPostComputingNow(val value: Any?, val threadId: Long)
|
||||||
private class ExceptionWasThrownDuringValueComputation(val error: Throwable)
|
private class ExceptionWasThrownDuringValueComputation(val error: Throwable)
|
||||||
private object ValueIsNotComputed
|
private object ValueIsNotComputed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val LOCKING_INTERVAL_MS = 50L
|
||||||
Reference in New Issue
Block a user