提交 254a978a 编写于 作者: I Ilya Matveev

Gradle, native: Forbid parallel in-process compiler execution

After enabling the in-process compiler execution, we got several
reports related to the race condition that takes place during
system properties configuring (e.g. KT-37442, KT-37444, probably
KT-37362).

The right fix here is to get rid of using system properties at all.
But it requires changes in many places of the K/N compiler and such
a patch is not safe enough to include it into a bug-fix release. So
it's decided to forbid parallel in-process compiler execution in
1.3.71 and 1.4-M2.

Issue #KT-37565 Fixed
Issue #KT-37696 Fixed

Ported from:
https://github.com/JetBrains/kotlin/commit/1c1b637cc46012a22867d8e653bb6d94ed6138ba
https://github.com/JetBrains/kotlin/commit/2128d3dfe77db4e0a8450f4f943cbd13c2e5dd4d
上级 f2c05bf8
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.modify
import org.junit.Test
class GeneralNativeIT : BaseGradleIT() {
@Test
fun testParallelExecutionDetection(): Unit = with(transformProjectWithPluginsDsl("native-parallel")) {
val compileTasks = arrayOf(":one:compileKotlinLinux", ":two:compileKotlinLinux")
// Check that parallel in-process execution fails with the corresponding message.
build(*compileTasks) {
assertFailed()
assertContains("Parallel in-process execution of the Kotlin/Native compiler detected.")
}
// Parallel execution without daemon => ok.
build("clean", *compileTasks, "-Pkotlin.native.disableCompilerDaemon=true") {
assertSuccessful()
assertTasksExecuted(*compileTasks)
}
// org.gradle.parallel must be set in the properties file (not in command line).
projectDir.resolve("gradle.properties").modify {
it.replace("org.gradle.parallel=true", "org.gradle.parallel=false")
}
// Sequential execution => ok.
build("clean", *compileTasks) {
assertSuccessful()
assertTasksExecuted(*compileTasks)
}
// Check for KT-37696.
// Add an incorrect code to trigger compilation failure.
projectDir.resolve("one/src/linuxMain/kotlin/main.kt").appendText("\nfun incorrect")
gradleBuildScript("two").appendText("""
val compileKotlinLinux by tasks.getting
compileKotlinLinux.mustRunAfter(":one:compileKotlinLinux")
""".trimIndent())
build("clean", *compileTasks, "--continue") {
assertFailed()
assertTasksFailed(":one:compileKotlinLinux")
assertTasksExecuted(":two:compileKotlinLinux")
assertNotContains("Parallel in-process execution of the Kotlin/Native compiler detected.")
}
}
}
\ No newline at end of file
plugins {
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>").apply(false)
}
allprojects {
repositories {
mavenLocal()
jcenter()
}
}
\ No newline at end of file
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
kotlin {
linuxX64("linux")
sourceSets["commonMain"].dependencies {
implementation(kotlin("stdlib"))
}
}
\ No newline at end of file
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
fun main() {
println(42)
}
\ No newline at end of file
pluginManagement {
repositories {
mavenLocal()
jcenter()
gradlePluginPortal()
}
}
include(":one", ":two")
\ No newline at end of file
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
kotlin {
linuxX64("linux")
sourceSets["commonMain"].dependencies {
implementation(kotlin("stdlib"))
}
}
\ No newline at end of file
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
fun main() {
println(42)
}
\ No newline at end of file
......@@ -90,7 +90,8 @@ internal abstract class KotlinToolRunner(
}
}
private fun runInProcess(args: List<String>) {
// TODO: Make it private again once KT-37550 is fixed.
protected open fun runInProcess(args: List<String>) {
val oldProperties = setUpSystemProperties()
try {
......
......@@ -78,6 +78,50 @@ internal abstract class KotlinNativeToolRunner(
override fun transformArgs(args: List<String>) = listOf(toolName) + args
final override fun getCustomJvmArgs() = project.jvmArgs
final override fun runInProcess(args: List<String>) {
withParallelExecutionGuard {
super.runInProcess(args)
}
}
// TODO: Remove once KT-37550 is fixed
private inline fun withParallelExecutionGuard(action: () -> Unit) {
try {
if (PropertiesProvider(project).nativeEnableParallelExecutionCheck) {
System.getProperties().compute(PARALLEL_EXECUTION_GUARD_PROPERTY) { _, value ->
check(value == null) { PARALLEL_EXECUTION_ERROR_MESSAGE }
"true"
}
}
action()
} finally {
if (PropertiesProvider(project).nativeEnableParallelExecutionCheck) {
System.clearProperty(PARALLEL_EXECUTION_GUARD_PROPERTY)
}
}
}
companion object {
private const val PARALLEL_EXECUTION_GUARD_PROPERTY = "org.jetbrains.kotlin.native.compiler.running"
private val PARALLEL_EXECUTION_ERROR_MESSAGE = """
Parallel in-process execution of the Kotlin/Native compiler detected.
At this moment the parallel execution of several compiler instances in the same process is not supported.
To fix this, you can do one of the following things:
- Disable in-process execution. To do this, set '${PropertiesProvider.KOTLIN_NATIVE_DISABLE_COMPILER_DAEMON}=true' project property.
- Disable parallel task execution. To do this, set 'org.gradle.parallel=false' project property.
If you still want to run the compiler in-process in parallel, you may disable this check by setting project
property '${PropertiesProvider.KOTLIN_NATIVE_ENABLE_PARALLEL_EXECUTION_CHECK}=false'. Note that in this case the compiler may fail.
""".trimIndent()
}
}
/** A common ancestor for all runners that run the cinterop tool. */
......
......@@ -189,7 +189,11 @@ internal class PropertiesProvider private constructor(private val project: Proje
* Forces to run a compilation in a separate JVM.
*/
val nativeDisableCompilerDaemon: Boolean?
get() = booleanProperty("kotlin.native.disableCompilerDaemon")
get() = booleanProperty(KOTLIN_NATIVE_DISABLE_COMPILER_DAEMON)
// TODO: Remove once KT-37550 is fixed
val nativeEnableParallelExecutionCheck: Boolean
get() = booleanProperty(KOTLIN_NATIVE_ENABLE_PARALLEL_EXECUTION_CHECK) ?: true
/**
* Dependencies caching strategy. The default is static.
......@@ -238,6 +242,11 @@ internal class PropertiesProvider private constructor(private val project: Proje
private const val CACHED_PROVIDER_EXT_NAME = "kotlin.properties.provider"
internal const val KOTLIN_NATIVE_DISABLE_COMPILER_DAEMON = "kotlin.native.disableCompilerDaemon"
// TODO: Remove once KT-37550 is fixed
internal const val KOTLIN_NATIVE_ENABLE_PARALLEL_EXECUTION_CHECK = "kotlin.native.enableParallelExecutionCheck"
operator fun invoke(project: Project): PropertiesProvider =
with(project.extensions.extraProperties) {
if (!has(CACHED_PROVIDER_EXT_NAME)) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册