Path: blob/master/src/jdk.jdi/share/classes/com/sun/tools/jdi/AbstractLauncher.java
41161 views
/*1* Copyright (c) 1999, 2017, 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. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.jdi;2627import java.io.IOException;28import java.io.InterruptedIOException;29import java.util.ArrayList;30import java.util.List;31import java.util.Map;32import java.util.StringTokenizer;3334import com.sun.jdi.Bootstrap;35import com.sun.jdi.InternalException;36import com.sun.jdi.VirtualMachine;37import com.sun.jdi.VirtualMachineManager;38import com.sun.jdi.connect.Connector;39import com.sun.jdi.connect.IllegalConnectorArgumentsException;40import com.sun.jdi.connect.LaunchingConnector;41import com.sun.jdi.connect.VMStartException;42import com.sun.jdi.connect.spi.Connection;43import com.sun.jdi.connect.spi.TransportService;4445abstract class AbstractLauncher extends ConnectorImpl46implements LaunchingConnector47{48abstract public VirtualMachine49launch(Map<String, ? extends Connector.Argument> arguments)50throws IOException, IllegalConnectorArgumentsException,51VMStartException;5253abstract public String name();5455abstract public String description();5657ThreadGroup grp;5859AbstractLauncher() {60super();6162grp = Thread.currentThread().getThreadGroup();63ThreadGroup parent = null;64while ((parent = grp.getParent()) != null) {65grp = parent;66}67}6869String[] tokenizeCommand(String command, char quote) {70String quoteStr = String.valueOf(quote); // easier to deal with7172/*73* Tokenize the command, respecting the given quote character.74*/75StringTokenizer tokenizer = new StringTokenizer(command,76quote + " \t\r\n\f",77true);78String quoted = null;79String pending = null;80List<String> tokenList = new ArrayList<>();81while (tokenizer.hasMoreTokens()) {82String token = tokenizer.nextToken();83if (quoted != null) {84if (token.equals(quoteStr)) {85tokenList.add(quoted);86quoted = null;87} else {88quoted += token;89}90} else if (pending != null) {91if (token.equals(quoteStr)) {92quoted = pending;93} else if ((token.length() == 1) &&94Character.isWhitespace(token.charAt(0))) {95tokenList.add(pending);96} else {97throw new InternalException("Unexpected token: " + token);98}99pending = null;100} else {101if (token.equals(quoteStr)) {102quoted = "";103} else if ((token.length() == 1) &&104Character.isWhitespace(token.charAt(0))) {105// continue106} else {107pending = token;108}109}110}111112/*113* Add final token.114*/115if (pending != null) {116tokenList.add(pending);117}118119/*120* An unclosed quote at the end of the command. Do an121* implicit end quote.122*/123if (quoted != null) {124tokenList.add(quoted);125}126127String[] tokenArray = new String[tokenList.size()];128for (int i = 0; i < tokenList.size(); i++) {129tokenArray[i] = tokenList.get(i);130}131return tokenArray;132}133134protected VirtualMachine launch(String[] commandArray, String address,135TransportService.ListenKey listenKey,136TransportService ts)137throws IOException, VMStartException {138Helper helper = new Helper(commandArray, address, listenKey, ts);139helper.launchAndAccept();140141VirtualMachineManager manager =142Bootstrap.virtualMachineManager();143144return manager.createVirtualMachine(helper.connection(),145helper.process());146}147148/**149* This class simply provides a context for a single launch and150* accept. It provides instance fields that can be used by151* all threads involved. This stuff can't be in the Connector proper152* because the connector is a singleton and is not specific to any153* one launch.154*/155private class Helper {156@SuppressWarnings("unused")157private final String address;158private TransportService.ListenKey listenKey;159private TransportService ts;160private final String[] commandArray;161private Process process = null;162private Connection connection = null;163private IOException acceptException = null;164private boolean exited = false;165166Helper(String[] commandArray, String address, TransportService.ListenKey listenKey,167TransportService ts) {168this.commandArray = commandArray;169this.address = address;170this.listenKey = listenKey;171this.ts = ts;172}173174String commandString() {175String str = "";176for (int i = 0; i < commandArray.length; i++) {177if (i > 0) {178str += " ";179}180str += commandArray[i];181}182return str;183}184185synchronized void launchAndAccept() throws186IOException, VMStartException {187188process = Runtime.getRuntime().exec(commandArray);189190Thread acceptingThread = acceptConnection();191Thread monitoringThread = monitorTarget();192try {193while ((connection == null) &&194(acceptException == null) &&195!exited) {196wait();197}198199if (exited) {200throw new VMStartException(201"VM initialization failed for: " + commandString(), process);202}203if (acceptException != null) {204// Rethrow the exception in this thread205throw acceptException;206}207} catch (InterruptedException e) {208throw new InterruptedIOException("Interrupted during accept");209} finally {210acceptingThread.interrupt();211monitoringThread.interrupt();212}213}214215Process process() {216return process;217}218219Connection connection() {220return connection;221}222223synchronized void notifyOfExit() {224exited = true;225notify();226}227228synchronized void notifyOfConnection(Connection connection) {229this.connection = connection;230notify();231}232233synchronized void notifyOfAcceptException(IOException acceptException) {234this.acceptException = acceptException;235notify();236}237238Thread monitorTarget() {239Thread thread = new Thread(grp, "launched target monitor") {240public void run() {241try {242process.waitFor();243/*244* Notify waiting thread of VM error termination245*/246notifyOfExit();247} catch (InterruptedException e) {248// Connection has been established, stop monitoring249}250}251};252thread.setDaemon(true);253thread.start();254return thread;255}256257Thread acceptConnection() {258Thread thread = new Thread(grp, "connection acceptor") {259public void run() {260try {261Connection connection = ts.accept(listenKey, 0, 0);262/*263* Notify waiting thread of connection264*/265notifyOfConnection(connection);266} catch (InterruptedIOException e) {267// VM terminated, stop accepting268} catch (IOException e) {269// Report any other exception to waiting thread270notifyOfAcceptException(e);271}272}273};274thread.setDaemon(true);275thread.start();276return thread;277}278}279}280281282