Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/tools/jdi/AbstractLauncher.java
38920 views
/*1* Copyright (c) 1999, 2013, 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 com.sun.tools.jdi.*;28import com.sun.jdi.connect.*;29import com.sun.jdi.connect.spi.*;30import com.sun.jdi.*;3132import java.util.Map;33import java.util.StringTokenizer;34import java.util.List;35import java.util.ArrayList;36import java.io.IOException;37import java.io.InterruptedIOException;3839abstract class AbstractLauncher extends ConnectorImpl implements LaunchingConnector {4041abstract public VirtualMachine42launch(Map<String,? extends Connector.Argument> arguments)43throws IOException,44IllegalConnectorArgumentsException,45VMStartException;46abstract public String name();47abstract public String description();4849ThreadGroup grp;5051AbstractLauncher() {52super();5354grp = Thread.currentThread().getThreadGroup();55ThreadGroup parent = null;56while ((parent = grp.getParent()) != null) {57grp = parent;58}59}6061String[] tokenizeCommand(String command, char quote) {62String quoteStr = String.valueOf(quote); // easier to deal with6364/*65* Tokenize the command, respecting the given quote character.66*/67StringTokenizer tokenizer = new StringTokenizer(command,68quote + " \t\r\n\f",69true);70String quoted = null;71String pending = null;72List<String> tokenList = new ArrayList<String>();73while (tokenizer.hasMoreTokens()) {74String token = tokenizer.nextToken();75if (quoted != null) {76if (token.equals(quoteStr)) {77tokenList.add(quoted);78quoted = null;79} else {80quoted += token;81}82} else if (pending != null) {83if (token.equals(quoteStr)) {84quoted = pending;85} else if ((token.length() == 1) &&86Character.isWhitespace(token.charAt(0))) {87tokenList.add(pending);88} else {89throw new InternalException("Unexpected token: " + token);90}91pending = null;92} else {93if (token.equals(quoteStr)) {94quoted = "";95} else if ((token.length() == 1) &&96Character.isWhitespace(token.charAt(0))) {97// continue98} else {99pending = token;100}101}102}103104/*105* Add final token.106*/107if (pending != null) {108tokenList.add(pending);109}110111/*112* An unclosed quote at the end of the command. Do an113* implicit end quote.114*/115if (quoted != null) {116tokenList.add(quoted);117}118119String[] tokenArray = new String[tokenList.size()];120for (int i = 0; i < tokenList.size(); i++) {121tokenArray[i] = tokenList.get(i);122}123return tokenArray;124}125126protected VirtualMachine launch(String[] commandArray, String address,127TransportService.ListenKey listenKey,128TransportService ts)129throws IOException, VMStartException {130Helper helper = new Helper(commandArray, address, listenKey, ts);131helper.launchAndAccept();132133VirtualMachineManager manager =134Bootstrap.virtualMachineManager();135136return manager.createVirtualMachine(helper.connection(),137helper.process());138}139140/**141* This class simply provides a context for a single launch and142* accept. It provides instance fields that can be used by143* all threads involved. This stuff can't be in the Connector proper144* because the connector is a singleton and is not specific to any145* one launch.146*/147private class Helper {148private final String address;149private TransportService.ListenKey listenKey;150private TransportService ts;151private final String[] commandArray;152private Process process = null;153private Connection connection = null;154private IOException acceptException = null;155private boolean exited = false;156157Helper(String[] commandArray, String address, TransportService.ListenKey listenKey,158TransportService ts) {159this.commandArray = commandArray;160this.address = address;161this.listenKey = listenKey;162this.ts = ts;163}164165String commandString() {166String str = "";167for (int i = 0; i < commandArray.length; i++) {168if (i > 0) {169str += " ";170}171str += commandArray[i];172}173return str;174}175176synchronized void launchAndAccept() throws177IOException, VMStartException {178179process = Runtime.getRuntime().exec(commandArray);180181Thread acceptingThread = acceptConnection();182Thread monitoringThread = monitorTarget();183try {184while ((connection == null) &&185(acceptException == null) &&186!exited) {187wait();188}189190if (exited) {191throw new VMStartException(192"VM initialization failed for: " + commandString(), process);193}194if (acceptException != null) {195// Rethrow the exception in this thread196throw acceptException;197}198} catch (InterruptedException e) {199throw new InterruptedIOException("Interrupted during accept");200} finally {201acceptingThread.interrupt();202monitoringThread.interrupt();203}204}205206Process process() {207return process;208}209210Connection connection() {211return connection;212}213214synchronized void notifyOfExit() {215exited = true;216notify();217}218219synchronized void notifyOfConnection(Connection connection) {220this.connection = connection;221notify();222}223224synchronized void notifyOfAcceptException(IOException acceptException) {225this.acceptException = acceptException;226notify();227}228229Thread monitorTarget() {230Thread thread = new Thread(grp,231"launched target monitor") {232public void run() {233try {234process.waitFor();235/*236* Notify waiting thread of VM error termination237*/238notifyOfExit();239} catch (InterruptedException e) {240// Connection has been established, stop monitoring241}242}243};244thread.setDaemon(true);245thread.start();246return thread;247}248249Thread acceptConnection() {250Thread thread = new Thread(grp,251"connection acceptor") {252public void run() {253try {254Connection connection = ts.accept(listenKey, 0, 0);255/*256* Notify waiting thread of connection257*/258notifyOfConnection(connection);259} catch (InterruptedIOException e) {260// VM terminated, stop accepting261} catch (IOException e) {262// Report any other exception to waiting thread263notifyOfAcceptException(e);264}265}266};267thread.setDaemon(true);268thread.start();269return thread;270}271}272}273274275