8169519: JShell: Handle start-up failures and hangs gracefully
authorrfield
Tue, 22 Nov 2016 19:24:02 -0800
changeset 42272 82e273c4f2b3
parent 42271 2537564a3031
child 42273 ee07db0e65a3
8169519: JShell: Handle start-up failures and hangs gracefully 8166581: JShell: locks forever if -R options is wrong 8169234: JShell: hangs on startup on some computers caused by hostname Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java
langtools/test/jdk/jshell/DyingRemoteAgent.java
langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java
langtools/test/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java
langtools/test/jdk/jshell/FailOverExecutionControlHangingListenTest.java
langtools/test/jdk/jshell/HangingRemoteAgent.java
langtools/test/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java
langtools/test/jdk/jshell/JdiBadOptionListenExecutionControlTest.java
langtools/test/jdk/jshell/JdiBogusHostListenExecutionControlTest.java
langtools/test/jdk/jshell/JdiFailingLaunchExecutionControlTest.java
langtools/test/jdk/jshell/JdiFailingListenExecutionControlTest.java
langtools/test/jdk/jshell/JdiHangingLaunchExecutionControlTest.java
langtools/test/jdk/jshell/JdiHangingListenExecutionControlTest.java
langtools/test/jdk/jshell/StartOptionTest.java
langtools/test/jdk/jshell/UserJdiUserRemoteTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue Nov 22 19:24:02 2016 -0800
@@ -719,11 +719,11 @@
 
     /**
      * If there are classes to load, loads by calling the execution engine.
-     * @param classbytecoes names of the classes to load.
+     * @param classbytecodes names of the classes to load.
      */
-    private void load(Collection<ClassBytecodes> classbytecoes) {
-        if (!classbytecoes.isEmpty()) {
-            ClassBytecodes[] cbcs = classbytecoes.toArray(new ClassBytecodes[classbytecoes.size()]);
+    private void load(Collection<ClassBytecodes> classbytecodes) {
+        if (!classbytecodes.isEmpty()) {
+            ClassBytecodes[] cbcs = classbytecodes.toArray(new ClassBytecodes[classbytecodes.size()]);
             try {
                 state.executionControl().load(cbcs);
                 state.classTracker.markLoaded(cbcs);
@@ -731,6 +731,7 @@
                 state.classTracker.markLoaded(cbcs, ex.installed());
             } catch (NotImplementedException ex) {
                 state.debug(ex, "Seriously?!? load not implemented");
+                state.closeDown();
             } catch (EngineTerminationException ex) {
                 state.closeDown();
             }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Tue Nov 22 19:24:02 2016 -0800
@@ -30,6 +30,7 @@
 import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.PrintStream;
+import java.net.InetAddress;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -92,7 +93,6 @@
     final BiFunction<Snippet, Integer, String> idGenerator;
     final List<String> extraRemoteVMOptions;
     final List<String> extraCompilerOptions;
-    final ExecutionControl.Generator executionControlGenerator;
 
     private int nextKeyIndex = 1;
 
@@ -102,13 +102,13 @@
     private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>();
     private boolean closed = false;
 
-    private ExecutionControl executionControl = null;
+    private final ExecutionControl executionControl;
     private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
 
     private static final String L10N_RB_NAME    = "jdk.jshell.resources.l10n";
     private static ResourceBundle outputRB  = null;
 
-    JShell(Builder b) {
+    JShell(Builder b) throws IllegalStateException {
         this.in = b.in;
         this.out = b.out;
         this.err = b.err;
@@ -116,11 +116,18 @@
         this.idGenerator = b.idGenerator;
         this.extraRemoteVMOptions = b.extraRemoteVMOptions;
         this.extraCompilerOptions = b.extraCompilerOptions;
-        this.executionControlGenerator = b.executionControlGenerator==null
-                ? failOverExecutionControlGenerator(JdiDefaultExecutionControl.launch(),
-                        JdiDefaultExecutionControl.listen("localhost"),
-                        JdiDefaultExecutionControl.listen(null))
+        ExecutionControl.Generator executionControlGenerator = b.executionControlGenerator==null
+                ? failOverExecutionControlGenerator(
+                        JdiDefaultExecutionControl.listen(InetAddress.getLoopbackAddress().getHostAddress()),
+                        JdiDefaultExecutionControl.launch(),
+                        JdiDefaultExecutionControl.listen(null)
+                  )
                 : b.executionControlGenerator;
+        try {
+            executionControl = executionControlGenerator.generate(new ExecutionEnvImpl());
+        } catch (Throwable ex) {
+            throw new IllegalStateException("Launching JShell execution engine threw: " + ex.getMessage(), ex);
+        }
 
         this.maps = new SnippetMaps(this);
         this.keyMap = new KeyMap(this);
@@ -331,9 +338,10 @@
          * functionality. This creates a remote process for execution. It is
          * thus important to close the returned instance.
          *
+         * @throws IllegalStateException if the {@code JShell} instance could not be created.
          * @return the state engine
          */
-        public JShell build() {
+        public JShell build() throws IllegalStateException {
             return new JShell(this);
         }
     }
@@ -345,9 +353,10 @@
      * That is, create an instance of {@code JShell}.
      * <p>
      * Equivalent to {@link JShell#builder() JShell.builder()}{@link JShell.Builder#build() .build()}.
+     * @throws IllegalStateException if the {@code JShell} instance could not be created.
      * @return an instance of {@code JShell}.
      */
-    public static JShell create() {
+    public static JShell create() throws IllegalStateException {
         return builder().build();
     }
 
@@ -458,6 +467,7 @@
      * Note that the unnamed package is not accessible from the package in which
      * {@link JShell#eval(String)} code is placed.
      * @param path the path to add to the classpath.
+     * @throws IllegalStateException if this {@code JShell} instance is closed.
      */
     public void addToClasspath(String path) {
         // Compiler
@@ -504,7 +514,11 @@
     public void close() {
         if (!closed) {
             closeDown();
-            executionControl().close();
+            try {
+                executionControl().close();
+            } catch (Throwable ex) {
+                // don't care about exceptions on close
+            }
             if (sourceCodeAnalysis != null) {
                 sourceCodeAnalysis.close();
             }
@@ -733,14 +747,8 @@
     }
 
     // --- private / package-private implementation support ---
+
     ExecutionControl executionControl() {
-        if (executionControl == null) {
-            try {
-                executionControl =  executionControlGenerator.generate(new ExecutionEnvImpl());
-            } catch (Throwable ex) {
-                throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex);
-            }
-        }
         return executionControl;
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java	Tue Nov 22 19:24:02 2016 -0800
@@ -63,7 +63,10 @@
  */
 public class JdiDefaultExecutionControl extends JdiExecutionControl {
 
-    private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName();
+    /**
+     * Default time-out expressed in milliseconds.
+     */
+    private static final int DEFAULT_TIMEOUT = 5000;
 
     private VirtualMachine vm;
     private Process process;
@@ -73,24 +76,60 @@
 
     /**
      * Creates an ExecutionControl instance based on a JDI
-     * {@code LaunchingConnector}.
+     * {@code LaunchingConnector}. Same as
+     * {@code JdiDefaultExecutionControl.create(defaultRemoteAgent(), true, null, defaultTimeout())}.
      *
      * @return the generator
      */
     public static ExecutionControl.Generator launch() {
-        return env -> create(env, true, null);
+        return create(defaultRemoteAgent(), true, null, defaultTimeout());
     }
 
     /**
      * Creates an ExecutionControl instance based on a JDI
-     * {@code ListeningConnector}.
+     * {@code ListeningConnector}. Same as
+     * {@code JdiDefaultExecutionControl.create(defaultRemoteAgent(), false, host, defaultTimeout())}.
      *
      * @param host explicit hostname to use, if null use discovered
      * hostname, applies to listening only (!isLaunch)
      * @return the generator
      */
     public static ExecutionControl.Generator listen(String host) {
-        return env -> create(env, false, host);
+        return create(defaultRemoteAgent(), false, host, defaultTimeout());
+    }
+
+    /**
+     * Creates a JDI based ExecutionControl instance.
+     *
+     * @param remoteAgent the remote agent to launch
+     * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
+     * otherwise we start explicitly and use ListeningConnector
+     * @param host explicit hostname to use, if null use discovered
+     * hostname, applies to listening only (!isLaunch)
+     * @param timeout the start-up time-out in milliseconds
+     * @return the generator
+     */
+    public static ExecutionControl.Generator create(String remoteAgent,
+            boolean isLaunch, String host, int timeout) {
+        return env -> create(env, remoteAgent, isLaunch, host, timeout);
+    }
+
+    /**
+     * Default remote agent.
+     *
+     * @return the name of the standard remote agent
+     */
+    public static String defaultRemoteAgent() {
+        return RemoteExecutionControl.class.getName();
+    }
+
+    /**
+     * Default remote connection time-out
+     *
+     * @return time to wait for connection before failing, expressed in milliseconds.
+     */
+    public static int defaultTimeout() {
+        return DEFAULT_TIMEOUT;
     }
 
     /**
@@ -103,6 +142,7 @@
      *
      * @param env the context passed by
      * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
+     * @param remoteAgent the remote agent to launch
      * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
      * otherwise we start explicitly and use ListeningConnector
      * @param host explicit hostname to use, if null use discovered
@@ -110,16 +150,16 @@
      * @return the channel
      * @throws IOException if there are errors in set-up
      */
-    private static ExecutionControl create(ExecutionEnv env,
-            boolean isLaunch, String host) throws IOException {
+    private static ExecutionControl create(ExecutionEnv env, String remoteAgent,
+            boolean isLaunch, String host, int timeout) throws IOException {
         try (final ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) {
-            // timeout after 60 seconds
-            listener.setSoTimeout(60000);
+            // timeout on I/O-socket
+            listener.setSoTimeout(timeout);
             int port = listener.getLocalPort();
 
             // Set-up the JDI connection
             JdiInitiator jdii = new JdiInitiator(port,
-                    env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch, host);
+                    env.extraRemoteVMOptions(), remoteAgent, isLaunch, host, timeout);
             VirtualMachine vm = jdii.vm();
             Process process = jdii.process();
 
@@ -197,7 +237,7 @@
                 for (ThreadReference thread : vm().allThreads()) {
                     // could also tag the thread (e.g. using name), to find it easier
                     for (StackFrame frame : thread.frames()) {
-                        if (REMOTE_AGENT.equals(frame.location().declaringType().name()) &&
+                        if (defaultRemoteAgent().equals(frame.location().declaringType().name()) &&
                                 (    "invoke".equals(frame.location().method().name())
                                 || "varValue".equals(frame.location().method().name()))) {
                             ObjectReference thiz = frame.thisObject();
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java	Tue Nov 22 19:24:02 2016 -0800
@@ -25,6 +25,7 @@
 package jdk.jshell.execution;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -35,6 +36,13 @@
 import com.sun.jdi.connect.Connector;
 import com.sun.jdi.connect.LaunchingConnector;
 import com.sun.jdi.connect.ListeningConnector;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import com.sun.jdi.connect.IllegalConnectorArgumentsException;
 
 /**
  * Sets up a JDI connection, providing the resulting JDI {@link VirtualMachine}
@@ -42,6 +50,12 @@
  */
 public class JdiInitiator {
 
+    // factor for the timeout on all of connect
+    private static final double CONNECT_TIMEOUT_FACTOR = 1.5;
+
+    // Over-all connect time-out
+    private final int connectTimeout;
+
     private VirtualMachine vm;
     private Process process = null;
     private final Connector connector;
@@ -58,10 +72,12 @@
      * otherwise we start explicitly and use ListeningConnector
      * @param host explicit hostname to use, if null use discovered
      * hostname, applies to listening only (!isLaunch)
+     * @param timeout the start-up time-out in milliseconds
      */
     public JdiInitiator(int port, List<String> remoteVMOptions, String remoteAgent,
-            boolean isLaunch, String host) {
+            boolean isLaunch, String host, int timeout) {
         this.remoteAgent = remoteAgent;
+        this.connectTimeout = (int) (timeout * CONNECT_TIMEOUT_FACTOR);
         String connectorName
                 = isLaunch
                         ? "com.sun.jdi.CommandLineLaunch"
@@ -74,8 +90,11 @@
                 = isLaunch
                         ? launchArgs(port, String.join(" ", remoteVMOptions))
                         : new HashMap<>();
-        if (host != null && !isLaunch) {
-            argumentName2Value.put("localAddress", host);
+        if (!isLaunch) {
+            argumentName2Value.put("timeout", ""+timeout);
+            if (host != null && !isLaunch) {
+                argumentName2Value.put("localAddress", host);
+            }
         }
         this.connectorArgs = mergeConnectorArgs(connector, argumentName2Value);
         this.vm = isLaunch
@@ -106,13 +125,12 @@
     private VirtualMachine launchTarget() {
         LaunchingConnector launcher = (LaunchingConnector) connector;
         try {
-            VirtualMachine new_vm = launcher.launch(connectorArgs);
+            VirtualMachine new_vm = timedVirtualMachineCreation(() -> launcher.launch(connectorArgs), null);
             process = new_vm.process();
             return new_vm;
-        } catch (Exception ex) {
-            reportLaunchFail(ex, "launch");
+        } catch (Throwable ex) {
+            throw reportLaunchFail(ex, "launch");
         }
-        return null;
     }
 
     /**
@@ -140,15 +158,52 @@
             ProcessBuilder pb = new ProcessBuilder(args);
             process = pb.start();
 
-            // Forward out, err, and in
             // Accept the connection from the remote agent
-            vm = listener.accept(connectorArgs);
-            listener.stopListening(connectorArgs);
+            vm = timedVirtualMachineCreation(() -> listener.accept(connectorArgs),
+                    () -> process.waitFor());
             return vm;
-        } catch (Exception ex) {
-            reportLaunchFail(ex, "listen");
+        } catch (Throwable ex) {
+            if (process != null) {
+                process.destroyForcibly();
+            }
+            throw reportLaunchFail(ex, "listen");
+        } finally {
+            try {
+                listener.stopListening(connectorArgs);
+            } catch (IOException | IllegalConnectorArgumentsException ex) {
+                // ignore
+            }
         }
-        return null;
+    }
+
+    VirtualMachine timedVirtualMachineCreation(Callable<VirtualMachine> creator,
+            Callable<Integer> processComplete) throws Exception {
+        VirtualMachine result;
+        ExecutorService executor = Executors.newCachedThreadPool(runnable -> {
+            Thread thread = Executors.defaultThreadFactory().newThread(runnable);
+            thread.setDaemon(true);
+            return thread;
+        });
+        try {
+            Future<VirtualMachine> future = executor.submit(creator);
+            if (processComplete != null) {
+                executor.submit(() -> {
+                    Integer i = processComplete.call();
+                    future.cancel(true);
+                    return i;
+                });
+            }
+
+            try {
+                result = future.get(connectTimeout, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException ex) {
+                future.cancel(true);
+                throw ex;
+            }
+        } finally {
+            executor.shutdownNow();
+        }
+        return result;
     }
 
     private Connector findConnector(String name) {
@@ -194,8 +249,10 @@
         return argumentName2Value;
     }
 
-    private void reportLaunchFail(Exception ex, String context) {
-        throw new InternalError("Failed remote " + context + ": " + connector +
+    private InternalError reportLaunchFail(Throwable ex, String context) {
+        return new InternalError("Failed remote " + context + ": "
+                + ex.toString()
+                + " @ " + connector +
                 " -- " + connectorArgs, ex);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/DyingRemoteAgent.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.jshell.JShell;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import jdk.jshell.execution.RemoteExecutionControl;
+import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
+
+class DyingRemoteAgent extends RemoteExecutionControl {
+
+    static final boolean INFRA_VERIFY = false;
+
+    public static void main(String[] args) throws Exception {
+        if (INFRA_VERIFY) {
+            RemoteExecutionControl.main(args);
+        } else {
+            System.exit(1);
+        }
+    }
+
+    static JShell state(boolean isLaunch, String host) {
+        return JShell.builder().executionEngine(
+                JdiDefaultExecutionControl.create(
+                        DyingRemoteAgent.class.getName(),
+                        isLaunch,
+                        host,
+                        defaultTimeout())).build();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8131029 8160127 8159935 8169519
+ * @summary Test that fail-over works for fail-over ExecutionControl generators.
+ * @modules jdk.jshell/jdk.jshell.execution
+ *          jdk.jshell/jdk.jshell.spi
+ * @build KullaTesting ExecutionControlTestBase
+ * @run testng FailOverExecutionControlDyingLaunchTest
+ */
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
+
+@Test
+public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTestBase {
+
+    @BeforeMethod
+    @Override
+    public void setUp() {
+        setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
+                JdiDefaultExecutionControl.create(
+                        DyingRemoteAgent.class.getName(),
+                        true,
+                        null,
+                        defaultTimeout()),
+                JdiDefaultExecutionControl.launch())));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8131029 8160127 8159935 8169519
+ * @summary Test that fail-over works for fail-over ExecutionControl generators.
+ * @modules jdk.jshell/jdk.jshell.execution
+ *          jdk.jshell/jdk.jshell.spi
+ * @build KullaTesting ExecutionControlTestBase
+ * @run testng FailOverExecutionControlHangingLaunchTest
+ */
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
+
+@Test
+public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlTestBase {
+
+    @BeforeMethod
+    @Override
+    public void setUp() {
+        setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
+                JdiDefaultExecutionControl.create(
+                        HangingRemoteAgent.class.getName(),
+                        true,
+                        null,
+                        defaultTimeout()),
+                JdiDefaultExecutionControl.launch())));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/FailOverExecutionControlHangingListenTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8131029 8160127 8159935 8169519
+ * @summary Test that fail-over works for fail-over ExecutionControl generators.
+ * @modules jdk.jshell/jdk.jshell.execution
+ *          jdk.jshell/jdk.jshell.spi
+ * @build KullaTesting ExecutionControlTestBase
+ * @run testng FailOverExecutionControlHangingListenTest
+ */
+
+import java.net.InetAddress;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
+
+@Test
+public class FailOverExecutionControlHangingListenTest extends ExecutionControlTestBase {
+
+    @BeforeMethod
+    @Override
+    public void setUp() {
+        String loopback = InetAddress.getLoopbackAddress().getHostAddress();
+        setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
+                JdiDefaultExecutionControl.create(
+                        HangingRemoteAgent.class.getName(),
+                        false,
+                        loopback,
+                        defaultTimeout()),
+                JdiDefaultExecutionControl.listen(loopback))));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/HangingRemoteAgent.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.jshell.JShell;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import jdk.jshell.execution.RemoteExecutionControl;
+
+/**
+ * Hang for three minutes (long enough to cause a timeout).
+ */
+class HangingRemoteAgent extends RemoteExecutionControl {
+
+    private static final long DELAY = 4000L;
+    private static final int TIMEOUT = 2000;
+    private static final boolean INFRA_VERIFY = false;
+
+    public static void main(String[] args) throws Exception {
+        if (INFRA_VERIFY) {
+            RemoteExecutionControl.main(args);
+        } else {
+            long end = System.currentTimeMillis() + DELAY;
+            long remaining;
+            while ((remaining = end - System.currentTimeMillis()) > 0L) {
+                try {
+                    Thread.sleep(remaining);
+                } catch (InterruptedException ex) {
+                    // loop again
+                }
+            }
+        }
+    }
+
+    static JShell state(boolean isLaunch, String host) {
+        return JShell.builder().executionEngine(
+                JdiDefaultExecutionControl.create(
+                        HangingRemoteAgent.class.getName(),
+                        isLaunch,
+                        host,
+                        TIMEOUT)).build();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519 8166581
+ * @summary Tests for JDI connector failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @run testng JdiBadOptionLaunchExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import jdk.jshell.JShell;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiBadOptionLaunchExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Failed remote launch: java.util.concurrent.ExecutionException: com.sun.jdi.connect.VMStartException: VM initialization failed";
+
+    public void badOptionLaunchTest() {
+        try {
+            JShell.builder()
+                    .executionEngine(JdiDefaultExecutionControl.launch())
+                    .remoteVMOptions("-BadBadOption")
+                    .build();
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiBadOptionListenExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519 8166581
+ * @summary Tests for JDI connector failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @run testng JdiBadOptionListenExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import jdk.jshell.JShell;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiBadOptionListenExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Failed remote listen:";
+
+    public void badOptionListenTest() {
+        try {
+            JShell.builder()
+                    .executionEngine(JdiDefaultExecutionControl.listen(null))
+                    .remoteVMOptions("-BadBadOption")
+                    .build();
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiBogusHostListenExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519
+ * @summary Tests for JDI connector failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @run testng JdiBogusHostListenExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import jdk.jshell.JShell;
+import jdk.jshell.execution.JdiDefaultExecutionControl;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiBogusHostListenExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Failed remote listen: java.net.SocketException: Unresolved address @ com.sun.jdi.SocketListe";
+
+    public void badOptionListenTest() {
+        try {
+            JShell.builder()
+                    .executionEngine(JdiDefaultExecutionControl.listen("BattyRumbleBuckets-Snurfle-99-Blip"))
+                    .build();
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiFailingLaunchExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519
+ * @summary Tests for JDI connector failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @build DyingRemoteAgent
+ * @run testng JdiFailingLaunchExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiFailingLaunchExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Accept timed out";
+
+    public void failLaunchTest() {
+        try {
+            System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;"));
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiFailingListenExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519
+ * @summary Tests for JDI connector failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @build DyingRemoteAgent
+ * @run testng JdiFailingListenExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiFailingListenExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Accept timed out";
+
+    public void failListenTest() {
+        try {
+            System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;"));
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiHangingLaunchExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519
+ * @summary Tests for JDI connector timeout failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @build HangingRemoteAgent
+ * @run testng JdiHangingLaunchExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiHangingLaunchExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Accept timed out";
+
+    public void hangLaunchTimeoutTest() {
+        try {
+            System.err.printf("Unexpected return value: %s\n",
+                    HangingRemoteAgent.state(true, null).eval("33;"));
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/JdiHangingListenExecutionControlTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169519
+ * @summary Tests for JDI connector timeout failure
+ * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
+ * @build HangingRemoteAgent
+ * @run testng JdiHangingListenExecutionControlTest
+ */
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test
+public class JdiHangingListenExecutionControlTest {
+
+    private static final String EXPECTED_ERROR =
+            "Launching JShell execution engine threw: Accept timed out";
+
+    public void hangListenTimeoutTest() {
+        try {
+            System.err.printf("Unexpected return value: %s\n",
+                    HangingRemoteAgent.state(false, null).eval("33;"));
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+}
--- a/langtools/test/jdk/jshell/StartOptionTest.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/test/jdk/jshell/StartOptionTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test 8151754 8080883 8160089
+ * @test 8151754 8080883 8160089 8166581
  * @summary Testing start-up options.
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -48,6 +48,7 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 @Test
 public class StartOptionTest {
@@ -135,6 +136,17 @@
         start("", "Argument to startup missing.", "--no-startup", "--startup");
     }
 
+    public void testStartupFailedOption() throws Exception {
+        try {
+            start("", "", "-R-hoge-foo-bar");
+        } catch (IllegalStateException ex) {
+            String s = ex.getMessage();
+            assertTrue(s.startsWith("Launching JShell execution engine threw: Failed remote"), s);
+            return;
+        }
+        fail("Expected IllegalStateException");
+    }
+
     public void testStartupUnknown() throws Exception {
         start("", "File 'UNKNOWN' for '--startup' is not found.", "--startup", "UNKNOWN");
     }
--- a/langtools/test/jdk/jshell/UserJdiUserRemoteTest.java	Tue Nov 22 16:31:03 2016 -0800
+++ b/langtools/test/jdk/jshell/UserJdiUserRemoteTest.java	Tue Nov 22 19:24:02 2016 -0800
@@ -118,6 +118,7 @@
 class MyExecutionControl extends JdiExecutionControl {
 
     private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName();
+    private static final int TIMEOUT = 2000;
 
     private VirtualMachine vm;
     private Process process;
@@ -147,8 +148,8 @@
      */
     static ExecutionControl make(ExecutionEnv env, UserJdiUserRemoteTest test) throws IOException {
         try (final ServerSocket listener = new ServerSocket(0)) {
-            // timeout after 60 seconds
-            listener.setSoTimeout(60000);
+            // timeout for socket
+            listener.setSoTimeout(TIMEOUT);
             int port = listener.getLocalPort();
 
             // Set-up the JDI connection
@@ -158,7 +159,7 @@
                     + System.getProperty("path.separator")
                     + System.getProperty("user.dir"));
             JdiInitiator jdii = new JdiInitiator(port,
-                    opts, REMOTE_AGENT, true, null);
+                    opts, REMOTE_AGENT, true, null, TIMEOUT);
             VirtualMachine vm = jdii.vm();
             Process process = jdii.process();