package org.jboss.test.classloader.test;
import java.net.URL;
import java.io.File;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import org.jboss.logging.Logger;
import org.jboss.mx.loading.UnifiedLoaderRepository3;
import org.jboss.mx.loading.UnifiedClassLoader3;
import org.jboss.mx.loading.LoaderRepository;
import org.jboss.mx.loading.LoadMgr3;
import org.jboss.test.classloader.circularity.test.MyClassLoadingTask;
import org.jboss.test.util.ClassMover;
public class DeadlockTests32
{
private static Logger log = Logger.getLogger(DeadlockTests32.class);
private SyncEvent syncEvent = new SyncEvent();
private TestClassLoader loaders[];
private UnifiedLoaderRepository3 mainRep;
private TestClassLoader blockingLoader;
private String blockname;
public DeadlockTests32(File libDir) throws Exception
{
ClassLoader appCl = this.getClass().getClassLoader();
URL u1 = new File(libDir, "dl-a.jar").toURL();
URL u2 = new File(libDir, "dl-b.jar").toURL();
loaders = new TestClassLoader[2];
mainRep = new UnifiedLoaderRepository3();
loaders[0] = new TestClassLoader(u1, appCl, mainRep);
loaders[1] = new TestClassLoader(u2, appCl, mainRep);
}
public void testDeadLock() throws Exception
{
log.info("RUNNING: testDeadLock");
File TestAclass = ClassMover.move("org.jboss.test.classloader.test.abc.TestA");
File TestBclass = ClassMover.move("org.jboss.test.classloader.test.abc.TestB");
File TestB2class = ClassMover.move("org.jboss.test.classloader.test.abc.TestB2");
blockingLoader = loaders[1];
blockname = "org.jboss.test.classloader.test.abc.TestB";
ClassLoader cl1 = loaders[0];
ClassLoader cl2 = loaders[1];
Runner t2 = new Runner("T2", blockname, cl2);
ThreadList threads = new ThreadList();
threads.add(t2);
log.info("t0, Waiting for T2 to start");
t2.start();
Thread.sleep(2000);
log.info("t1, T2 should be waiting in beforeTaskLoop");
Runner t1 = new Runner("T1", "org.jboss.test.classloader.test.abc.TestB2", cl1);
threads.add(t1);
log.info("t2, Waiting for T1 to start");
t1.start();
Thread.sleep(4000);
log.info("t3, Now releasing T2/CL2");
syncEvent.set();
log.info("t4, Waiting for T1, T2 to complete");
threads.waitAll();
ClassMover.restore(TestAclass);
ClassMover.restore(TestBclass);
ClassMover.restore(TestB2class);
}
public void testDeadLockAndCircularity() throws Exception
{
log.info("RUNNING: testDeadLockAndCircularity");
File TestAclass = ClassMover.move("org.jboss.test.classloader.test.abc.TestA");
File TestBclass = ClassMover.move("org.jboss.test.classloader.test.abc.TestB");
File TestB3class = ClassMover.move("org.jboss.test.classloader.test.abc.TestB3");
blockingLoader = loaders[1];
blockname = "org.jboss.test.classloader.test.abc.TestB";
ClassLoader cl1 = loaders[0];
ClassLoader cl2 = loaders[1];
Runner t2 = new Runner("T2", blockname, cl2);
ThreadList threads = new ThreadList();
threads.add(t2);
log.info("t0, Waiting for T2 to start");
t2.start();
Thread.sleep(2000);
log.info("t1, T2 should be waiting in beforeTaskLoop");
Runner t1 = new Runner("T1", "org.jboss.test.classloader.test.abc.TestB3", cl1);
threads.add(t1);
log.info("t2, Waiting for T1 to start");
t1.start();
Thread.sleep(4000);
log.info("t3, Now releasing T2/CL2");
syncEvent.set();
threads.waitAll();
ClassMover.restore(TestAclass);
ClassMover.restore(TestBclass);
ClassMover.restore(TestB3class);
}
private class Runner extends Thread
{
private String clsname;
private ClassLoader loader;
public Runner(String name, String clsname, ClassLoader cl)
{
super(name);
this.clsname = clsname;
this.loader = cl;
}
private Throwable savedEx;
public Throwable getThrowable()
{
return savedEx;
}
public void showException()
{
if (savedEx != null)
{
log.error("Exception for: " + getName(), savedEx);
}
}
public void run()
{
try
{
Class cls = Class.forName(clsname, true, loader);
cls.newInstance();
}
catch (Throwable ex)
{
savedEx = ex;
}
}
}
public void beforeTaskLoop(UnifiedClassLoader3 cl, String clsname)
{
log.info("BeforeTaskLoop: " + clsname);
if (cl == blockingLoader && clsname.equals(blockname))
{
log.info("Waiting in beforeTaskLoop: " + cl + " on " + blockname);
try
{
syncEvent.aquire();
}
catch (InterruptedException e)
{
log.error("Interrupted", e);
}
log.info("End beforeTaskLoop: " + cl);
}
}
public class TestClassLoader extends UnifiedClassLoader3
{
public TestClassLoader(URL url, ClassLoader parent,
LoaderRepository repository)
{
super(url, null, parent, null);
repository.addClassLoader(this);
}
public synchronized Class loadClassImpl(String name, boolean resolve)
throws ClassNotFoundException
{
boolean trace = log.isTraceEnabled();
boolean acquired = attempt(1);
while( acquired == false )
{
try
{
if( trace )
log.trace("Waiting for loadClass lock");
this.wait();
}
catch(InterruptedException ignore)
{
}
acquired = attempt(1);
}
MyClassLoadingTask task = null;
try
{
Thread t = Thread.currentThread();
if( loadLock.holds() == 1 )
LoadMgr3.registerLoaderThread(this, t);
beforeTaskLoop(name);
task = new MyClassLoadingTask(name, this, t);
UnifiedLoaderRepository3 ulr3 = (UnifiedLoaderRepository3) repository;
if( LoadMgr3.beginLoadTask(task, ulr3) == false )
{
while( task.threadTaskCount() != 0 )
{
try
{
LoadMgr3.nextTask(t, task, ulr3);
}
catch(InterruptedException e)
{
break;
}
}
}
}
finally
{
if( loadLock.holds() == 1 )
LoadMgr3.endLoadTask(task);
this.release();
this.notifyAll();
}
if( task.loadedClass() == null )
{
if( task.loadException() instanceof ClassNotFoundException )
throw (ClassNotFoundException) task.loadException();
else if( task.loadException() != null )
{
if( log.isTraceEnabled() )
log.trace("Unexpected error during load of:"+name, task.loadException());
String msg = "Unexpected error during load of: "+name
+ ", msg="+task.loadException().getMessage();
throw new ClassNotFoundException(msg);
}
else
throw new IllegalStateException("ClassLoadingTask.loadedTask is null, name: "+name);
}
return task.loadedClass();
}
protected void beforeTaskLoop(String clsname)
{
log.info("Calling taskLoop");
DeadlockTests32.this.beforeTaskLoop(this, clsname);
}
}
private class ThreadList
{
List list = new ArrayList();
public ThreadList()
{
}
public void add(Thread t)
{
list.add(t);
}
public void waitAll() throws Exception
{
Iterator it = list.iterator();
Throwable ex = null;
StringBuffer buf = new StringBuffer();
while (it.hasNext())
{
Runner t = (Runner) it.next();
t.join();
Throwable e = t.getThrowable();
if (e != null)
{
buf.append("Failure for: ").append(t.getName());
buf.append('\n').append(e);
if (ex == null)
{
ex = e;
}
}
}
if (ex != null)
{
log.info(buf.toString());
if (ex instanceof Exception)
{
throw (Exception) ex;
}
else if (ex instanceof Error)
{
throw (Error) ex;
}
}
}
}
private class SyncEvent
{
private boolean cond;
public SyncEvent()
{
this(false);
}
public SyncEvent(boolean initialValue)
{
cond = initialValue;
}
public void aquire() throws InterruptedException
{
synchronized (this)
{
while (!cond)
{
wait();
}
}
}
public synchronized void set()
{
cond = true;
notifyAll();
}
public synchronized void unset()
{
cond = false;
}
}
}