jdk/src/solaris/classes/java/lang/UNIXProcess.java.bsd
changeset 21357 eb15eae19cd9
parent 19399 e2e5122cd62e
child 22626 758d413359c4
equal deleted inserted replaced
21356:ad2735d41496 21357:eb15eae19cd9
   335      * This is tricky because we do not want the user-level InputStream to be
   335      * This is tricky because we do not want the user-level InputStream to be
   336      * closed until the user invokes close(), and we need to continue to be
   336      * closed until the user invokes close(), and we need to continue to be
   337      * able to read any buffered data lingering in the OS pipe buffer.
   337      * able to read any buffered data lingering in the OS pipe buffer.
   338      */
   338      */
   339     static class ProcessPipeInputStream extends BufferedInputStream {
   339     static class ProcessPipeInputStream extends BufferedInputStream {
       
   340         private final Object closeLock = new Object();
       
   341 
   340         ProcessPipeInputStream(int fd) {
   342         ProcessPipeInputStream(int fd) {
   341             super(new FileInputStream(newFileDescriptor(fd)));
   343             super(new FileInputStream(newFileDescriptor(fd)));
   342         }
   344         }
   343 
   345 
   344         private static byte[] drainInputStream(InputStream in)
   346         private InputStream drainInputStream(InputStream in)
   345                 throws IOException {
   347                 throws IOException {
   346             if (in == null) return null;
       
   347             int n = 0;
   348             int n = 0;
   348             int j;
   349             int j;
   349             byte[] a = null;
   350             byte[] a = null;
   350             while ((j = in.available()) > 0) {
   351             synchronized (closeLock) {
       
   352                 if (buf == null) // asynchronous close()?
       
   353                     return null; // discard
       
   354                 j = in.available();
       
   355             }
       
   356             while (j > 0) {
   351                 a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
   357                 a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
   352                 n += in.read(a, n, j);
   358                 synchronized (closeLock) {
       
   359                     if (buf == null) // asynchronous close()?
       
   360                         return null; // discard
       
   361                     n += in.read(a, n, j);
       
   362                     j = in.available();
       
   363                 }
   353             }
   364             }
   354             return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
   365             return (a == null) ?
       
   366                     ProcessBuilder.NullInputStream.INSTANCE :
       
   367                     new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n));
   355         }
   368         }
   356 
   369 
   357         /** Called by the process reaper thread when the process exits. */
   370         /** Called by the process reaper thread when the process exits. */
   358         synchronized void processExited() {
   371         synchronized void processExited() {
   359             // Most BufferedInputStream methods are synchronized, but close()
       
   360             // is not, and so we have to handle concurrent racing close().
       
   361             try {
   372             try {
   362                 InputStream in = this.in;
   373                 InputStream in = this.in;
   363                 if (in != null) {
   374                 if (in != null) {
   364                     byte[] stragglers = drainInputStream(in);
   375                     InputStream stragglers = drainInputStream(in);
   365                     in.close();
   376                     in.close();
   366                     this.in = (stragglers == null) ?
   377                     this.in = stragglers;
   367                         ProcessBuilder.NullInputStream.INSTANCE :
       
   368                         new ByteArrayInputStream(stragglers);
       
   369                     if (buf == null) // asynchronous close()?
       
   370                         this.in = null;
       
   371                 }
   378                 }
   372             } catch (IOException ignored) {
   379             } catch (IOException ignored) { }
   373                 // probably an asynchronous close().
   380         }
       
   381 
       
   382         @Override
       
   383         public void close() throws IOException {
       
   384             // BufferedInputStream#close() is not synchronized unlike most other methods.
       
   385             // Synchronizing helps avoid racing with drainInputStream().
       
   386             synchronized (closeLock) {
       
   387                 super.close();
   374             }
   388             }
   375         }
   389         }
   376     }
   390     }
   377 
   391 
   378     /**
   392     /**