Fixed deadlock in AsyncSshHandlerWriter 83/81783/1
authorJaroslav Tóth <jtoth@frinx.io>
Tue, 2 Apr 2019 03:41:32 +0000 (05:41 +0200)
committerRobert Varga <nite@hq.sk>
Thu, 25 Apr 2019 13:22:12 +0000 (13:22 +0000)
Deadlock happened when listener for window is resized
and write is invoked at the same time.

Change-Id: I8c662d6cd5edbc3e36b31a754d826f79bec76434
Signed-off-by: Martin Sunal <msunal@frinx.io>
Signed-off-by: Jaroslav Tóth <jtoth@frinx.io>
(cherry picked from commit 0f45153d60a0fc71a08d011e21fdf5e83c174290)

netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java

index f35372742e9b3aa7f4c54bc6fe6fd05dbab71be9..e05408551f065bdb151e0306e6c51f3100734377 100644 (file)
@@ -21,6 +21,7 @@ import org.apache.sshd.common.io.IoOutputStream;
 import org.apache.sshd.common.io.WritePendingException;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,6 +51,9 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
         this.asyncIn = asyncIn;
     }
 
+    @GuardedBy("asyncInLock")
+    private boolean isWriteExecuted = false;
+
     public void write(final ChannelHandlerContext ctx,
             final Object msg, final ChannelPromise promise) {
         if (asyncIn == null) {
@@ -67,7 +71,7 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
                 promise.setFailure(new IllegalStateException("Channel closed"));
             } else {
                 final ByteBuf byteBufMsg = (ByteBuf) msg;
-                if (!pending.isEmpty()) {
+                if (isWriteExecuted) {
                     queueRequest(ctx, byteBufMsg, promise);
                     return;
                 }
@@ -86,6 +90,9 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
             if (LOG.isTraceEnabled()) {
                 LOG.trace("Writing request on channel: {}, message: {}", ctx.channel(), byteBufToString(byteBufMsg));
             }
+
+            isWriteExecuted = true;
+
             asyncIn.writePacket(toBuffer(byteBufMsg)).addListener(future -> {
                 // synchronized block due to deadlock that happens on ssh window resize
                 // writes and pending writes would lock the underlyinch channel session
@@ -133,6 +140,7 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
     private void writePendingIfAny() {
         synchronized (asyncInLock) {
             if (pending.peek() == null) {
+                isWriteExecuted = false;
                 return;
             }