From 8e0a8667a04dfd8d3509a08dc693de31cd5d2e77 Mon Sep 17 00:00:00 2001 From: Jenkins BBVA Date: Mon, 9 May 2016 10:11:41 +0200 Subject: [PATCH] [JENKINS-19445] Force class load on UserRequest (#82) * Force class load on UserRequest, see JENKINS-19445 This is a workaround to force class load of any class. This helps prevent deadlock on windows nodes when using JNA and Subversion. Use property hudson.remoting.RemoteClassLoader.force to name the class to load. Ideally this forced load should happen earlier on the startup, however the classloader isn't available. * Update UserRequest as per code review comments Fixes based on code review of pull-request: https://github.com/jenkinsci/remoting/pull/82 * Fix Logger.log() invocation Fix Logger.log() invocation: needs Object[], not vargs. --- .../java/hudson/remoting/UserRequest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/main/java/hudson/remoting/UserRequest.java b/src/main/java/hudson/remoting/UserRequest.java index ff898c2d2..26ef41cba 100644 --- a/src/main/java/hudson/remoting/UserRequest.java +++ b/src/main/java/hudson/remoting/UserRequest.java @@ -34,6 +34,8 @@ import java.io.Serializable; import java.io.NotSerializableException; import java.io.ObjectInputStream; +import java.util.logging.Level; +import java.util.logging.Logger; /** * {@link Request} that can take {@link Callable} whose actual implementation @@ -86,10 +88,40 @@ public UserRequest(Channel local, Callable c) throws IOException { return result; } + private static boolean workaroundDone = false; protected UserResponse perform(Channel channel) throws EXC { try { ClassLoader cl = channel.importedClassLoaders.get(classLoaderProxy); + // Allow forcibly load of a class, allows to workaround: + // @See https://issues.jenkins-ci.org/browse/JENKINS-19445 + // @Related https://issues.tmatesoft.com/issue/SGT-451 + final String clazz = System.getProperty(RemoteClassLoader.class.getName() + ".force", null); + if ( clazz != null && !workaroundDone) { + // Optimistic logging set. + String eventMsg = "Loaded"; + Level logLevel = Level.INFO; + // java.lang classes can only be instantiated by the bootstrap Classloader. + // Guarantees that *all* threads with whatever Classloader in use, have the + // same mutex instance: an intance of java.lang.Class + synchronized(java.lang.Object.class) + { + workaroundDone = true; + try { + final Class loaded = Class.forName( clazz, true, cl ); + } catch (final ClassNotFoundException cnfe) { + // not big deal, elevate log to warning and swallow exception + eventMsg = "Couldn't find"; + logLevel = Level.WARNING; + } + } + final Logger logger = Logger.getLogger(RemoteClassLoader.class.getName()); + if( logger.isLoggable(logLevel) ) + { + logger.log(logLevel, "%s class '%s' using classloader: %s", new String[]{ eventMsg, clazz, cl.toString()} ); + } + } + RSP r = null; Channel oldc = Channel.setCurrent(channel); try {