Skip to content

Commit 620bbd0

Browse files
committed
Retry launching in AbstractDebugTest on BindException
Debug tests infrequently run into: java.net.BindException: Address already in use This can occur when the chosen debug port is in use. The port is chosen in StandardVMDebugger.getCommandLine(), delegating to SocketUtil.findFreePort(): try (ServerSocket socket = new ServerSocket(0)) { return socket.getLocalPort(); } Which can result in the socket being in use, at the time of the launch. This change adds 3 retries to the launch, in case of BindException. Fixes: #940
1 parent db4f441 commit 620bbd0

1 file changed

Lines changed: 25 additions & 9 deletions

File tree

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.File;
2020
import java.io.PrintWriter;
2121
import java.io.StringWriter;
22+
import java.net.BindException;
2223
import java.util.ArrayList;
2324
import java.util.Arrays;
2425
import java.util.Collection;
@@ -177,6 +178,7 @@
177178
@SuppressWarnings("deprecation")
178179
public abstract class AbstractDebugTest extends TestCase implements IEvaluationListener {
179180

181+
private static final int SOCKET_BIND_ERROR_MAX_RETRIES = 3;
180182
private static boolean setupFirstTest = false;
181183

182184
public static final String MULTI_OUTPUT_PROJECT_NAME = "MultiOutput";
@@ -1490,13 +1492,7 @@ protected Object launchAndWait(ILaunchConfiguration configuration, DebugEventWai
14901492
* if the event is never received.
14911493
*/
14921494
protected Object launchAndWait(ILaunchConfiguration configuration, String mode, DebugEventWaiter waiter, boolean register) throws CoreException {
1493-
ILaunch launch;
1494-
try {
1495-
launch = configuration.launch(mode, new TimeoutMonitor(DEFAULT_TIMEOUT), false, register);
1496-
} catch (Throwable t) {
1497-
logProcessConsoleContents();
1498-
throw t;
1499-
}
1495+
ILaunch launch = launchConfig(configuration, mode, register);
15001496
Object suspendee= waiter.waitForEvent();
15011497
if (suspendee == null) {
15021498
StringBuilder buf = new StringBuilder();
@@ -1539,8 +1535,6 @@ protected Object launchAndWait(ILaunchConfiguration configuration, String mode,
15391535
return suspendee;
15401536
}
15411537

1542-
1543-
15441538
/**
15451539
* Launches the type with the given name, and waits for a
15461540
* suspend event in that program. Returns the thread in which the suspend
@@ -3224,6 +3218,28 @@ private static void logVMChange(String message, IVMInstall vm) {
32243218
JDIDebugPlugin.log(status);
32253219
}
32263220

3221+
private static ILaunch launchConfig(ILaunchConfiguration configuration, String mode, boolean register) throws CoreException {
3222+
ILaunch launch = null;
3223+
for (int retry = 1; retry <= SOCKET_BIND_ERROR_MAX_RETRIES; ++retry) {
3224+
try {
3225+
launch = configuration.launch(mode, new TimeoutMonitor(DEFAULT_TIMEOUT), false, register);
3226+
break;
3227+
} catch (CoreException e) {
3228+
Throwable cause = e.getStatus().getException();
3229+
if (retry < SOCKET_BIND_ERROR_MAX_RETRIES && cause instanceof BindException) {
3230+
// port might be in use between checking for a free port and launching, try a few times
3231+
DebugPlugin.log(Status.error("Could not bind socket for debugging, retry: " + retry, e));
3232+
} else {
3233+
throw e;
3234+
}
3235+
} catch (Throwable t) {
3236+
logProcessConsoleContents();
3237+
throw t;
3238+
}
3239+
}
3240+
return launch;
3241+
}
3242+
32273243
private static void logProcessConsoleContents() {
32283244
try {
32293245
StringBuilder buf = new StringBuilder();

0 commit comments

Comments
 (0)