From 99a75021e189824c1d34150ed72739b0c9a4272e Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 29 Jun 2016 15:44:38 +0300 Subject: [PATCH] Problem: manually shutdown AppScheduledExecutorService to allow compiler stop properly Without such shutdown console program that gets PSI file will hang forever. Introduced in https://github.com/JetBrains/intellij-community/commit/446b80077aed71e2384301ae993cf44416bf9a83 Stack example: java.lang.Thread.State: RUNNABLE at com.intellij.util.concurrency.AppDelayQueue.(AppDelayQueue.java:37) at com.intellij.util.concurrency.AppScheduledExecutorService.(AppScheduledExecutorService.java:50) at com.intellij.util.concurrency.AppScheduledExecutorService$Holder.(AppScheduledExecutorService.java:41) at com.intellij.util.concurrency.AppScheduledExecutorService.getInstance(AppScheduledExecutorService.java:46) at com.intellij.util.concurrency.AppExecutorUtil.getAppScheduledExecutorService(AppExecutorUtil.java:39) at com.intellij.concurrency.JobScheduler.getScheduler(JobScheduler.java:43) at com.intellij.psi.impl.source.AstPathPsiMap.(AstPathPsiMap.java:45) at com.intellij.psi.impl.source.PsiFileImpl.(PsiFileImpl.java:76) at com.intellij.extapi.psi.PsiFileBase.(PsiFileBase.java:39) at org.jetbrains.kotlin.psi.KtFile.(KtFile.java:48) at org.jetbrains.kotlin.parsing.KotlinParserDefinition.createFile(KotlinParserDefinition.kt:73) at com.intellij.psi.SingleRootFileViewProvider.createFile(SingleRootFileViewProvider.java:407) at com.intellij.psi.SingleRootFileViewProvider.createFile(SingleRootFileViewProvider.java:348) at com.intellij.psi.SingleRootFileViewProvider.createFile(SingleRootFileViewProvider.java:326) at com.intellij.psi.SingleRootFileViewProvider.getPsiInner(SingleRootFileViewProvider.java:171) at com.intellij.psi.SingleRootFileViewProvider.getPsi(SingleRootFileViewProvider.java:155) at com.intellij.psi.impl.PsiFileFactoryImpl.trySetupPsiForFile(PsiFileFactoryImpl.java:121) at com.intellij.psi.impl.PsiFileFactoryImpl.createFileFromText(PsiFileFactoryImpl.java:100) at com.intellij.psi.impl.PsiFileFactoryImpl.createFileFromText(PsiFileFactoryImpl.java:56) at org.jetbrains.kotlin.psi.KtPsiFactory.doCreateFile(KtPsiFactory.kt:174) at org.jetbrains.kotlin.psi.KtPsiFactory.createFile(KtPsiFactory.kt:178) at org.jetbrains.kotlin.preprocessor.Preprocessor.processFileSingleEvaluator(Preprocessor.kt:82) at org.jetbrains.kotlin.preprocessor.Preprocessor.processDirectorySingleEvaluator(Preprocessor.kt:105) at org.jetbrains.kotlin.preprocessor.Preprocessor.processDirectorySingleEvaluator(Preprocessor.kt:135) at org.jetbrains.kotlin.preprocessor.Preprocessor.processSources(Preprocessor.kt:74) at org.jetbrains.kotlin.preprocessor.PreprocessorCLI.main(PreprocessorCLI.kt:35) --- .../kotlin/serialization/builtins/run.kt | 12 ++++++++++-- .../jetbrains/kotlin/cli/common/CLICompiler.java | 15 ++++++++++++--- .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 1 + .../PreprocessorCLI.kt | 13 ++++++++++--- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/run.kt b/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/run.kt index bac7fb77eb1..87911d5d4a2 100644 --- a/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/run.kt +++ b/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/run.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.serialization.builtins +import com.intellij.util.concurrency.AppExecutorUtil +import com.intellij.util.concurrency.AppScheduledExecutorService import java.io.File fun main(args: Array) { @@ -41,7 +43,13 @@ found top-level declarations to (*.kotlin_builtins files)""" val missing = srcDirs.filterNot { it.exists() } assert(missing.isEmpty()) { "These source directories are missing: $missing" } - BuiltInsSerializer(dependOnOldBuiltIns = false).serialize(destDir, srcDirs, listOf()) { totalSize, totalFiles -> - println("Total bytes written: $totalSize to $totalFiles files") + try { + BuiltInsSerializer(dependOnOldBuiltIns = false).serialize(destDir, srcDirs, listOf()) { totalSize, totalFiles -> + println("Total bytes written: $totalSize to $totalFiles files") + } + } + finally { + val service = AppExecutorUtil.getAppScheduledExecutorService() as AppScheduledExecutorService + service.shutdownAppScheduledExecutorService() } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java index 3811509678a..7e0b3541245 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java @@ -20,6 +20,8 @@ import com.google.common.base.Predicates; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.concurrency.AppExecutorUtil; +import com.intellij.util.concurrency.AppScheduledExecutorService; import com.sampullara.cli.Args; import kotlin.Pair; import kotlin.collections.ArraysKt; @@ -303,9 +305,16 @@ public abstract class CLICompiler { // We depend on swing (indirectly through PSI or something), so we want to declare headless mode, // to avoid accidentally starting the UI thread System.setProperty("java.awt.headless", "true"); - ExitCode exitCode = doMainNoExit(compiler, args); - if (exitCode != OK) { - System.exit(exitCode.getCode()); + try { + ExitCode exitCode = doMainNoExit(compiler, args); + + if (exitCode != OK) { + System.exit(exitCode.getCode()); + } + } + finally { + AppScheduledExecutorService service = (AppScheduledExecutorService) AppExecutorUtil.getAppScheduledExecutorService(); + service.shutdownAppScheduledExecutorService(); } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 8cf6ff5887a..433b426ff90 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -95,6 +95,7 @@ import org.jetbrains.kotlin.script.* import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.ifEmpty import java.io.File +import java.lang.IllegalStateException import java.util.* class KotlinCoreEnvironment private constructor( diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/PreprocessorCLI.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/PreprocessorCLI.kt index b49863d0c22..dae64dce390 100644 --- a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/PreprocessorCLI.kt +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/PreprocessorCLI.kt @@ -16,9 +16,9 @@ @file:JvmName("PreprocessorCLI") package org.jetbrains.kotlin.preprocessor +import com.intellij.util.concurrency.AppExecutorUtil +import com.intellij.util.concurrency.AppScheduledExecutorService import java.io.File -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit fun main(args: Array) { if (args.size != 3) { @@ -32,5 +32,12 @@ fun main(args: Array) { val profile = createProfile(args[2], targetPath) println("Preprocessing sources in $sourcePath to $targetPath with profile ${profile.name}") - Preprocessor().processSources(sourcePath, profile) + + try { + Preprocessor().processSources(sourcePath, profile) + } + finally { + val service = AppExecutorUtil.getAppScheduledExecutorService() as AppScheduledExecutorService + service.shutdownAppScheduledExecutorService() + } }