NETTY-384 Another deadlock in ChunkedWriteHandler

ChunkedWriteHandler.discard() do not issue write requests to trigger exceptionCaught events and to notify write futures anymore.  Instead, it triggers exceptionCaught events and notifies write futures by itself.  Therefore, no write lock is involved during discard(), avoiding the reported dead lock.

However, this is a temporary solution, and eventually Netty must introduce more robust event thread model.
This commit is contained in:
Trustin Lee 2011-08-02 09:33:27 +09:00
parent d72b89db21
commit 73d1f3fe02

View File

@ -17,6 +17,7 @@ package org.jboss.netty.handler.stream;
import static org.jboss.netty.channel.Channels.*;
import java.nio.channels.ClosedChannelException;
import java.util.Queue;
import org.jboss.netty.buffer.ChannelBuffers;
@ -150,32 +151,40 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
ctx.sendUpstream(e);
}
private synchronized void discard(ChannelHandlerContext ctx) {
for (;;) {
if (currentEvent == null) {
currentEvent = queue.poll();
}
private void discard(ChannelHandlerContext ctx) {
ClosedChannelException cause = null;
boolean fireExceptionCaught = false;
synchronized (this) {
for (;;) {
if (currentEvent == null) {
currentEvent = queue.poll();
}
if (currentEvent == null) {
break;
}
if (currentEvent == null) {
break;
}
MessageEvent currentEvent = this.currentEvent;
this.currentEvent = null;
MessageEvent currentEvent = this.currentEvent;
this.currentEvent = null;
Object m = currentEvent.getMessage();
if (m instanceof ChunkedInput) {
closeInput((ChunkedInput) m);
Object m = currentEvent.getMessage();
if (m instanceof ChunkedInput) {
closeInput((ChunkedInput) m);
}
// Trigger a ClosedChannelException
Channels.write(
ctx, currentEvent.getFuture(), ChannelBuffers.EMPTY_BUFFER,
currentEvent.getRemoteAddress());
} else {
// Trigger a ClosedChannelException
ctx.sendDownstream(currentEvent);
if (cause == null) {
cause = new ClosedChannelException();
}
currentEvent.getFuture().setFailure(cause);
fireExceptionCaught = true;
currentEvent = null;
}
currentEvent = null;
}
if (fireExceptionCaught) {
Channels.fireExceptionCaught(currentEvent.getChannel(), cause);
}
}