changes after first review

0 import static java.io.File.createTempFile;                                                                                 
1 import static java.lang.Long.parseLong;                                                                                    
2 import static java.lang.System.getProperty;                                                                                
3 import static java.lang.management.ManagementFactory.getOperatingSystemMXBean;                                             
4 import static java.nio.file.Files.readAllBytes;                                                                            
5 import static java.nio.file.Files.readSymbolicLink;                                                                        
6 import static java.util.Arrays.stream;                                                                                     
                                                                                                                           
                                                                                                                           
7 import static java.util.stream.Collectors.joining;                                                                         
8 import static jdk.test.lib.process.ProcessTools.createJavaProcessBuilder;                                                  
9 
10 import java.io.File;                                                                                                       
                                                                                                                           
                                                                                                                           
11 import java.io.IOException;                                                                                                
                                                                                                                           
12 
13 import com.sun.management.UnixOperatingSystemMXBean;                                                                       
14 
15 /*                                                                                                                         
16  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.                                                  
17  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.                                                           
18  *                                                                                                                         
19  * This code is free software; you can redistribute it and/or modify it                                                    
20  * under the terms of the GNU General Public License version 2 only, as                                                    
21  * published by the Free Software Foundation.                                                                              
22  *                                                                                                                         
23  * This code is distributed in the hope that it will be useful, but WITHOUT                                                
24  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or                                                   
25  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License                                                   
26  * version 2 for more details (a copy is included in the LICENSE file that                                                 
27  * accompanied this code).                                                                                                 
28  *                                                                                                                         
29  * You should have received a copy of the GNU General Public License version                                               
30  * 2 along with this work; if not, write to the Free Software Foundation,                                                  
31  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.                                                           
32  *                                                                                                                         
33  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA                                                 
34  * or visit www.oracle.com if you need additional information or have any                                                  
35  * questions.                                                                                                              
36  */                                                                                                                        
37 
38 /*                                                                                                                         
39  * @test TestInheritFD                                                                                                     
40  * @bug 8176717 8176809                                                                                                    
41  * @summary a new process should not inherit open file descriptors                                                         
42  * @requires (os.family != "mac")                                                                                          
43  * @library /test/lib                                                                                                      
44  * @modules java.base/jdk.internal.misc                                                                                    
45  *          java.management                                                                                                
46  */                                                                                                                        
47 
48 /**                                                                                                                        
49  * Test that HotSpot does not leak logging file descriptors.                                                               
50  *                                                                                                                         
51  * This test is performed in three steps. The first VM starts a second VM with                                             
52  * gc logging enabled. The second VM starts a third VM and redirects the third                                             
53  * VMs output to the first VM, it then exits and hopefully closes its log file.                                            
54  *                                                                                                                         
55  * The third VM waits for the second to exit and close its log file. After that,                                           
56  * the third VM tries to rename the log file of the second VM. If it succeeds in                                           
57  * doing so it means that the third VM did not inherit the open log file                                                   
58  * (windows can not rename opened files easily)                                                                            
59  *                                                                                                                         
60  * The third VM communicates the success to rename the file by printing "CLOSED                                            
61  * FD". The first VM checks that the string was printed by the third VM.                                                   
62  *                                                                                                                         
63  * On unix like systems, UnixOperatingSystemMXBean is used to check open file                                              
64  * descriptors.                                                                                                            
65  */                                                                                                                        
66 
67 public class TestInheritFD {                                                                                               
68 
69     public static final String LEAKS_FD = "VM RESULT => LEAKS FD";                                                         
70     public static final String RETAINS_FD = "VM RESULT => RETAINS FD";                                                     
71     public static final String EXIT = "VM RESULT => VM EXIT";                                                              
72     public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor";                                        
73 
74     // first VM                                                                                                            
75     public static void main(String[] args) throws Exception {                                                              
76         String logPath = createTempFile("logging", LOG_SUFFIX).getName();                                                  
77         File commFile = createTempFile("communication", ".txt");                                                           
78 
79         ProcessBuilder pb = createJavaProcessBuilder(                                                                      
80             "-Xlog:gc:\"" + logPath + "\"",                                                                                
81             "-Dtest.jdk=" + getProperty("test.jdk"),                                                                       
82             VMStartedWithLogging.class.getName(),                                                                          
83             logPath);                                                                                                      
84 
85         pb.redirectOutput(commFile); // use temp file to communicate between processes                                     
86         pb.start();                                                                                                        
87 
88         String out = "";                                                                                                   
89         do {                                                                                                               
90             out = new String(readAllBytes(commFile.toPath()));                                                             
91             Thread.sleep(100);                                                                                             
92             System.out.println("SLEEP 100 millis");                                                                        
93         } while (!out.contains(EXIT));                                                                                     
94 
95         System.out.println(out);                                                                                           
96         if (out.contains(RETAINS_FD)) {                                                                                    
97             System.out.println("Log file was not inherited by third VM");                                                  
98         } else {                                                                                                           
99             throw new RuntimeException("could not match: " + RETAINS_FD);                                                  
100         }                                                                                                                  
101     }                                                                                                                      
102 
103     static class VMStartedWithLogging {                                                                                    
104         // second VM                                                                                                       
105         public static void main(String[] args) throws IOException, InterruptedException {                                  
106             ProcessBuilder pb = createJavaProcessBuilder(                                                                  
107                 "-Dtest.jdk=" + getProperty("test.jdk"),                                                                   
108                 VMShouldNotInheritFileDescriptors.class.getName(),                                                         
109                 args[0],                                                                                                   
110                 "" + ProcessHandle.current().pid(),                                                                        
111                 "" + (supportsUnixMXBean()?+unixNrFD():-1));                                                               
112             pb.inheritIO(); // in future, redirect information from third VM to first VM                                   
113             pb.start();                                                                                                    
114 
115             findOpenLogFile();                                                                                             
116         }                                                                                                                  
117     }                                                                                                                      
118 
119     static class VMShouldNotInheritFileDescriptors {                                                                       
120         // third VM                                                                                                        
121         public static void main(String[] args) throws InterruptedException {                                               
122             File logFile = new File(args[0]);                                                                              
123             long parentPid = parseLong(args[1]);                                                                           
124             long parentFDCount = parseLong(args[2]);                                                                       
125 
                                                                                                                           
                                                                                                                           
126             if(supportsUnixMXBean()){                                                                                      
127                 long thisFDCount = unixNrFD();                                                                             
128                 System.out.println("This VM FD-count ("                                                                    
129                         + thisFDCount                                                                                      
130                         + ") should be strictly less than parent VM FD-count ("                                            
131                         + parentFDCount                                                                                    
132                         + ") as log file should have been closed, HOWEVER, THIS CAN NOT BE RELIED"                         
133                         + " ON as files in /proc and /sys is opened by the JVM");                                          
134                 System.out.println(findOpenLogFile()?LEAKS_FD:RETAINS_FD);                                                 
135             } else if (getProperty("os.name").toLowerCase().contains("win")) {                                             
136                 windows(logFile, parentPid);                                                                               
137             } else {                                                                                                       
138                 System.out.println(LEAKS_FD); // default fail on unknown configuration                                     
139             }                                                                                                              
140             System.out.println(EXIT);                                                                                      
141         }                                                                                                                  
142     }                                                                                                                      
143 
144     static boolean supportsUnixMXBean() {                                                                                  
145         return getOperatingSystemMXBean() instanceof UnixOperatingSystemMXBean;                                            
146     }                                                                                                                      
147 
148     static long unixNrFD() {                                                                                               
149         UnixOperatingSystemMXBean osBean = (UnixOperatingSystemMXBean) getOperatingSystemMXBean();                         
150         return osBean.getOpenFileDescriptorCount();                                                                        
151     }                                                                                                                      
152 
153     static File linkTarget(File f) {                                                                                       
154         try {                                                                                                              
155             return readSymbolicLink(f.toPath()).toFile();                                                                  
156         } catch (IOException e) {                                                                                          
157             return new File("Error: could not read symbolic link (last link can not be read as it points to the /proc/self/
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
158         }                                                                                                                  
159     }                                                                                                                      
160 
161     static boolean findOpenLogFile() {                                                                                     
162         File dir = new File("/proc/self/fd");                                                                              
163 
164         System.out.println("Open file descriptors:\n" + stream(dir.listFiles())                                            
165             .map(f -> "###" + f.getAbsolutePath() + " -> " + linkTarget(f))                                                
166             .collect(joining("\n")));                                                                                      
167 
168         return stream(dir.listFiles())                                                                                     
169             .map(TestInheritFD::linkTarget)                                                                                
170             .filter(f -> f.getName().endsWith(LOG_SUFFIX))                                                                 
                                                                                                                           
171             .findAny()                                                                                                     
172             .isPresent();                                                                                                  
173     }                                                                                                                      
174 
175     static void windows(File f, long parentPid) throws InterruptedException {                                              
176         System.out.println("waiting for pid: " + parentPid);                                                               
177         ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().join());                                           
178         System.out.println("trying to rename file to the same name: " + f);                                                
179         System.out.println(f.renameTo(f)?RETAINS_FD:LEAKS_FD); // this parts communicates a closed file descriptor by print
180     }                                                                                                                      
--- EOF ---