[#943] Fix CanceledKeyException which can happen on frequently deregister/register while using the NIO Transport

This commit is contained in:
Norman Maurer 2013-01-16 12:20:35 +01:00
parent 895bce6cd5
commit f136eafd5e
2 changed files with 30 additions and 2 deletions

View File

@ -27,6 +27,7 @@ import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.Queue;
@ -250,8 +251,24 @@ public abstract class AbstractNioChannel extends AbstractChannel {
@Override
protected Runnable doRegister() throws Exception {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return null;
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return null;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
@Override

View File

@ -519,4 +519,15 @@ public final class NioEventLoop extends SingleThreadEventLoop {
selector.wakeup();
}
}
void selectNow() throws IOException {
try {
selector.selectNow();
} finally {
// restore wakup state if needed
if (wakenUp.get()) {
selector.wakeup();
}
}
}
}