1 /*
  2  * Copyright (c) 2020, 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 import java.io.BufferedReader;
 25 import java.io.IOException;
 26 import java.io.InputStream;
 27 import java.io.InputStreamReader;
 28 import java.lang.ProcessHandle;
 29 
 30 /*
 31  * @test
 32  * @bug 8239893
 33  * @summary Verify that handles for processes that terminate do not accumulate
 34  * @requires (os.family == "windows")
 35  * @run main/native CheckHandles
 36  */
 37 public class CheckHandles {
 38 
 39     // Return the current process handle count
 40     private static native long getProcessHandleCount();
 41 
 42     public static void main(String[] args) throws Exception {
 43         System.loadLibrary("CheckHandles");
 44 
 45         System.out.println("mypid: " + ProcessHandle.current().pid());
 46         long minHandles = Long.MAX_VALUE;
 47         long maxHandles = 0L;
 48         int MAX_SPAWN = 50;
 49         for (int i = 0; i < MAX_SPAWN; i++) {
 50             try {
 51                 Process testProcess = new ProcessBuilder("cmd", "/c", "dir").start();
 52 
 53                 Thread outputConsumer = new Thread(() -> consumeStream(testProcess.pid(), testProcess.getInputStream()));
 54                 outputConsumer.setDaemon(true);
 55                 outputConsumer.start();
 56                 Thread errorConsumer = new Thread(() -> consumeStream(testProcess.pid(), testProcess.getErrorStream()));
 57                 errorConsumer.setDaemon(true);
 58                 errorConsumer.start();
 59 
 60                 testProcess.waitFor();
 61                 System.gc();
 62                 outputConsumer.join();
 63                 errorConsumer.join();
 64                 long count = getProcessHandleCount();
 65                 if (count < 0)
 66                     throw new AssertionError("getProcessHandleCount failed");
 67                 minHandles =  Math.min(minHandles, count);
 68                 maxHandles =  Math.max(maxHandles, count);
 69             } catch (IOException | InterruptedException e) {
 70                 e.printStackTrace();
 71                 throw e;
 72             }
 73         }
 74         final long ERROR_PERCENT = 10;
 75         final long ERROR_THRESHOLD = // 10% increase over min to passing max
 76                 minHandles + ((minHandles + ERROR_PERCENT - 1) / ERROR_PERCENT);
 77         if (maxHandles >= ERROR_THRESHOLD) {
 78             System.out.println("Processes started: " + MAX_SPAWN);
 79             System.out.println("minhandles: " + minHandles);
 80             System.out.println("maxhandles: " + maxHandles);
 81             throw new AssertionError("Handle use increased by more than " + ERROR_PERCENT + " percent.");
 82         }
 83     }
 84 
 85     private static void consumeStream(long pid, InputStream inputStream) {
 86         BufferedReader reader = null;
 87         try {
 88             int lines = 0;
 89             reader = new BufferedReader(new InputStreamReader(inputStream));
 90             while (reader.readLine() != null) {
 91                 lines++;
 92             }
 93         } catch (IOException e) {
 94             e.printStackTrace();
 95         } finally {
 96             if (reader != null) {
 97                 try {
 98                     reader.close();
 99                 } catch (IOException e) {
100                     e.printStackTrace();
101                 }
102             }
103         }
104     }
105 }