diff --git a/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorker.java b/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorker.java index 6bfa5a57d7..5c1d3e2234 100644 --- a/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorker.java +++ b/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorker.java @@ -645,6 +645,13 @@ class NioDatagramWorker implements Runnable { 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.getDatagramChannel().keyFor(selector); if (key != null) { diff --git a/src/main/java/org/jboss/netty/channel/socket/nio/NioWorker.java b/src/main/java/org/jboss/netty/channel/socket/nio/NioWorker.java index ca947eb193..94466628ea 100644 --- a/src/main/java/org/jboss/netty/channel/socket/nio/NioWorker.java +++ b/src/main/java/org/jboss/netty/channel/socket/nio/NioWorker.java @@ -559,6 +559,13 @@ class NioWorker implements Runnable { 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) {