* Removed the calls to SelectionKey.cancel() which takes places before calling Channel.close(), according to SelectableChannel Javadoc

* Fixed a bug where connect future is not notified if the channel is closed during the connection attempt
This commit is contained in:
Trustin Lee 2009-11-16 05:14:36 +00:00
parent 1f2d65ce54
commit f8aea1547e
3 changed files with 18 additions and 41 deletions

View File

@ -133,19 +133,25 @@ class NioClientSocketPipelineSink extends AbstractChannelSink {
}
private void connect(
final NioClientSocketChannel channel, ChannelFuture future,
final NioClientSocketChannel channel, final ChannelFuture cf,
SocketAddress remoteAddress) {
try {
if (channel.socket.connect(remoteAddress)) {
channel.worker.register(channel, future);
channel.worker.register(channel, cf);
} else {
future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
channel.connectFuture = future;
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture f)
throws Exception {
cf.setFailure(new ClosedChannelException());
}
});
cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
channel.connectFuture = cf;
boss.register(channel);
}
} catch (Throwable t) {
future.setFailure(t);
cf.setFailure(t);
fireExceptionCaught(channel, t);
}
}
@ -363,7 +369,7 @@ class NioClientSocketPipelineSink extends AbstractChannelSink {
ch.connectFuture.setFailure(cause);
fireExceptionCaught(ch, cause);
close(k);
NioWorker.close(ch, succeededFuture(ch));
}
}
}
@ -378,13 +384,12 @@ class NioClientSocketPipelineSink extends AbstractChannelSink {
} catch (Throwable t) {
ch.connectFuture.setFailure(t);
fireExceptionCaught(ch, t);
close(k);
NioWorker.close(ch, succeededFuture(ch));
}
}
private void close(SelectionKey k) {
k.cancel();
NioSocketChannel ch = (NioSocketChannel) k.attachment();
NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment();
NioWorker.close(ch, succeededFuture(ch));
}
}

View File

@ -653,26 +653,12 @@ class NioDatagramWorker implements Runnable {
static void close(final NioDatagramChannel channel,
final ChannelFuture future) {
NioDatagramWorker worker = channel.worker;
Selector selector = worker.selector;
boolean connected = channel.isConnected();
boolean bound = channel.isBound();
try {
// It is necessary to cancel all keys before closing a socket
// because the shutdown flag in the Selector loop is set only when
// all keys are cancelled. Thus, DatagramChannel.close() and
// SelectionKey.cancel() must be placed in a synchronized block.
// Otherwise DatagramChannel.register() in RegisterTask can be called
// after cancel(), but before close(), resulting in the infinite
// Selector loop that refuses to shut down due to the dangling keys.
synchronized (channel.interestOpsLock) {
SelectionKey key = channel.getDatagramChannel().keyFor(selector);
if (key != null) {
key.cancel();
worker.cancelledKeys ++;
}
channel.getDatagramChannel().close();
}
worker.cancelledKeys ++;
if (channel.setClosed()) {
future.setSuccess();

View File

@ -573,26 +573,12 @@ class NioWorker implements Runnable {
static void close(NioSocketChannel channel, ChannelFuture future) {
NioWorker worker = channel.worker;
Selector selector = worker.selector;
boolean connected = channel.isConnected();
boolean bound = channel.isBound();
try {
// It is necessary to cancel all keys before closing a socket
// because the shutdown flag in the Selector loop is set only when
// all keys are cancelled. Thus, SocketChannel.close() and
// SelectionKey.cancel() must be placed in a synchronized block.
// Otherwise SocketChannel.register() in RegisterTask can be called
// after cancel(), but before close(), resulting in the infinite
// Selector loop that refuses to shut down due to the dangling keys.
synchronized (channel.interestOpsLock) {
SelectionKey key = channel.socket.keyFor(selector);
if (key != null) {
key.cancel();
worker.cancelledKeys ++;
}
channel.socket.close();
}
worker.cancelledKeys ++;
if (channel.setClosed()) {
future.setSuccess();