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 static org.jboss.netty.channel.Channels.*;
import java.nio.channels.ClosedChannelException;
import java.util.Queue; import java.util.Queue;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
@ -150,7 +151,10 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
ctx.sendUpstream(e); ctx.sendUpstream(e);
} }
private synchronized void discard(ChannelHandlerContext ctx) { private void discard(ChannelHandlerContext ctx) {
ClosedChannelException cause = null;
boolean fireExceptionCaught = false;
synchronized (this) {
for (;;) { for (;;) {
if (currentEvent == null) { if (currentEvent == null) {
currentEvent = queue.poll(); currentEvent = queue.poll();
@ -166,19 +170,24 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
Object m = currentEvent.getMessage(); Object m = currentEvent.getMessage();
if (m instanceof ChunkedInput) { if (m instanceof ChunkedInput) {
closeInput((ChunkedInput) m); closeInput((ChunkedInput) m);
}
// Trigger a ClosedChannelException // Trigger a ClosedChannelException
Channels.write( if (cause == null) {
ctx, currentEvent.getFuture(), ChannelBuffers.EMPTY_BUFFER, cause = new ClosedChannelException();
currentEvent.getRemoteAddress());
} else {
// Trigger a ClosedChannelException
ctx.sendDownstream(currentEvent);
} }
currentEvent.getFuture().setFailure(cause);
fireExceptionCaught = true;
currentEvent = null; currentEvent = null;
} }
} }
if (fireExceptionCaught) {
Channels.fireExceptionCaught(currentEvent.getChannel(), cause);
}
}
private synchronized void flush(ChannelHandlerContext ctx) throws Exception { private synchronized void flush(ChannelHandlerContext ctx) throws Exception {
final Channel channel = ctx.getChannel(); final Channel channel = ctx.getChannel();
if (!channel.isConnected()) { if (!channel.isConnected()) {