/* * Copyright 2013 Guidewire Software, Inc. */ package gw.lang.reflect.module; import gw.lang.UnstableAPI; import gw.lang.reflect.TypeSystem; import java.util.Map; @UnstableAPI public class TypeSystemLockHelper { /** * We avoid doing deadlock detection with class loading if we're running in * Studio primarily because the TIDB can grab the type system lock and hold * it for a long time during TIDB initialization. */ private static Boolean _bStudioRunning = null; private static boolean isStudioRunning() { if( _bStudioRunning == null ) { _bStudioRunning = System.getProperty( "gw.studio.running" ) != null; } return _bStudioRunning; } public static void getTypeSystemLockWithMonitor(Object objectToLock) { long lStart = System.currentTimeMillis(); while( !TypeSystem.getGlobalLock().tryLock() ) { try { //## hack: // This prevents deadlock ie., the call to findClass() could come back around and // try to grab the type sys lock. Not much we can do about this since this method // is called by private method ClassLoader.loadClassInternal(), which is synchronized! // Release this class loader's monitor, let some other thread have it (if that's the case), // and try again to acquire the type sys lock. The idea is to prevent deadlock by ensuring // we can acquire both locks or none at all... albeit expensively. try { objectToLock.wait(100); } catch (IllegalMonitorStateException e) { // Ugh! It turns out to be non-deterministic whether or not the VM will invoke this loop with the classloader's // monitor acquired. However, there can still be deadlocks due to other locks (not the monitor, but VM-level // locks around loading specific class names), so we have to just sleep and try again, even though it's // inefficient Thread.sleep(100); } if( !isStudioRunning() && System.currentTimeMillis() - lStart > 1000000 ) // wait pretty long (1000 secs as opposed to 10 secs) to avoid a false positive deadlock detection { StringBuilder b = new StringBuilder(); for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { b.append(entry.getKey().getName()).append('\n'); for (StackTraceElement stackTraceElement : entry.getValue()) { b.append(stackTraceElement).append('\n'); } b.append('\n'); } System.err.print(b.toString()); throw new RuntimeException( "Deadlock detected while loading classes" ); } } catch( InterruptedException e ) { throw new RuntimeException( e ); } } } }