public static void nextTask(Thread t,
ClassLoadingTask task,
UnifiedLoaderRepository3 repository) throws InterruptedException {
boolean trace = log.isTraceEnabled();
List taskList = (List) loadTasksByThread.get(t);
synchronized( taskList )
{
// There may not be any ThreadTasks
while( taskList.size() == 0 && task.threadTaskCount != 0 )
{
/* There are no more tasks for the calling thread to execute, so the
calling thread must wait until the task.threadTaskCount reaches 0
*/
if( trace )
log.trace("Begin nextTask(WAIT_ON_EVENT), task="+task);
try
{
task.state = ClassLoadingTask.WAIT_ON_EVENT;
taskList.wait();
}
catch(InterruptedException e)
{
if( trace )
log.trace("nextTask(WAIT_ON_EVENT), interrupted, task="+task, e);
// Abort this task attempt
throw e;
}
if( trace )
log.trace("nextTask(WAIT_ON_EVENT), notified, task="+task);
}
if( trace )
log.trace("Continue nextTask("+taskList.size()+"), task="+task);
// See if the task is complete
if( task.threadTaskCount == 0 )
{
task.state = ClassLoadingTask.FINISHED;
log.trace("End nextTask(FINISHED), task="+task);
return;
}
}
ThreadTask threadTask = (ThreadTask) taskList.remove(0);
ClassLoadingTask loadTask = threadTask.getLoadTask();
if( trace )
log.trace("Begin nextTask("+taskList.size()+"), loadTask="+loadTask);
RepositoryClassLoader ucl3 = threadTask.ucl;
try
{
if( threadTask.t == null )
{
/* This is a task that has been reassigned back to the original
requesting thread ClassLoadingTask, so a new ThreadTask must
be scheduled.
*/
if( trace )
log.trace("Rescheduling threadTask="+threadTask);
scheduleTask(loadTask, ucl3, threadTask.order, true, trace);
}
else
{
if( trace )
log.trace("Running threadTask="+threadTask);
// Load the class using this thread
threadTask.run();
}
}
catch(Throwable e)
{
boolean retry = e instanceof ClassCircularityError
|| e.getClass().equals(LinkageError.class);
int numCCE = loadTask.incNumCCE();
if( retry && numCCE < = 10 )
{
/* Reschedule this task after all existing tasks to allow the
current load tasks which are conflicting to complete.
*/
try
{
if( trace )
log.trace("Run failed with exception", e);
// Reschedule and update the loadTask.threadTaskCount
scheduleTask(loadTask, ucl3, Integer.MAX_VALUE, true, trace);
}
catch(Throwable ex)
{
loadTask.setLoadError(ex);
log.warn("Failed to reschedule task after LinkageError", ex);
}
if( trace )
log.trace("Post LinkageError state, loadTask="+loadTask);
}
else
{
loadTask.setLoadError(e);
if( trace )
log.trace("Run failed with exception, loadTask="+loadTask, e);
}
}
finally
{
// We must release the loadLock acquired in beginLoadTask
if( threadTask.releaseInNextTask == true )
{
if( trace )
log.trace("Releasing loadLock and ownership of UCL: "+threadTask.ucl);
synchronized( registrationLock )
{
loadClassThreads.remove(threadTask.ucl);
}
synchronized( threadTask.ucl )
{
ucl3.release();
ucl3.notifyAll();
}
}
}
// If the ThreadTasks are complete mark the ClassLoadingTask finished
if( loadTask.threadTaskCount == 0 )
{
Class loadedClass = threadTask.getLoadedClass();
if( loadedClass != null )
{
ClassLoader loader = loadedClass.getClassLoader();
ClassLoader wrapper = repository.getWrappingClassLoader(loader);
if (wrapper != null)
loader=wrapper;
// Place the loaded class into the repositry cache
repository.cacheLoadedClass(threadTask.getClassname(),
loadedClass, loader);
}
/*
synchronized( loadTask )
{
if( trace )
log.trace("Notifying task of thread completion, loadTask:"+loadTask);
loadTask.state = ClassLoadingTask.FINISHED;
loadTask.notify();
}
*/
List loadTaskThreadTasks = (List) loadTasksByThread.get(loadTask.requestingThread);
synchronized( loadTaskThreadTasks )
{
if( trace )
log.trace("Notifying task of thread completion, loadTask:"+loadTask);
loadTask.state = ClassLoadingTask.FINISHED;
loadTaskThreadTasks.notify();
}
}
if( trace )
log.trace("End nextTask("+taskList.size()+"), loadTask="+loadTask);
}
Called by threads owning a UCL3.loadLock from within UCL3.loadClass to
process ThreadTasks assigned to them. This is the mechanism by which we
avoid deadlock due to a given loadClass request requiring multiple UCLs
to be involved. Any thread active in loadClass with the monitor held
processes class loading tasks that must be handled by its UCL3. The
active set of threads loading classes form a pool of cooperating threads. |