From 7a24e9ea0ecb7a8f758ae13fa8f3186700c7bfe9 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Thu, 25 Jun 2020 17:59:47 +0700 Subject: [PATCH] Use a system property to lock in the dependencies downloader (#4255) Current implementation of synchronization in the dependencies downloader uses a static mutex and a file lock. It doesn't work if compiler instances are started in the same process but in different classloaders (see KT-39450). This patch works around this problem by using a system property instead of a static mutex for synchronization. Issue #KT-39450 fixed --- .../kotlin/konan/util/DependencyProcessor.kt | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DependencyProcessor.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DependencyProcessor.kt index 34e42dc8aef..c6bbac1aa33 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DependencyProcessor.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DependencyProcessor.kt @@ -211,8 +211,6 @@ class DependencyProcessor(dependenciesRoot: File, } companion object { - private val lock = ReentrantLock() - val localKonanDir: File by lazy { File(System.getenv("KONAN_DATA_DIR") ?: (System.getProperty("user.home") + File.separator + ".konan")) } @@ -265,17 +263,25 @@ class DependencyProcessor(dependenciesRoot: File, } } - fun run() = lock.withLock { - RandomAccessFile(lockFile, "rw").channel.lock().use { - resolvedDependencies.forEach { (dependency, candidate) -> - val baseUrl = when (candidate) { - is DependencySource.Local -> null - DependencySource.Remote.Public -> dependenciesUrl - DependencySource.Remote.Internal -> InternalServer.url - } - // TODO: consider using different caches for different remotes. - if (baseUrl != null) { - downloadDependency(dependency, baseUrl) + fun run() { + // We need a lock that can be shared between different classloaders (KT-39781). + // TODO: Rework dependencies downloading to avoid storing the lock in the system properties. + val lock = System.getProperties().computeIfAbsent("kotlin.native.dependencies.lock") { + // String literals are internalized so we create a new instance to avoid synchronization on a shared object. + java.lang.String("lock") + } + synchronized(lock) { + RandomAccessFile(lockFile, "rw").channel.lock().use { + resolvedDependencies.forEach { (dependency, candidate) -> + val baseUrl = when (candidate) { + is DependencySource.Local -> null + DependencySource.Remote.Public -> dependenciesUrl + DependencySource.Remote.Internal -> InternalServer.url + } + // TODO: consider using different caches for different remotes. + if (baseUrl != null) { + downloadDependency(dependency, baseUrl) + } } } }