Patch ThreadTracker during Kotlin plugin init

This commit is contained in:
Nikolay Krasko
2016-09-21 22:18:32 +03:00
parent 68f0953b02
commit 63943c60d3
6 changed files with 81 additions and 78 deletions
@@ -95,9 +95,7 @@ fun doKotlinTearDown(project: Project, runnable: RunnableWithException) {
fun doKotlinTearDown(project: Project, runnable: () -> Unit) {
unInvalidateBuiltinsAndStdLib(project) {
patchThreadTracker {
runnable()
}
runnable()
}
}
@@ -148,55 +146,4 @@ fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(this)
return offset
}
private val patched = AtomicBoolean(false)
fun patchThreadTracker(runnable: RunnableWithException) {
patchThreadTracker {
runnable.run()
}
}
fun patchThreadTracker(runnable: () -> Unit) {
fun patch() {
if (patched.get()) return
patched.compareAndSet(false, true)
IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool()
// Check setup was successful
val commonPoolFactoryName = ForkJoinPool.commonPool().factory.javaClass.name
if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) {
return
}
println("Patching!")
try {
val wellKnownOffendersField = try {
ThreadTracker::class.java.getDeclaredField("wellKnownOffenders")
}
catch (communityPropertyNotFoundEx: NoSuchFieldException) {
ThreadTracker::class.java.getDeclaredField("a")
}
wellKnownOffendersField.isAccessible = true
@Suppress("UNCHECKED_CAST")
val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet<String>
wellKnownOffenders.add("ForkJoinPool.commonPool-worker-")
}
catch (e: NoSuchFieldException) {
println("Patching failed: " + e)
}
catch (e: IllegalAccessException) {
println("Patching failed: " + e)
}
}
patch()
runnable()
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory
import com.intellij.testFramework.ThreadTracker
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.atomic.AtomicBoolean
/*
Workaround for ThreadTracker.checkLeak() failures on TeamCity.
Currently TeamCity runs tests in classloader without boot.jar where IdeaForkJoinWorkerThreadFactory is defined. That
makes ForkJoinPool.commonPool() silently ignores java.util.concurrent.ForkJoinPool.common.threadFactory
(because of java.lang.ClassNotFoundException) option during factory initialization.
Standard names for ForkJoinPool threads doesn't pass ThreadTracker.checkLeak() check and that ruins tests constantly.
As it's allowed to reorder tests on TeamCity and any test can be first at some point, this patch should be applied at
some common place.
*/
object ForkJoinPoolPatcherForTeamCityTesting {
private val patched = AtomicBoolean(false)
fun patchThreadTracker() {
if (patched.get()) return
patched.compareAndSet(false, true)
IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool()
// Check setup was successful and patching isn't needed
val commonPoolFactoryName = ForkJoinPool.commonPool().factory.javaClass.name
if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) {
return
}
try {
val wellKnownOffendersField = try {
ThreadTracker::class.java.getDeclaredField("wellKnownOffenders")
}
catch (communityPropertyNotFoundEx: NoSuchFieldException) {
ThreadTracker::class.java.getDeclaredField("a")
}
wellKnownOffendersField.isAccessible = true
@Suppress("UNCHECKED_CAST")
val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet<String>
wellKnownOffenders.add("ForkJoinPool.commonPool-worker-")
println("Patching ThreadTracker was successful")
}
catch (e: NoSuchFieldException) {
println("Patching ThreadTracker failed: " + e)
}
catch (e: IllegalAccessException) {
println("Patching ThreadTracker failed: " + e)
}
}
}
@@ -54,6 +54,10 @@ public class PluginStartupComponent implements ApplicationComponent {
public void initComponent() {
registerPathVariable();
if (ApplicationManager.getApplication().isUnitTestMode()) {
ForkJoinPoolPatcherForTeamCityTesting.INSTANCE.patchThreadTracker();
}
JarUserDataManager.INSTANCE.register(KotlinJavaScriptLibraryDetectionUtil.HasKotlinJSMetadataInJar.INSTANCE);
DebuggerFiltersUtilKt.addKotlinStdlibDebugFilterIfNeeded();
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.idea;
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import org.jetbrains.kotlin.idea.test.RunnableWithException;
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
import org.jetbrains.kotlin.test.KotlinTestUtils;
abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase {
@@ -31,12 +29,7 @@ abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCas
@Override
protected void tearDown() throws Exception {
TestUtilsKt.patchThreadTracker(new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinDaemonAnalyzerTestCase.super.tearDown();
}
});
super.tearDown();
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
}
}
@@ -45,8 +45,6 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.idea.test.RunnableWithException;
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtFile;
@@ -101,7 +99,6 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase {
ConfigLibraryUtil.addLibrary(customLibEditor, model);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
protected void tearDown() throws Exception {
if (getTestName(true).startsWith("dex")) {
@@ -116,12 +113,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase {
}
});
TestUtilsKt.patchThreadTracker(new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinDebuggerTestCase.super.tearDown();
}
});
super.tearDown();
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
}
@@ -17,15 +17,8 @@
package org.jetbrains.kotlin.idea.rename
import org.jetbrains.kotlin.idea.refactoring.rename.AbstractRenameTest
import org.jetbrains.kotlin.idea.test.patchThreadTracker
import org.jetbrains.kotlin.tests.ULTIMATE_TEST_DATA_DIR
abstract class AbstractUltimateRenameTest : AbstractRenameTest() {
override fun getTestDataPath() = ULTIMATE_TEST_DATA_DIR
override fun tearDown() {
patchThreadTracker {
super.tearDown()
}
}
}