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                 minHandles =  Math.min(minHandles, getProcessHandleCount());
 65                 maxHandles =  Math.max(maxHandles, getProcessHandleCount());
 66             } catch (IOException | InterruptedException e) {
 67                 e.printStackTrace();
 68                 throw e;
 69             }
 70         }
 71         final long ERROR_PERCENT = 10;
 72         final long ERROR_THRESHOLD = minHandles + (minHandles / ERROR_PERCENT); // 10% increase over min to passing max
 73         if (maxHandles >= ERROR_THRESHOLD) {
 74             System.out.println("Processes started: " + MAX_SPAWN);
 75             System.out.println("minhandles: " + minHandles);
 76             System.out.println("maxhandles: " + maxHandles);
 77             throw new AssertionError("Handle use increased by more than " + ERROR_PERCENT + " percent.");
 78         }
 79     }
 80 
 81     private static void consumeStream(long pid, InputStream inputStream) {
 82         BufferedReader reader = null;
 83         try {
 84             int lines = 0;
 85             reader = new BufferedReader(new InputStreamReader(inputStream));
 86             while (reader.readLine() != null) {
 87                 lines++;
 88             }
 89         } catch (IOException e) {
 90             e.printStackTrace();
 91         } finally {
 92             if (reader != null) {
 93                 try {
 94                     reader.close();
 95                 } catch (IOException e) {
 96                     e.printStackTrace();
 97                 }
 98             }
 99         }
100     }
101 }