FIR IDE: add deadlock checking for read/write resolve locks

This commit is contained in:
Ilya Kirillov
2020-12-22 13:58:05 +01:00
parent 0ec152e457
commit ce77903898
@@ -6,8 +6,7 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.file.builder
import com.google.common.collect.MapMaker
import com.intellij.openapi.diagnostic.logger
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.PrivateForInline
import org.jetbrains.kotlin.idea.fir.low.level.api.util.lockWithPCECheck
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.locks.ReadWriteLock
@@ -17,22 +16,51 @@ import kotlin.concurrent.withLock
internal class LockProvider<KEY> {
private val locks: ConcurrentMap<KEY, ReadWriteLock> = MapMaker().weakKeys().makeMap()
@OptIn(PrivateForInline::class)
private val deadLockGuard = DeadLockGuard()
@Suppress("NOTHING_TO_INLINE")
private inline fun getLockFor(key: KEY) = locks.getOrPut(key) { ReentrantReadWriteLock() }
@OptIn(PrivateForInline::class)
inline fun <R> withReadLock(key: KEY, action: () -> R): R {
val readLock = getLockFor(key).readLock()
return readLock.withLock { action() }
return deadLockGuard.guardReadLock { readLock.withLock { action() } }
}
@OptIn(PrivateForInline::class)
inline fun <R> withWriteLock(key: KEY, action: () -> R): R {
val writeLock = getLockFor(key).writeLock()
return writeLock.withLock { action() }
return deadLockGuard.guardWriteLock { writeLock.withLock { action() } }
}
@OptIn(PrivateForInline::class)
inline fun <R> withWriteLockPCECheck(key: KEY, lockingIntervalMs: Long, action: () -> R): R {
val writeLock = getLockFor(key).writeLock()
return writeLock.lockWithPCECheck(lockingIntervalMs, action)
return deadLockGuard.guardWriteLock { writeLock.lockWithPCECheck(lockingIntervalMs, action) }
}
}
}
@PrivateForInline
internal class DeadLockGuard {
private val readLocksCount = ThreadLocal.withInitial { 0 }
inline fun <R> guardReadLock(action: () -> R): R {
readLocksCount.set(readLocksCount.get() + 1)
return try {
action()
} finally {
readLocksCount.set(readLocksCount.get() - 1)
}
}
inline fun <R> guardWriteLock(action: () -> R): R {
if (readLocksCount.get() > 0) {
throw ReadWriteDeadLockException()
}
return action()
}
}
class ReadWriteDeadLockException : IllegalStateException("Acquiring write lock when read lock hold")