AttachWithStalePidFile.java revision 12290:8953c0318163
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:open
30 * @modules java.base/java.lang:open
31 * @modules jdk.attach/sun.tools.attach
32 * @library /test/lib
33 * @run main AttachWithStalePidFile
34 */
35
36import jdk.test.lib.Platform;
37import jdk.test.lib.process.ProcessTools;
38import com.sun.tools.attach.VirtualMachine;
39import sun.tools.attach.HotSpotVirtualMachine;
40import java.lang.reflect.Field;
41import java.nio.file.*;
42import java.nio.file.attribute.*;
43import java.io.*;
44
45public class AttachWithStalePidFile {
46  public static void main(String... args) throws Exception {
47
48    // this test is only valid on non-Windows platforms
49    if(Platform.isWindows()) {
50      System.out.println("This test is only valid on non-Windows platforms.");
51      return;
52    }
53
54    // Since there might be stale pid-files owned by different
55    // users on the system we may need to retry the test in case we
56    // are unable to remove the existing file.
57    int retries = 5;
58    while(!runTest() && --retries > 0);
59
60    if(retries == 0) {
61      throw new RuntimeException("Test failed after 5 retries. " +
62        "Remove any /tmp/.java_pid* files and retry.");
63    }
64  }
65
66  public static boolean runTest() throws Exception {
67    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
68      "-XX:+UnlockDiagnosticVMOptions", "-XX:+PauseAtStartup", "AttachWithStalePidFileTarget");
69    Process target = pb.start();
70    Path pidFile = null;
71
72    try {
73      int pid = getUnixProcessId(target);
74
75      // create the stale .java_pid file. use hard-coded /tmp path as in th VM
76      pidFile = createJavaPidFile(pid);
77      if(pidFile == null) {
78        return false;
79      }
80
81      // wait for vm.paused file to be created and delete it once we find it.
82      waitForAndResumeVM(pid);
83
84      waitForTargetReady(target);
85
86      HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString());
87      BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader(vm.remoteDataDump()));
88      String line = null;
89      while((line = remoteDataReader.readLine()) != null);
90
91      vm.detach();
92      return true;
93    }
94    finally {
95      target.destroy();
96      target.waitFor();
97
98      if(pidFile != null && Files.exists(pidFile)) {
99        Files.delete(pidFile);
100      }
101    }
102  }
103
104  private static void waitForTargetReady(Process target) throws IOException {
105    BufferedReader br = new BufferedReader(new InputStreamReader(target.getInputStream()));
106    String line = br.readLine();
107    // wait for the ready message having been printed or EOF (line == null)
108    while (line != null && !line.equals(AttachWithStalePidFileTarget.READY_MSG)) {
109        line = br.readLine();
110    }
111    // target VM ready
112  }
113
114  private static Path createJavaPidFile(int pid) throws Exception {
115    Path pidFile = Paths.get("/tmp/.java_pid" + pid);
116    if(Files.exists(pidFile)) {
117      try {
118        Files.delete(pidFile);
119      }
120      catch(FileSystemException e) {
121        if(e.getReason().matches("Operation not permitted|Not owner")) {
122          System.out.println("Unable to remove exisiting stale PID file" + pidFile);
123          System.out.println("===================================================");
124          e.printStackTrace(System.out);
125          return null;
126        }
127        throw e;
128      }
129    }
130    return Files.createFile(pidFile,
131      PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")));
132  }
133
134  private static void waitForAndResumeVM(int pid) throws Exception {
135    Path pauseFile = Paths.get("vm.paused." + pid);
136    int retries = 60;
137    while(!Files.exists(pauseFile) && --retries > 0) {
138      Thread.sleep(1000);
139    }
140    if(retries == 0) {
141      throw new RuntimeException("Timeout waiting for VM to start. " +
142        "vm.paused file not created within 60 seconds.");
143    }
144    Files.delete(pauseFile);
145  }
146
147  private static int getUnixProcessId(Process unixProcess) throws Exception {
148    Field pidField = unixProcess.getClass().getDeclaredField("pid");
149    pidField.setAccessible(true);
150    return (Integer)pidField.get(unixProcess);
151  }
152}
153