[#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.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<MessageEvent> writeBuffer = channel.writeBufferQueue;
final int writeSpinCount = channel.getConfig().getWriteSpinCount();
List<Throwable> 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<Throwable>(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 {