From 96441d80a6b51d89a5278d81c0fb1e20753dcb5d Mon Sep 17 00:00:00 2001 From: Matthias Jaros Date: Sat, 5 Sep 2026 21:15:31 +0200 Subject: Improved performance of PortScanRateLimiter by sleeping outside of synchronized block. Potential carrier thread pinning through sleeping inside sync block is now being prevented --- .../jns/scan/engine/PortScanRateLimiter.java | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/it_jaros/jns/scan/engine/PortScanRateLimiter.java b/src/main/java/com/it_jaros/jns/scan/engine/PortScanRateLimiter.java index aa897a4..3411367 100644 --- a/src/main/java/com/it_jaros/jns/scan/engine/PortScanRateLimiter.java +++ b/src/main/java/com/it_jaros/jns/scan/engine/PortScanRateLimiter.java @@ -23,16 +23,29 @@ public class PortScanRateLimiter { if (delayInNanos <= 0) { return; } + + long deadlineNanos; synchronized (lock) { if (cancelledToken.isCancelled()) { return; } long now = System.nanoTime(); - if (nextAllowedTime > now) { - LockSupport.parkNanos(nextAllowedTime - now); - now = System.nanoTime(); // re-read after waking + if (nextAllowedTime <= now) { + // a slot is free: claim it and proceed immediately + nextAllowedTime = now + delayInNanos; + return; } - nextAllowedTime = now + delayInNanos; + // claim my slot now, wait for it later + deadlineNanos = nextAllowedTime; + nextAllowedTime += delayInNanos; + } + + // wait outside the lock so the thread is not blocked + // while holding the monitor (which would pin virtual threads) + LockSupport.parkNanos(Math.max(0, deadlineNanos - System.nanoTime())); + + if (cancelledToken.isCancelled()) { + return; } } } -- cgit v1.3.1-4-g156e