Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java
41161 views
/*1* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.share.jpda;2425import nsk.share.*;26import java.io.*;27import java.net.*;2829/**30* This class is used to control debugee VM process.31* <p>32* Object of this class is constructed by <code>DebugeeBinder</code>33* and is used as a mirror of debugee VM process.34* It provides abilities to launch such process,35* redirect standard output streams, wait for process terminates36* or kill the process, and so on.37* <p>38* This is an abstract class that declares abstract methods to control39* debugee VM process.40* Derived classes should implement these methods corresponding to the mode41* that the process should be started in (locally, remotely or manually).42* <p>43* Particular derived classes <code>nsk.share.jdi.Debugee</code> and44* <code>nsk.share.jdwp.Debugee</code> provides additional abilities45* to control debugee VM using JDI or JDWP specific features.46*47* @see DebugeeBinder48*49* @see nsk.share.jdi.Debugee50* @see nsk.share.jdwp.Debugee51*/52abstract public class DebugeeProcess extends FinalizableObject {5354/** Default prefix for log messages. */55public static final String LOG_PREFIX = "binder> ";56public static final String DEBUGEE_STDOUT_LOG_PREFIX = "debugee.stdout> ";57public static final String DEBUGEE_STDERR_LOG_PREFIX = "debugee.stderr> ";5859/** Messages prefix. */60protected String prefix = LOG_PREFIX;6162/** Binder that creates this debugee process. */63protected DebugeeBinder binder = null;6465/** Messages log from binder. */66protected Log log = null;6768/** Communicational channel between debuger and debugee. */69protected IOPipe pipe = null;7071/** Argument handler from binder. */72protected DebugeeArgumentHandler argumentHandler = null;7374/** Need or not to check debuggee process termination at exit. */75protected boolean checkTermination = false;7677/** Debugee VM process or <i>null</i> if not available. */78protected Process process = null;7980/** Make new <code>Debugee</code> object for the given binder. */81protected DebugeeProcess (DebugeeBinder binder) {82this.binder = binder;83this.log = binder.getLog();84}8586/**87* Return already bound ServerSocket for IOPipe connection or null.88*/89protected ServerSocket getPipeServerSocket() {90return binder.getPipeServerSocket();91}9293/** Return <code>DebugeeArgumentHandler</code> of the debugee object. */94public DebugeeArgumentHandler getArgumentHandler() {95return binder.getArgumentHandler();96}9798/** Return <code>Log</code> of the debugee object. */99public Log getLog() {100return log;101}102103/** Return <code>Process</code> object associated with debugee VM or <i>null</i>. */104public Process getProcess() {105return process;106}107108// --------------------------------------------------- //109110/** Created and return new IOPipe channel to the debugee VM. */111public IOPipe createIOPipe() {112if (pipe != null) {113throw new TestBug("IOPipe channel is already created");114}115pipe = new IOPipe(this);116return pipe;117}118119/** Return IOPipe channel or null if not yet ctreated. */120public IOPipe getIOPipe() {121return pipe;122}123124/** Receive and return signal from the debugee VM via IOPipe channel.125*126* @throws TestBug if IOPipe channel is not created127*/128public String receiveSignal() {129if ( pipe == null )130throw new TestBug("IOPipe channel is not initialized");131return pipe.readln();132}133134/** Receive an expected <code>signal</code> from the debugee VM via IOPipe channel.135*136* @throws Failure if received signal is not equal to the expected one137* @throws TestBug if IOPipe channel is not created138*/139public void receiveExpectedSignal(String signal) {140String line = receiveSignal();141if (line == null || !line.equals(signal))142throw new Failure("Received unexpected signal from debugee: " + line);143display("Received expected signal from debugee: " + signal);144}145146/** Send <code>signal</code> to the debugee VM via IOPipe channel.147*148* @throws TestBug if IOPipe channel is not defined created.149*/150public void sendSignal(String signal) {151if (pipe == null)152throw new TestBug("IOPipe channel is not initialized");153pipe.println(signal);154}155156157// --------------------------------------------------- //158159/** Wait until the debugee VM shutdown or crash. */160abstract protected int waitForDebugee () throws InterruptedException;161162/** Kill the debugee VM. */163abstract protected void killDebugee ();164165/** Check whether the debugee VM has been terminated. */166abstract public boolean terminated ();167168/** Return the debugee VM exit status. */169abstract public int getStatus ();170171/** Get a pipe to write to the debugee's stdin stream. */172abstract protected OutputStream getInPipe ();173174/** Get a pipe to read the debugee's stdout stream. */175abstract protected InputStream getOutPipe ();176177/** Get a pipe to read the debugee's stderr stream. */178abstract protected InputStream getErrPipe ();179180// --------------------------------------------------- //181182/**183* Wait until the debugee VM shutdown or crash,184* and let finish its stdout, stderr, and stdin185* redirectors (if any).186*187* @return Debugee process exit code.188* @see #waitForRedirectors(long)189*/190public int waitFor () {191long timeout = binder.getArgumentHandler().getWaitTime() * 60 * 1000;192int exitCode = 0;193try {194exitCode = waitForDebugee();195} catch (InterruptedException ie) {196ie.printStackTrace(log.getOutStream());197throw new Failure("Caught exception while waiting for debuggee process: \n\t" + ie);198}199waitForRedirectors(timeout);200if (process != null) {201process.destroy();202}203return exitCode;204}205206/**207* Wait until the debugee VM redirectors to complete for specified <code>timeout</code>.208*209* @see #waitFor()210*/211public void waitForRedirectors (long timeout) {212try {213if (stdinRedirector != null) {214if (stdinRedirector.isAlive()) {215stdinRedirector.join(timeout);216if (stdinRedirector.isAlive()) {217log.complain("Timeout for waiting STDIN redirector exceeded");218stdinRedirector.interrupt();219}220}221stdinRedirector = null;222};223if (stdoutRedirector != null) {224if (stdoutRedirector.isAlive()) {225stdoutRedirector.join(timeout);226if (stdoutRedirector.isAlive()) {227log.complain("Timeout for waiting STDOUT redirector exceeded");228stdoutRedirector.interrupt();229}230}231stdoutRedirector = null;232};233if (stderrRedirector != null) {234if (stderrRedirector.isAlive()) {235stderrRedirector.join(timeout);236if (stderrRedirector.isAlive()) {237log.complain("Timeout for waiting STDERR redirector exceeded");238stderrRedirector.interrupt();239}240}241stderrRedirector = null;242};243} catch (InterruptedException ie) {244ie.printStackTrace(log.getOutStream());245throw new Failure("Caught exception while waiting for debuggee output redirectors: \n\t"246+ ie);247}248}249250// --------------------------------------------------- //251252/**253* Get a pipe to write to the debugee's stdin stream,254* or throw TestBug exception is redirected.255*/256final public OutputStream getStdin () {257if (stdinRedirector != null)258throw new TestBug("Debugee's stdin is redirected");259return getInPipe();260}261262/**263* Get a pipe to read the debugee's stdout stream,264* or throw TestBug exception is redirected.265*/266final public InputStream getStdout () {267if (stdoutRedirector != null)268throw new TestBug("Debugee's stdout is redirected");269return getOutPipe();270}271272/**273* Get a pipe to read the debugee's stderr stream,274* or throw TestBug exception is redirected.275*/276final public InputStream getStderr () {277if (stderrRedirector != null)278throw new TestBug("Debugee's stderr is redirected");279return getErrPipe();280}281282// --------------------------------------------------- //283284private IORedirector stdoutRedirector = null;285private IORedirector stderrRedirector = null;286private IORedirector stdinRedirector = null;287288// /**289// * Start a thread redirecting the given <code>in</code> stream290// * to the debugee's stdin. If the debugee's stdin was already291// * redirected, the TestBug exception is thrown.292// */293// final public void redirectStdin(InputStream in) {294// if (stdinRedirector != null)295// throw new TestBug("the debugee's stdin is already redirected");296// stdinRedirector = new IORedirector(in,getInPipe());297// stdinRedirector.setName("IORedirector for stdin");298// stdinRedirector.setDaemon(true);299// stdinRedirector.start();300// }301302/**303* Start thread redirecting the debugee's stdout to the304* given <code>out</code> stream. If the debugee's stdout305* was already redirected, the TestBug exception is thrown.306*307* @deprecated Use redirectStdout(Log, String) instead.308*/309@Deprecated310public void redirectStdout(OutputStream out) {311if (stdoutRedirector != null) {312return;313}314// throw new TestBug("Debugee's stdout is already redirected");315stdoutRedirector = new IORedirector(getOutPipe(),out);316stdoutRedirector.setPrefix(DEBUGEE_STDOUT_LOG_PREFIX);317stdoutRedirector.setName("IORedirector for stdout");318stdoutRedirector.setDaemon(true);319stdoutRedirector.start();320}321322/**323* Start thread redirecting the debugee's stdout to the324* given <code>Log</code>. If the debugee's stdout325* was already redirected, the TestBug exception is thrown.326*/327public void redirectStdout(Log log, String prefix) {328if (stdoutRedirector != null) {329// stdoutRedirector.setPrefix(prefix);330return;331// throw new TestBug("the debugee's stdout is already redirected");332}333stdoutRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getOutPipe())), log, prefix);334stdoutRedirector.setName("IORedirector for stdout");335stdoutRedirector.setDaemon(true);336stdoutRedirector.start();337}338339/**340* Start thread redirecting the debugee's stderr to the341* given <code>err</code> stream. If the debugee's stderr342* was already redirected, the TestBug exception is thrown.343*344* @deprecated Use redirectStderr(Log, String) instead.345*/346@Deprecated347public void redirectStderr(OutputStream err) {348if (stderrRedirector != null) {349return;350}351// throw new TestBug("Debugee's stderr is already redirected");352stderrRedirector = new IORedirector(getErrPipe(),err);353stderrRedirector.setPrefix(DEBUGEE_STDERR_LOG_PREFIX);354stdoutRedirector.setName("IORedirector for stderr");355stderrRedirector.setDaemon(true);356stderrRedirector.start();357}358359/**360* Start thread redirecting the debugee's stderr to the361* given <code>Log</code>. If the debugee's stderr362* was already redirected, the TestBug exception is thrown.363*/364public void redirectStderr(Log log, String prefix) {365if (stderrRedirector != null) {366// stderrRedirector.setPrefix(prefix);367return;368// throw new TestBug("Debugee's stderr is already redirected");369}370stderrRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getErrPipe())), log, prefix);371stdoutRedirector.setName("IORedirector for stderr");372stderrRedirector.setDaemon(true);373stderrRedirector.start();374}375376/**377* Start thread redirecting the debugee's stdout/stderr to the378* given <code>Log</code> using standard prefixes.379* If the debugee's stdout/stderr were already redirected,380* the TestBug exception is thrown.381*/382public void redirectOutput(Log log) {383redirectStdout(log, "debugee.stdout> ");384redirectStderr(log, "debugee.stderr> ");385}386// --------------------------------------------------- //387388/**389* Kill the debugee VM if it is not terminated yet.390*391* @throws Throwable if any throwable exception is thrown during finalization392*/393public void close() {394if (checkTermination) {395if (!terminated()) {396complain("Debugee VM has not exited correctly: trying to kill it");397killDebugee();398}399checkTermination = false;400}401}402403// --------------------------------------------------- //404405/**406* Display log message with prefix.407*/408protected void display(String message) {409log.display(prefix + message);410}411412/**413* Complain about error with specified message.414*/415protected void complain(String message) {416log.complain(prefix + message);417}418419/**420* Finalize debuggee VM wrapper by invoking <code>close()</code>.421*422* @throws Throwable if any throwable exception is thrown during finalization423*/424protected void finalize() throws Throwable {425close();426super.finalize();427}428}429430431