diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java index 50ee58e0cc..5a88289703 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java @@ -5,6 +5,10 @@ import java.net.URLClassLoader; /** Classloader used to run the core datadog agent. */ public class DatadogClassLoader extends URLClassLoader { + static { + ClassLoader.registerAsParallelCapable(); + } + // Calling java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch // adds a jar to the bootstrap class lookup, but not to the resource lookup. // As a workaround, we keep a reference to the bootstrap jar @@ -45,6 +49,10 @@ public class DatadogClassLoader extends URLClassLoader { *

This class is thread safe. */ public static final class BootstrapClassLoaderProxy extends URLClassLoader { + static { + ClassLoader.registerAsParallelCapable(); + } + public BootstrapClassLoaderProxy(URL[] urls, ClassLoader parent) { super(urls, parent); } diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy new file mode 100644 index 0000000000..842b9573fe --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy @@ -0,0 +1,49 @@ +package datadog.trace.bootstrap + +import spock.lang.Specification +import spock.lang.Timeout + +import java.util.concurrent.Phaser +import java.util.concurrent.TimeUnit + +class DatadogClassLoaderTest extends Specification { + @Timeout(value = 60, unit = TimeUnit.SECONDS) + def "DD classloader does not lock classloading around instance" () { + setup: + def className1 = 'some/class/Name1' + def className2 = 'some/class/Name2' + final URL loc = getClass().getProtectionDomain().getCodeSource().getLocation() + final DatadogClassLoader ddLoader = new DatadogClassLoader(loc, loc, (ClassLoader) null) + final Phaser threadHoldLockPhase = new Phaser(2) + final Phaser acquireLockFromMainThreadPhase = new Phaser(2) + + when: + final Thread thread1 = new Thread() { + @Override + void run() { + synchronized (ddLoader.getClassLoadingLock(className1)) { + threadHoldLockPhase.arrive() + acquireLockFromMainThreadPhase.arriveAndAwaitAdvance() + } + } + } + thread1.start() + + final Thread thread2 = new Thread() { + @Override + void run() { + threadHoldLockPhase.arriveAndAwaitAdvance() + synchronized (ddLoader.getClassLoadingLock(className2)) { + acquireLockFromMainThreadPhase.arrive() + } + } + } + thread2.start() + thread1.join() + thread2.join() + boolean applicationDidNotDeadlock = true + + then: + applicationDidNotDeadlock + } +}