diff --git a/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorker.java b/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorker.java index 632af5facf..230ec87ce6 100644 --- a/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorker.java +++ b/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorker.java @@ -31,7 +31,9 @@ import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; @@ -171,6 +173,8 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker { final WritableByteChannel ch = channel.channel; final Queue writeBuffer = channel.writeBufferQueue; final int writeSpinCount = channel.getConfig().getWriteSpinCount(); + List causes = null; + synchronized (channel.writeLock) { channel.inWriteNowLoop = true; for (;;) { @@ -245,7 +249,14 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker { future.setFailure(t); } if (iothread) { - fireExceptionCaught(channel, t); + // An exception was thrown from within a write in the iothread. We store a reference to it + // in a list for now and notify the handlers in the chain after the writeLock was released + // to prevent possible deadlock. + // See #1310 + if (causes == null) { + causes = new ArrayList(1); + } + causes.add(t); } else { fireExceptionCaughtLater(channel, t); } @@ -273,11 +284,18 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker { } else if (removeOpWrite) { clearOpWrite(channel); } - } else { - // close the channel now - close(channel, succeededFuture(channel)); } } + if (causes != null) { + for (Throwable cause: causes) { + // notify about cause now as it was triggered in the write loop + fireExceptionCaught(channel, cause); + } + } + if (!open) { + // close the channel now + close(channel, succeededFuture(channel)); + } if (iothread) { fireWriteComplete(channel, writtenBytes); } else {