Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/tools/attach/SolarisVirtualMachine.java
32288 views
/*1* Copyright (c) 2005, 2014, 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*/24package sun.tools.attach;2526import com.sun.tools.attach.AttachOperationFailedException;27import com.sun.tools.attach.AgentLoadException;28import com.sun.tools.attach.AttachNotSupportedException;29import com.sun.tools.attach.spi.AttachProvider;3031import java.io.InputStream;32import java.io.IOException;33import java.io.File;34import java.io.FileNotFoundException;3536/*37* Solaris implementation of HotSpotVirtualMachine.38*/39public class SolarisVirtualMachine extends HotSpotVirtualMachine {40// "/tmp" is used as a global well-known location for the files41// .java_pid<pid>. and .attach_pid<pid>. It is important that this42// location is the same for all processes, otherwise the tools43// will not be able to find all Hotspot processes.44// Any changes to this needs to be synchronized with HotSpot.45private static final String tmpdir = "/tmp";4647// door descriptor;48private int fd = -1;4950/**51* Attaches to the target VM52*/53SolarisVirtualMachine(AttachProvider provider, String vmid)54throws AttachNotSupportedException, IOException55{56super(provider, vmid);57// This provider only understands process-ids (pids).58int pid;59try {60pid = Integer.parseInt(vmid);61} catch (NumberFormatException x) {62throw new AttachNotSupportedException("invalid process identifier");63}6465// Opens the door file to the target VM. If the file is not66// found it might mean that the attach mechanism isn't started in the67// target VM so we attempt to start it and retry.68try {69fd = openDoor(pid);70} catch (FileNotFoundException fnf1) {71File f = createAttachFile(pid);72try {73// kill -QUIT will tickle target VM to check for the74// attach file.75sigquit(pid);7677// give the target VM time to start the attach mechanism78int i = 0;79long delay = 200;80int retries = (int)(attachTimeout() / delay);81do {82try {83Thread.sleep(delay);84} catch (InterruptedException x) { }85try {86fd = openDoor(pid);87} catch (FileNotFoundException fnf2) { }88i++;89} while (i <= retries && fd == -1);90if (fd == -1) {91throw new AttachNotSupportedException(92"Unable to open door: target process not responding or " +93"HotSpot VM not loaded");94}95} finally {96f.delete();97}98}99assert fd >= 0;100}101102/**103* Detach from the target VM104*/105public void detach() throws IOException {106synchronized (this) {107if (fd != -1) {108close(fd);109fd = -1;110}111}112}113114/**115* Execute the given command in the target VM.116*/117InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {118assert args.length <= 3; // includes null119120// first check that we are still attached121int door;122synchronized (this) {123if (fd == -1) {124throw new IOException("Detached from target VM");125}126door = fd;127}128129// enqueue the command via a door call130int s = enqueue(door, cmd, args);131assert s >= 0; // valid file descriptor132133// The door call returns a file descriptor (one end of a socket pair).134// Create an input stream around it.135SocketInputStream sis = new SocketInputStream(s);136137// Read the command completion status138int completionStatus;139try {140completionStatus = readInt(sis);141} catch (IOException ioe) {142sis.close();143throw ioe;144}145146// If non-0 it means an error but we need to special-case the147// "load" command to ensure that the right exception is thrown.148if (completionStatus != 0) {149// read from the stream and use that as the error message150String message = readErrorMessage(sis);151sis.close();152if (cmd.equals("load")) {153throw new AgentLoadException("Failed to load agent library");154} else {155if (message == null) {156throw new AttachOperationFailedException("Command failed in target VM");157} else {158throw new AttachOperationFailedException(message);159}160}161}162163// Return the input stream so that the command output can be read164return sis;165}166167// InputStream over a socket168private class SocketInputStream extends InputStream {169int s;170171public SocketInputStream(int s) {172this.s = s;173}174175public synchronized int read() throws IOException {176byte b[] = new byte[1];177int n = this.read(b, 0, 1);178if (n == 1) {179return b[0] & 0xff;180} else {181return -1;182}183}184185public synchronized int read(byte[] bs, int off, int len) throws IOException {186if ((off < 0) || (off > bs.length) || (len < 0) ||187((off + len) > bs.length) || ((off + len) < 0)) {188throw new IndexOutOfBoundsException();189} else if (len == 0)190return 0;191192return SolarisVirtualMachine.read(s, bs, off, len);193}194195public void close() throws IOException {196SolarisVirtualMachine.close(s);197}198}199200// The door is attached to .java_pid<pid> in the temporary directory.201private int openDoor(int pid) throws IOException {202String path = tmpdir + "/.java_pid" + pid;;203fd = open(path);204205// Check that the file owner/permission to avoid attaching to206// bogus process207try {208checkPermissions(path);209} catch (IOException ioe) {210close(fd);211throw ioe;212}213return fd;214}215216// On Solaris/Linux a simple handshake is used to start the attach mechanism217// if not already started. The client creates a .attach_pid<pid> file in the218// target VM's working directory (or temporary directory), and the SIGQUIT219// handler checks for the file.220private File createAttachFile(int pid) throws IOException {221String fn = ".attach_pid" + pid;222String path = "/proc/" + pid + "/cwd/" + fn;223File f = new File(path);224try {225f.createNewFile();226} catch (IOException x) {227f = new File(tmpdir, fn);228f.createNewFile();229}230return f;231}232233//-- native methods234235static native int open(String path) throws IOException;236237static native void close(int fd) throws IOException;238239static native int read(int fd, byte buf[], int off, int buflen) throws IOException;240241static native void checkPermissions(String path) throws IOException;242243static native void sigquit(int pid) throws IOException;244245// enqueue a command (and arguments) to the given door246static native int enqueue(int fd, String cmd, Object ... args)247throws IOException;248249static {250System.loadLibrary("attach");251}252}253254255