--- /dev/null 2016-07-12 14:35:29.888302783 -0700 +++ new/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java 2016-07-12 22:46:58.570033327 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package jdk.jshell.execution; + +import java.lang.reflect.Method; +import java.net.Socket; + +import jdk.jshell.spi.ExecutionControl; +import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; + +/** + * The remote agent runs in the execution process (separate from the main JShell + * process). This agent loads code over a socket from the main JShell process, + * executes the code, and other misc, Specialization of + * {@link DirectExecutionControl} which adds stop support controlled by + * an external process. Designed to work with {@link JDIDefaultExecutionControl}. + * + * @author Jan Lahoda + * @author Robert Field + */ +public class RemoteExecutionControl extends DirectExecutionControl implements ExecutionControl { + + /** + * Launch the agent, connecting to the JShell-core over the socket specified + * in the command-line argument. + * + * @param args standard command-line arguments, expectation is the socket + * number is the only argument + * @throws Exception any unexpected exception + */ + public static void main(String[] args) throws Exception { + String loopBack = null; + Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); + forwardExecutionControlAndIO(new RemoteExecutionControl(), socket); + } + + // These three variables are used by the main JShell process in interrupting + // the running process. Access is via JDI, so the reference is not visible + // to code inspection. + private boolean inClientCode; // Queried by the main process (in superclass) + private boolean expectingStop; // Set by the main process +// Set by the main process + + // thrown by the main process via JDI: + private final StopExecutionException stopException = new StopExecutionException(); + + @Override + public void stop() throws EngineTerminationException, InternalException { + // handled by JDI + } + + // Overridden only so this stack frame is seen + @Override + protected String invoke(Method doitMethod) throws Exception { + return super.invoke(doitMethod); + } + + // Overridden only so this stack frame is seen + @Override + public String varValue(String className, String varName) throws RunException, EngineTerminationException, InternalException { + return super.varValue(className, varName); + } + + @Override + protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException { + if (cause instanceof StopExecutionException) { + expectingStop = false; + throw new StoppedException(); + } else { + return super.throwConvertedInvocationException(cause); + } + } + + @Override + protected String throwConvertedOtherException(Throwable ex) throws RunException, InternalException { + if (ex instanceof StopExecutionException || + ex.getCause() instanceof StopExecutionException) { + expectingStop = false; + throw new StoppedException(); + } + return super.throwConvertedOtherException(ex); + } + + @Override + protected void clientCodeEnter() { + expectingStop = false; + inClientCode = true; + } + + @Override + protected void clientCodeLeave() throws InternalException { + inClientCode = false; + while (expectingStop) { + try { + Thread.sleep(0); + } catch (InterruptedException ex) { + throw new InternalException("*** Sleep interrupted while waiting for stop exception: " + ex); + } + } + } + + @SuppressWarnings("serial") // serialVersionUID intentionally omitted + private class StopExecutionException extends ThreadDeath { + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + } + +}