1 /*
2  * Copyright (c) 2003, 2011, 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 
Copier(String name, InputStream in, OutputStream out, boolean ae, boolean wi, CountDownLatch l)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 
log(String s)59         private void log(String s) {
60             System.err.println("  " + name + ": " + s);
61         }
62 
run()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 
check()94         public void check() throws Exception {
95             if (!acceptException && exc != null)
96                 throw new Exception(name + ": Exception thrown", exc);
97         }
98 
99     }
100 
test()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 
testCloseBeforeDestroy()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 
testCloseAfterDestroy()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 
testInterrupt()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 
main(String[] args)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 }
203