* 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:
parent
1f2d65ce54
commit
f8aea1547e
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user