From d12fbcf574bdac7247604e2b1e5196cdc62885c4 Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Fri, 9 Dec 2022 12:25:01 +0100 Subject: [PATCH] [Gradle] Share NativeDistributionCommonizerLock with 'cleanNativeDistributionCommonization' task KT-52172 --- .../native/internal/CommonizerTasks.kt | 14 ++++- .../NativeDistributionCommonizerCache.kt | 54 +---------------- .../NativeDistributionCommonizerLock.kt | 60 +++++++++++++++++++ 3 files changed, 73 insertions(+), 55 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerLock.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt index 3d01e789dbe..5932b068773 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlin.gradle.targets.native.internal +import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.api.tasks.Delete import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.compilerRunner.maybeCreateCommonizerClasspathConfiguration import org.jetbrains.kotlin.gradle.internal.isInIdeaSync @@ -140,7 +140,7 @@ internal val Project.commonizeNativeDistributionTask: TaskProvider? +internal val Project.cleanNativeDistributionCommonizerTask: TaskProvider? get() { val commonizeNativeDistributionTask = commonizeNativeDistributionTask ?: return null return rootProject.locateOrRegisterTask( @@ -148,7 +148,15 @@ internal val Project.cleanNativeDistributionCommonizerTask: TaskProvider configureTask = { group = "interop" description = "Deletes all previously commonized klib's from the Kotlin/Native distribution" - delete(commonizeNativeDistributionTask.map { it.rootOutputDirectory }) + + val commonizerDirectory = commonizeNativeDistributionTask.map { it.rootOutputDirectory } + outputs.dir(commonizerDirectory) + + doFirst { + NativeDistributionCommonizerLock(commonizerDirectory.get()).withLock { + delete(commonizerDirectory.get()) + } + } } ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt index 5674bcef5a9..249cba6ccbf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerCache.kt @@ -11,12 +11,8 @@ import org.gradle.api.logging.Logger import org.jetbrains.kotlin.commonizer.* import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.resolveCommonizedDirectory import java.io.File -import java.io.FileOutputStream import java.io.ObjectInputStream import java.io.Serializable -import java.util.concurrent.locks.Lock -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock class NativeDistributionCommonizerCache( private val outputDirectory: File, @@ -100,59 +96,13 @@ class NativeDistributionCommonizerCache( * even between multiple process (Gradle Daemons) */ @Transient - private var lock = Lock() + private var lock = NativeDistributionCommonizerLock(outputDirectory, ::logInfo) private fun logInfo(message: String) = logger.info("Native Distribution Commonization: $message") - private inner class Lock { - private val lockedOutputDirectories = mutableSetOf() - - fun withLock(action: () -> T): T { - /* Enter intra-process wide lock */ - intraProcessLock.withLock { - if (outputDirectory in lockedOutputDirectories) { - /* Already acquired this directory and re-entered: We can just execute the action */ - return action() - } - - /* Lock output directory inter-process wide */ - outputDirectory.mkdirs() - val lockfile = outputDirectory.resolve(".lock") - logInfo("Acquire lock: ${lockfile.path} ...") - FileOutputStream(outputDirectory.resolve(".lock")).use { stream -> - val lock = stream.channel.lock() - assert(lock.isValid) - return try { - logInfo("Lock acquired: ${lockfile.path}") - lockedOutputDirectories.add(outputDirectory) - action() - } finally { - lockedOutputDirectories.remove(outputDirectory) - lock.release() - logInfo("Lock released: ${lockfile.path}") - } - } - } - } - - fun checkLocked(outputDirectory: File) { - check(intraProcessLock.isHeldByCurrentThread) { - "Expected lock to be held by current thread ${Thread.currentThread().name}" - } - - check(outputDirectory in lockedOutputDirectories) { - "Expected $outputDirectory to be locked. Locked directories: $lockedOutputDirectories" - } - } - } - private fun readObject(input: ObjectInputStream) { input.defaultReadObject() - lock = Lock() - } - - private companion object { - val intraProcessLock: ReentrantLock = ReentrantLock() + lock = NativeDistributionCommonizerLock(outputDirectory, ::logInfo) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerLock.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerLock.kt new file mode 100644 index 00000000000..ecb0ab66677 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeDistributionCommonizerLock.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2022 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.targets.native.internal + +import java.io.File +import java.io.FileOutputStream +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock + +internal class NativeDistributionCommonizerLock( + private val outputDirectory: File, + private val logInfo: (message: String) -> Unit = {} +) { + private companion object { + val intraProcessLock: ReentrantLock = ReentrantLock() + } + + private val lockedOutputDirectories = mutableSetOf() + + fun withLock(action: () -> T): T { + /* Enter intra-process wide lock */ + intraProcessLock.withLock { + if (outputDirectory in lockedOutputDirectories) { + /* Already acquired this directory and re-entered: We can just execute the action */ + return action() + } + + /* Lock output directory inter-process wide */ + outputDirectory.mkdirs() + val lockfile = outputDirectory.resolve(".lock") + logInfo("Acquire lock: ${lockfile.path} ...") + FileOutputStream(outputDirectory.resolve(".lock")).use { stream -> + val lock = stream.channel.lock() + assert(lock.isValid) + return try { + logInfo("Lock acquired: ${lockfile.path}") + lockedOutputDirectories.add(outputDirectory) + action() + } finally { + lockedOutputDirectories.remove(outputDirectory) + lock.release() + logInfo("Lock released: ${lockfile.path}") + } + } + } + } + + fun checkLocked(outputDirectory: File) { + check(intraProcessLock.isHeldByCurrentThread) { + "Expected lock to be held by current thread ${Thread.currentThread().name}" + } + + check(outputDirectory in lockedOutputDirectories) { + "Expected $outputDirectory to be locked. Locked directories: $lockedOutputDirectories" + } + } +}