Register Datadog classloader as parallel capable
MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
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
@@ -24,6 +28,12 @@ public class DatadogClassLoader extends URLClassLoader {
bootstrapProxy = new BootstrapClassLoaderProxy(new URL[] {bootstrapJarLocation}, null);
}
+ /** Public for testing only */
+ @Override
+ public Object getClassLoadingLock(String className) {
+ return super.getClassLoadingLock(className);
+ }
+
@Override
public URL getResource(String resourceName) {
final URL bootstrapResource = bootstrapProxy.getResource(resourceName);
@@ -45,6 +55,10 @@ public class DatadogClassLoader extends URLClassLoader {
* <p>This class is thread safe.
*/
public static final class BootstrapClassLoaderProxy extends URLClassLoader {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+
public BootstrapClassLoaderProxy(URL[] urls, ClassLoader parent) {
super(urls, parent);
}

ADD
dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy
+package datadog.trace.bootstrap
+
+import spock.lang.Specification
+
+import java.util.concurrent.Phaser
+
+class DatadogClassLoaderTest extends Specification {
+ 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 thread = new Thread() {
+ @Override
+ void run() {
+ synchronized (ddLoader.getClassLoadingLock(className1)) {
+ threadHoldLockPhase.arrive()
+ acquireLockFromMainThreadPhase.arriveAndAwaitAdvance()
+ }
+ }
+ }
+ thread.start()
+
+ threadHoldLockPhase.arriveAndAwaitAdvance()
+ synchronized (ddLoader.getClassLoadingLock(className2)) {
+ acquireLockFromMainThreadPhase.arrive()
+ }
+ thread.join()
+ boolean applicationDidNotDeadlock = true
+
+ then:
+ applicationDidNotDeadlock
+ }
+}

Register Datadog classloader as parallel capable