[#1310] Fix deadlock which can happen if limit of MemoryAwareThreadPoolExecutor was exceed and an exceptionCaught(..) is triggered by a write

This commit is contained in:
Norman Maurer 2013-05-06 13:54:25 +02:00
parent 960067c78a
commit 60695012ab

View File

@ -31,7 +31,9 @@ import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey; import java.nio.channels.SelectionKey;
import java.nio.channels.Selector; import java.nio.channels.Selector;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -171,6 +173,8 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker {
final WritableByteChannel ch = channel.channel; final WritableByteChannel ch = channel.channel;
final Queue<MessageEvent> writeBuffer = channel.writeBufferQueue; final Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
final int writeSpinCount = channel.getConfig().getWriteSpinCount(); final int writeSpinCount = channel.getConfig().getWriteSpinCount();
List<Throwable> causes = null;
synchronized (channel.writeLock) { synchronized (channel.writeLock) {
channel.inWriteNowLoop = true; channel.inWriteNowLoop = true;
for (;;) { for (;;) {
@ -245,7 +249,14 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker {
future.setFailure(t); future.setFailure(t);
} }
if (iothread) { 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<Throwable>(1);
}
causes.add(t);
} else { } else {
fireExceptionCaughtLater(channel, t); fireExceptionCaughtLater(channel, t);
} }
@ -273,11 +284,18 @@ abstract class AbstractNioWorker extends AbstractNioSelector implements Worker {
} else if (removeOpWrite) { } else if (removeOpWrite) {
clearOpWrite(channel); 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) { if (iothread) {
fireWriteComplete(channel, writtenBytes); fireWriteComplete(channel, writtenBytes);
} else { } else {