1 /* 2 * Copyright (c) 2003, 2019, 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 /* @test 25 * @bug 4820217 26 * @summary Ensure that pending reads on stdout and stderr streams 27 * return -1 when the process is destroyed 28 */ 29 30 import java.io.*; 31 import java.util.concurrent.*; 32 33 34 public class StreamsSurviveDestroy { 35 36 private static class Copier extends Thread { 37 38 String name; 39 InputStream in; 40 OutputStream out; 41 boolean wantInterrupt; 42 boolean acceptException; 43 Exception exc = null; 44 CountDownLatch latch; 45 46 Copier(String name, InputStream in, OutputStream out, 47 boolean ae, boolean wi, CountDownLatch l) 48 { 49 this.name = name; 50 this.in = in; 51 this.out = out; 52 this.acceptException = ae; 53 this.wantInterrupt = wi; 54 this.latch = l; 55 setName(name); 56 start(); 57 } 58 59 private void log(String s) { 60 System.err.println(" " + name + ": " + s); 61 } 62 63 public void run() { 64 byte[] buf = new byte[4242]; 65 latch.countDown(); 66 for (;;) { 67 try { 68 int n = in.read(buf); 69 if (n < 0) { 70 System.err.println(" EOF"); 71 break; 72 } 73 out.write(buf, 0, n); 74 } catch (IOException x) { 75 if (wantInterrupt) { 76 if (x instanceof InterruptedIOException) { 77 log("Interrupted as expected"); 78 return; 79 } 80 exc = new Exception(name 81 + ": Not interrupted as expected"); 82 return; 83 } 84 exc = x; 85 if (acceptException) { 86 log("Thrown, but okay: " + x); 87 return; 88 } 89 return; 90 } 91 } 92 } 93 94 public void check() throws Exception { 95 if (!acceptException && exc != null) 96 throw new Exception(name + ": Exception thrown", exc); 97 } 98 99 } 100 101 static void test() throws Exception { 102 CountDownLatch latch = new CountDownLatch(2); 103 104 System.err.println("test"); 105 Process p = Runtime.getRuntime().exec(UnixCommands.cat()); 106 Copier cp1 = new Copier("out", p.getInputStream(), System.err, 107 false, false, latch); 108 Copier cp2 = new Copier("err", p.getErrorStream(), System.err, 109 false, false, latch); 110 latch.await(); // Wait till both Copiers about to read 111 Thread.sleep(100);// Give both Copiers a chance to start read 112 113 p.destroy(); 114 System.err.println(" exit: " + p.waitFor()); 115 cp1.join(); 116 cp1.check(); 117 cp2.join(); 118 cp2.check(); 119 } 120 121 static void testCloseBeforeDestroy() throws Exception { 122 CountDownLatch latch = new CountDownLatch(2); 123 124 System.err.println("testCloseBeforeDestroy"); 125 Process p = Runtime.getRuntime().exec(UnixCommands.cat()); 126 Copier cp1 = new Copier("out", p.getInputStream(), System.err, 127 true, false, latch); 128 Copier cp2 = new Copier("err", p.getErrorStream(), System.err, 129 true, false, latch); 130 latch.await(); // Wait till both Copiers about to read 131 Thread.sleep(100);// Give both Copiers a chance to start read 132 133 p.getInputStream().close(); 134 p.getErrorStream().close(); 135 p.destroy(); 136 System.err.println(" exit: " + p.waitFor()); 137 cp1.join(); 138 cp1.check(); 139 cp2.join(); 140 cp2.check(); 141 } 142 143 static void testCloseAfterDestroy() throws Exception { 144 CountDownLatch latch = new CountDownLatch(2); 145 System.err.println("testCloseAfterDestroy"); 146 Process p = Runtime.getRuntime().exec(UnixCommands.cat()); 147 Copier cp1 = new Copier("out", p.getInputStream(), System.err, 148 true, false,latch); 149 Copier cp2 = new Copier("err", p.getErrorStream(), System.err, 150 true, false, latch); 151 152 latch.await(); // Wait till both Copiers about to read 153 Thread.sleep(100);// Give both Copiers a chance to start read 154 155 p.destroy(); 156 p.getInputStream().close(); 157 p.getErrorStream().close(); 158 System.err.println(" exit: " + p.waitFor()); 159 cp1.join(); 160 cp1.check(); 161 cp2.join(); 162 cp2.check(); 163 } 164 165 static void testInterrupt() throws Exception { 166 CountDownLatch latch = new CountDownLatch(2); 167 System.err.println("testInterrupt"); 168 Process p = Runtime.getRuntime().exec(UnixCommands.cat()); 169 Copier cp1 = new Copier("out", p.getInputStream(), System.err, 170 false, true, latch); 171 Copier cp2 = new Copier("err", p.getErrorStream(), System.err, 172 false, true, latch); 173 latch.await(); // Wait till both Copiers about to read 174 Thread.sleep(100);// Give both Copiers a chance to start read 175 176 cp1.interrupt(); 177 cp2.interrupt(); 178 Thread.sleep(100); 179 p.destroy(); 180 System.err.println(" exit: " + p.waitFor()); 181 cp1.join(); 182 cp1.check(); 183 cp2.join(); 184 cp2.check(); 185 } 186 187 public static void main(String[] args) throws Exception { 188 189 // Applies only to Solaris; 190 // Linux and Windows behave a little differently 191 if (! UnixCommands.isSunOS) { 192 System.out.println("For SunOS only"); 193 return; 194 } 195 UnixCommands.ensureCommandsAvailable("cat"); 196 197 test(); 198 testCloseBeforeDestroy(); 199 testCloseAfterDestroy(); 200 testInterrupt(); 201 } 202 }