From bb1a4e1e898a43c87dd968233df5c4bf1204b2cb Mon Sep 17 00:00:00 2001 From: Stefan Oehme Date: Fri, 19 Jul 2024 13:42:27 +0200 Subject: [PATCH] Fix daemon connection race condition (#1071) The Server was using a SynchrnousQueue to coordinate the main thread and the background thread that receives the request from the client. A SynchronousQueue only allows insertions when a corresponding call to `get` is in progress. However, since the receiver thread is started before the call to `get`, there was a short time window, where the call to `queue.offer` could fail and simply return `false`. This return code was ignored. A possible solution would have been to call `put` instead of `offer`, but I decided to replace the queue with a Future, since we only wait for a single element. --- .../src/main/java/org/mvndaemon/mvnd/daemon/Server.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java index 6d9586cf..9d95876b 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java @@ -37,11 +37,11 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -271,13 +271,13 @@ public class Server implements AutoCloseable, Runnable { try (DaemonConnection connection = new DaemonConnection(socket)) { LOGGER.info("Waiting for request"); - SynchronousQueue request = new SynchronousQueue<>(); + CompletableFuture request = new CompletableFuture<>(); new DaemonThread(() -> { Message message = connection.receive(); - request.offer(message); + request.complete(message); }) .start(); - Message message = request.poll(1, TimeUnit.MINUTES); + Message message = request.get(1, TimeUnit.MINUTES); if (message == null) { LOGGER.info("Could not receive request after one minute, dropping connection"); updateState(DaemonState.Idle);