AttachWithStalePidFile.java revision 11833:1cbffa2beba6
1/*
2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 7162400
27 * @key regression
28 * @summary Regression test for attach issue where stale pid files in /tmp lead to connection issues
29 * @modules java.base/jdk.internal.misc
30 * @modules jdk.attach/sun.tools.attach
31 * @library /test/lib
32 * @run main AttachWithStalePidFile
33 */
34
35import jdk.test.lib.Platform;
36import jdk.test.lib.process.ProcessTools;
37import com.sun.tools.attach.VirtualMachine;
38import sun.tools.attach.HotSpotVirtualMachine;
39import java.lang.reflect.Field;
40import java.nio.file.*;
41import java.nio.file.attribute.*;
42import java.io.*;
43
44public class AttachWithStalePidFile {
45  public static void main(String... args) throws Exception {
46
47    // this test is only valid on non-Windows platforms
48    if(Platform.isWindows()) {
49      System.out.println("This test is only valid on non-Windows platforms.");
50      return;
51    }
52
53    // Since there might be stale pid-files owned by different
54    // users on the system we may need to retry the test in case we
55    // are unable to remove the existing file.
56    int retries = 5;
57    while(!runTest() && --retries > 0);
58
59    if(retries == 0) {
60      throw new RuntimeException("Test failed after 5 retries. " +
61        "Remove any /tmp/.java_pid* files and retry.");
62    }
63  }
64
65  public static boolean runTest() throws Exception {
66    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
67      "-XX:+UnlockDiagnosticVMOptions", "-XX:+PauseAtStartup", "AttachWithStalePidFileTarget");
68    Process target = pb.start();
69    Path pidFile = null;
70
71    try {
72      int pid = getUnixProcessId(target);
73
74      // create the stale .java_pid file. use hard-coded /tmp path as in th VM
75      pidFile = createJavaPidFile(pid);
76      if(pidFile == null) {
77        return false;
78      }
79
80      // wait for vm.paused file to be created and delete it once we find it.
81      waitForAndResumeVM(pid);
82
83      waitForTargetReady(target);
84
85      HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString());
86      BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader(vm.remoteDataDump()));
87      String line = null;
88      while((line = remoteDataReader.readLine()) != null);
89
90      vm.detach();
91      return true;
92    }
93    finally {
94      target.destroy();
95      target.waitFor();
96
97      if(pidFile != null && Files.exists(pidFile)) {
98        Files.delete(pidFile);
99      }
100    }
101  }
102
103  private static void waitForTargetReady(Process target) throws IOException {
104    BufferedReader br = new BufferedReader(new InputStreamReader(target.getInputStream()));
105    String line = br.readLine();
106    // wait for the ready message having been printed or EOF (line == null)
107    while (line != null && !line.equals(AttachWithStalePidFileTarget.READY_MSG)) {
108        line = br.readLine();
109    }
110    // target VM ready
111  }
112
113  private static Path createJavaPidFile(int pid) throws Exception {
114    Path pidFile = Paths.get("/tmp/.java_pid" + pid);
115    if(Files.exists(pidFile)) {
116      try {
117        Files.delete(pidFile);
118      }
119      catch(FileSystemException e) {
120        if(e.getReason().matches("Operation not permitted|Not owner")) {
121          System.out.println("Unable to remove exisiting stale PID file" + pidFile);
122          System.out.println("===================================================");
123          e.printStackTrace(System.out);
124          return null;
125        }
126        throw e;
127      }
128    }
129    return Files.createFile(pidFile,
130      PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")));
131  }
132
133  private static void waitForAndResumeVM(int pid) throws Exception {
134    Path pauseFile = Paths.get("vm.paused." + pid);
135    int retries = 60;
136    while(!Files.exists(pauseFile) && --retries > 0) {
137      Thread.sleep(1000);
138    }
139    if(retries == 0) {
140      throw new RuntimeException("Timeout waiting for VM to start. " +
141        "vm.paused file not created within 60 seconds.");
142    }
143    Files.delete(pauseFile);
144  }
145
146  private static int getUnixProcessId(Process unixProcess) throws Exception {
147    Field pidField = unixProcess.getClass().getDeclaredField("pid");
148    pidField.setAccessible(true);
149    return (Integer)pidField.get(unixProcess);
150  }
151}
152