This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git


The following commit(s) were added to refs/heads/master by this push:
     new 5a9194bb9 Replace "synchronized" blocks in AbstractSession with 
ReentrantLock
5a9194bb9 is described below

commit 5a9194bb9bc86384d5303dcb6bd41c6f67ce9a42
Author: Evgenii Pasynkov <[email protected]>
AuthorDate: Fri Dec 12 18:12:04 2025 +0100

    Replace "synchronized" blocks in AbstractSession with ReentrantLock
    
    synchronized blocks pin the virtual thread under JDK21+ to physical thread. 
It is better to avoid such pinning in I/O bound operations so VirtualThread 
planner can do its job
---
 .../sshd/common/session/helpers/AbstractSession.java | 20 +++++++++++++++-----
 .../sshd/server/session/AbstractServerSession.java   |  5 ++++-
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
index 029808107..fd8784c4e 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
@@ -47,6 +47,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.LongConsumer;
 import java.util.logging.Level;
 import java.util.stream.Collectors;
@@ -196,8 +197,8 @@ public abstract class AbstractSession extends SessionHelper 
{
     protected int decoderState;
     protected int decoderLength;
     protected SshException discarding;
-    protected final Object encodeLock = new Object();
-    protected final Object decodeLock = new Object();
+    protected final ReentrantLock encodeLock = new ReentrantLock();
+    protected final ReentrantLock decodeLock = new ReentrantLock();
     protected final Object requestLock = new Object();
 
     /**
@@ -501,7 +502,8 @@ public abstract class AbstractSession extends SessionHelper 
{
      * @throws Exception if an error occurs while decoding or handling the data
      */
     public void messageReceived(Readable buffer) throws Exception {
-        synchronized (decodeLock) {
+        decodeLock.lock();
+        try {
             decoderBuffer.putBuffer(buffer);
             // One of those properties will be set by the constructor and the 
other
             // one should be set by the readIdentification method
@@ -513,6 +515,8 @@ public abstract class AbstractSession extends SessionHelper 
{
                 }
             }
             decode();
+        } finally {
+            decodeLock.unlock();
         }
     }
 
@@ -718,13 +722,16 @@ public abstract class AbstractSession extends 
SessionHelper {
         prepareNewKeys();
         Buffer buffer = createBuffer(SshConstants.SSH_MSG_NEWKEYS, Byte.SIZE);
         IoWriteFuture future;
-        synchronized (encodeLock) {
+        encodeLock.lock();
+        try {
             // writePacket() would also work since it would never try to queue 
the packet, and would never try to
             // initiate a new KEX, and thus would never try to get the kexLock 
monitor. If it did, we might get a
             // deadlock due to lock inversion. It seems safer to push this out 
directly, though.
             future = doWritePacket(buffer);
             // Use the new settings from now on for any outgoing packet
             setOutputEncoding();
+        } finally {
+            encodeLock.unlock();
         }
         kexHandler.updateState(() -> kexState.set(KexState.KEYS));
 
@@ -1169,11 +1176,14 @@ public abstract class AbstractSession extends 
SessionHelper {
         // Synchronize all write requests as needed by the encoding algorithm
         // and also queue the write request in this synchronized block to 
ensure
         // packets are sent in the correct order
-        synchronized (encodeLock) {
+        encodeLock.lock();
+        try {
             Buffer packet = resolveOutputPacket(buffer);
             IoSession networkSession = getIoSession();
             IoWriteFuture future = networkSession.writeBuffer(packet);
             return future;
+        } finally {
+            encodeLock.unlock();
         }
     }
 
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
index 25108ce7e..54c465ebb 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
@@ -317,7 +317,8 @@ public abstract class AbstractServerSession extends 
AbstractSession implements S
         Buffer response = createBuffer(SshConstants.SSH_MSG_USERAUTH_SUCCESS, 
Byte.SIZE);
         IoWriteFuture future;
         IoSession networkSession = getIoSession();
-        synchronized (encodeLock) {
+        encodeLock.lock();
+        try {
             Buffer packet = resolveOutputPacket(response);
 
             setUsername(username);
@@ -327,6 +328,8 @@ public abstract class AbstractServerSession extends 
AbstractSession implements S
 
             // Now we can inform the peer that authentication is successful
             future = networkSession.writeBuffer(packet);
+        } finally {
+            encodeLock.unlock();
         }
 
         resetIdleTimeout();

Reply via email to