I discovered a deadlock condition in the streaming renderer. it happens
in StreamingRenderer.PainterThread.run() :
public void run() {
thread = Thread.currentThread();
boolean done = false;
while(!done) {
try {
RenderingRequest request = requests.take();
if(request instanceof EndRequest ||
renderingStopRequested) {
done = true;
} else {
request.execute();
}
} catch(InterruptedException e) {
// ok, we might have been interupped to stop processing
if(renderingStopRequested) {
done = true;
} }
}
}
when called, this function is executed from a thread pool:
StreamingRenderer$PainterThread.run() line: 3590
Executors$RunnableAdapter<T>.call() line: 471 [local variables unavailable]
FutureTask$Sync.innerRun() line: 334
FutureTask<V>.run() line: 166
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1110
ThreadPoolExecutor$Worker.run() line: 603
Thread.run() line: 722
in the case that the RenderingRequest throws a RuntimeException or
Throwable, for example an OutOfMemoryError, the run() function returns,
leaving no threads in the thread pool, making the thread pool block and
wait for a new thread task:
Unsafe.park(boolean, long) line: not available [native method]
LockSupport.park(Object) line: 186
AbstractQueuedSynchronizer$ConditionObject.await() line: 2043
LinkedBlockingQueue<E>.take() line: 442
ThreadPoolExecutor.getTask() line: 1043
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1103
ThreadPoolExecutor$Worker.run() line: 603
Thread.run() line: 722
at the same time, the rendering queue might still have items in it, it
might even be full. the result is that the rendering process hangs.
I'd suggest the following fix:
public void run() {
thread = Thread.currentThread();
boolean done = false;
while(!done) {
try {
RenderingRequest request = requests.take();
if(request instanceof EndRequest ||
renderingStopRequested) {
done = true;
} else {
request.execute();
}
} catch(InterruptedException e) {
// ok, we might have been interupped to stop processing
if(renderingStopRequested) {
done = true;
} }
} catch (Throwable t) {
LOGGER.log(Level.SEVERE, "PainterThread caught
throwable", t);
}
}
|