changeset 2896:5d7925b886b9

Merge
author asaha
date Sun, 13 Jun 2010 07:40:36 -0700
parents 0e3daaccfbdf 422531c98ba5
children 34080da7fab2
files
diffstat 21 files changed, 394 insertions(+), 245 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/nio/cs/Makefile	Sat Jun 12 00:42:51 2010 -0700
+++ b/make/sun/nio/cs/Makefile	Sun Jun 13 07:40:36 2010 -0700
@@ -37,7 +37,7 @@
 # This re-directs all the class files to a separate location
 CLASSDESTDIR = $(TEMPDIR)/classes
 
-OTHER_JAVACFLAGS += -Xlint:serial -Werror
+OTHER_JAVACFLAGS += -Xlint:serial,-deprecation -Werror
 include $(BUILDDIR)/common/Defs.gmk
 
 #
--- a/src/share/classes/java/lang/ProcessBuilder.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/java/lang/ProcessBuilder.java	Sun Jun 13 07:40:36 2010 -0700
@@ -418,6 +418,8 @@
      * Implements a <a href="#redirect-output">null input stream</a>.
      */
     static class NullInputStream extends InputStream {
+        static final NullInputStream INSTANCE = new NullInputStream();
+        private NullInputStream() {}
         public int read()      { return -1; }
         public int available() { return 0; }
     }
@@ -426,6 +428,8 @@
      * Implements a <a href="#redirect-input">null output stream</a>.
      */
     static class NullOutputStream extends OutputStream {
+        static final NullOutputStream INSTANCE = new NullOutputStream();
+        private NullOutputStream() {}
         public void write(int b) throws IOException {
             throw new IOException("Stream closed");
         }
--- a/src/share/classes/sun/io/ByteToCharISO2022.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/io/ByteToCharISO2022.java	Sun Jun 13 07:40:36 2010 -0700
@@ -124,15 +124,15 @@
         switch(shiftFlag) {
         case SOFlag:
             tmpIndex = curSODes;
-            tmpConverter = (ByteToCharConverter [])SOConverter;
+            tmpConverter = SOConverter;
             break;
         case SS2Flag:
             tmpIndex = curSS2Des;
-            tmpConverter = (ByteToCharConverter [])SS2Converter;
+            tmpConverter = SS2Converter;
             break;
         case SS3Flag:
             tmpIndex = curSS3Des;
-            tmpConverter = (ByteToCharConverter [])SS3Converter;
+            tmpConverter = SS3Converter;
             break;
         }
 
--- a/src/share/classes/sun/io/ByteToCharISO2022JP.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/io/ByteToCharISO2022JP.java	Sun Jun 13 07:40:36 2010 -0700
@@ -141,7 +141,7 @@
                         } else {
                             savedSize = 2;
                             savedBytes[0] = (byte)byte1;
-                            savedBytes[1] = (byte)input[readOff + inputSize];
+                            savedBytes[1] = input[readOff + inputSize];
                             inputSize++;
                         }
                         break;
--- a/src/share/classes/sun/io/ByteToCharJISAutoDetect.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/io/ByteToCharJISAutoDetect.java	Sun Jun 13 07:40:36 2010 -0700
@@ -34,14 +34,12 @@
     private final static int SJIS1B_MASK = 0x04;
     private final static int EUCJP_KANA1_MASK = 0x08;
     private final static int EUCJP_KANA2_MASK = 0x10;
-    private static byte[] maskTable1;
-    private static byte[] maskTable2;
+    private final static byte[] maskTable1 = JISAutoDetect.getByteMask1();
+    private final static byte[] maskTable2 = JISAutoDetect.getByteMask2();
 
     private final static int SS2 = 0x8e;
     private final static int SS3 = 0x8f;
 
-    private final static JISAutoDetect nioCoder = new JISAutoDetect();
-
     // SJISName is set to either "SJIS" or "MS932"
     private String SJISName;
     private String EUCJPName;
@@ -57,8 +55,6 @@
         defaultConv = new ByteToCharISO8859_1();
         defaultConv.subChars = subChars;
         defaultConv.subMode = subMode;
-        maskTable1 = nioCoder.getByteMask1();
-        maskTable2 = nioCoder.getByteMask2();
     }
 
     public int flush(char [] output, int outStart, int outEnd)
@@ -133,7 +129,7 @@
                                 break;
                             }
                             if ((mask == SJIS2B_MASK) || (mask == SJIS1B_MASK)
-                                || (nioCoder.canBeSJIS1B(firstmask) && secondmask == 0)) {
+                                || (JISAutoDetect.canBeSJIS1B(firstmask) && secondmask == 0)) {
                                 convName = SJISName;
                                 break;
                             }
@@ -145,15 +141,15 @@
                             // character boundary. If we tried both
                             // possibilities here, it might be able to be
                             // determined correctly.
-                            if ((byte1 == SS3) && nioCoder.canBeEUCJP(secondmask)) {
+                            if ((byte1 == SS3) && JISAutoDetect.canBeEUCJP(secondmask)) {
                                 if (cnt+1 < inEnd) {
                                     int nextbyte = input[cnt+1] & 0xff;
-                                    if (! nioCoder.canBeEUCJP(maskTable2[nextbyte]))
+                                    if (! JISAutoDetect.canBeEUCJP(maskTable2[nextbyte]))
                                         convName = SJISName;
                                 } else
                                     convName = SJISName;
                             }
-                            if (nioCoder.canBeEUCKana(firstmask, secondmask))
+                            if (JISAutoDetect.canBeEUCKana(firstmask, secondmask))
                                 euckana++;
                         } else {
                             if ((firstmask & SJIS1B_MASK) != 0) {
--- a/src/share/classes/sun/io/CharToBytePCK.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/io/CharToBytePCK.java	Sun Jun 13 07:40:36 2010 -0700
@@ -66,7 +66,7 @@
 
          switch (ch) {
             case '\u2015':
-                return (int)0x815C;
+                return 0x815C;
             case '\u2014':
                 return 0;
             default:
--- a/src/share/classes/sun/nio/cs/ext/DoubleByte.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/DoubleByte.java	Sun Jun 13 07:40:36 2010 -0700
@@ -103,7 +103,7 @@
     public final static char[] B2C_UNMAPPABLE;
     static {
         B2C_UNMAPPABLE = new char[0x100];
-        Arrays.fill(B2C_UNMAPPABLE, (char)UNMAPPABLE_DECODING);
+        Arrays.fill(B2C_UNMAPPABLE, UNMAPPABLE_DECODING);
     }
 
     public static class Decoder extends CharsetDecoder
@@ -374,7 +374,7 @@
         static final char[] b2cSB;
         static {
             b2cSB = new char[0x100];
-            Arrays.fill(b2cSB, (char)UNMAPPABLE_DECODING);
+            Arrays.fill(b2cSB, UNMAPPABLE_DECODING);
         }
         Decoder_EBCDIC_DBCSONLY(Charset cs, char[][] b2c, int b2Min, int b2Max) {
             super(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max);
--- a/src/share/classes/sun/nio/cs/ext/EUC_JP.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/EUC_JP.java	Sun Jun 13 07:40:36 2010 -0700
@@ -79,8 +79,10 @@
         JIS_X_0201.Decoder decoderJ0201;
         JIS_X_0212_Decoder decoderJ0212;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+          JIS_X_0208_Decoder.getIndex1();
+        private static final String[] j0208Index2 =
+          JIS_X_0208_Decoder.getIndex2();
 
         protected Decoder(Charset cs) {
             super(cs);
@@ -88,8 +90,6 @@
             decoderJ0212 = new JIS_X_0212_Decoder(cs);
             start = 0xa1;
             end = 0xfe;
-            j0208Index1 = super.getIndex1();
-            j0208Index2 = super.getIndex2();
         }
         protected char decode0212(int byte1, int byte2) {
              return decoderJ0212.decodeDouble(byte1, byte2);
@@ -238,8 +238,10 @@
         JIS_X_0201.Encoder encoderJ0201;
         JIS_X_0212_Encoder encoderJ0212;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+          JIS_X_0208_Encoder.getIndex1();
+        private static final String[] j0208Index2 =
+          JIS_X_0208_Encoder.getIndex2();
 
         private final Surrogate.Parser sgp = new Surrogate.Parser();
 
@@ -247,8 +249,6 @@
             super(cs, 3.0f, 3.0f);
             encoderJ0201 = new JIS_X_0201.Encoder(cs);
             encoderJ0212 = new JIS_X_0212_Encoder(cs);
-            j0208Index1 = super.getIndex1();
-            j0208Index2 = super.getIndex2();
         }
 
         public boolean canEncode(char c) {
--- a/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java	Sun Jun 13 07:40:36 2010 -0700
@@ -65,20 +65,18 @@
 
     private static class Decoder extends CharsetDecoder {
         JIS_X_0201.Decoder decoderJ0201;
-        JIS_X_0208_Decoder decodeMappingJ0208;
         protected final char REPLACE_CHAR='\uFFFD';
 
-        short[] jis0208Index1;
-        String[] jis0208Index2;
+        private static final int start = 0xa1;
+        private static final int end = 0xfe;
+        private static final short[] jis0208Index1 =
+            JIS_X_0208_Decoder.getIndex1();
+        private static final String[] jis0208Index2 =
+            JIS_X_0208_Decoder.getIndex2();
 
         private Decoder(Charset cs) {
             super(cs, 1.0f, 1.0f);
             decoderJ0201 = new JIS_X_0201.Decoder(cs);
-            decodeMappingJ0208 = new JIS_X_0208_Decoder(cs);
-            decodeMappingJ0208.start = 0xa1;
-            decodeMappingJ0208.end = 0xfe;
-            jis0208Index1 = decodeMappingJ0208.getIndex1();
-            jis0208Index2 = decodeMappingJ0208.getIndex2();
         }
 
         protected char convSingleByte(int b) {
@@ -93,11 +91,11 @@
             }
 
             if (((byte1 < 0) || (byte1 > jis0208Index1.length))
-                || ((byte2 < decodeMappingJ0208.start) || (byte2 > decodeMappingJ0208.end)))
+                || ((byte2 < start) || (byte2 > end)))
                 return REPLACE_CHAR;
 
-            int n = (jis0208Index1[byte1 - 0x80] & 0xf) * (decodeMappingJ0208.end - decodeMappingJ0208.start + 1)
-                    + (byte2 - decodeMappingJ0208.start);
+            int n = (jis0208Index1[byte1 - 0x80] & 0xf) * (end - start + 1)
+                    + (byte2 - start);
             return jis0208Index2[jis0208Index1[byte1 - 0x80] >> 4].charAt(n);
         }
 
@@ -213,18 +211,16 @@
     private static class Encoder extends CharsetEncoder {
 
         JIS_X_0201.Encoder encoderJ0201;
-        JIS_X_0208_Encoder encoderJ0208;
 
         private final Surrogate.Parser sgp = new Surrogate.Parser();
-        short[] jis0208Index1;
-        String[] jis0208Index2;
+        private static final short[] jis0208Index1 =
+            JIS_X_0208_Encoder.getIndex1();
+        private static final String[] jis0208Index2 =
+            JIS_X_0208_Encoder.getIndex2();
 
         private Encoder(Charset cs) {
             super(cs, 2.0f, 2.0f);
             encoderJ0201 = new JIS_X_0201.Encoder(cs);
-            encoderJ0208 = new JIS_X_0208_Encoder(cs);
-            jis0208Index1 = encoderJ0208.getIndex1();
-            jis0208Index2 = encoderJ0208.getIndex2();
         }
 
         public boolean canEncode(char c) {
--- a/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java	Sun Jun 13 07:40:36 2010 -0700
@@ -75,8 +75,12 @@
         JIS_X_0212_Solaris_Decoder decodeMappingJ0212;
         JIS_X_0208_Solaris_Decoder decodeMappingJ0208;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+          JIS_X_0208_Solaris_Decoder.getIndex1();
+        private static final String[] j0208Index2 =
+          JIS_X_0208_Solaris_Decoder.getIndex2();
+        private static final int start = 0xa1;
+        private static final int end = 0xfe;
 
         protected final char REPLACE_CHAR='\uFFFD';
 
@@ -84,11 +88,6 @@
             super(cs);
             decoderJ0201 = new JIS_X_0201.Decoder(cs);
             decodeMappingJ0212 = new JIS_X_0212_Solaris_Decoder(cs);
-            decodeMappingJ0208 = new JIS_X_0208_Solaris_Decoder(cs);
-            decodeMappingJ0208.start = 0xa1;
-            decodeMappingJ0208.end = 0xfe;
-            j0208Index1 = decodeMappingJ0208.getIndex1();
-            j0208Index2 = decodeMappingJ0208.getIndex2();
         }
 
 
@@ -103,9 +102,9 @@
             }
 
             if (((byte1 < 0)
-                || (byte1 > decodeMappingJ0208.getIndex1().length))
-                || ((byte2 < decodeMappingJ0208.start)
-                || (byte2 > decodeMappingJ0208.end)))
+                || (byte1 > j0208Index1.length))
+                || ((byte2 < start)
+                || (byte2 > end)))
                 return REPLACE_CHAR;
 
             char result = super.decodeDouble(byte1, byte2);
@@ -113,8 +112,8 @@
                 return result;
             } else {
                 int n = (j0208Index1[byte1 - 0x80] & 0xf) *
-                        (decodeMappingJ0208.end - decodeMappingJ0208.start + 1)
-                        + (byte2 - decodeMappingJ0208.start);
+                        (end - start + 1)
+                        + (byte2 - start);
                 return j0208Index2[j0208Index1[byte1 - 0x80] >> 4].charAt(n);
             }
         }
@@ -125,10 +124,11 @@
 
         JIS_X_0201.Encoder encoderJ0201;
         JIS_X_0212_Solaris_Encoder encoderJ0212;
-        JIS_X_0208_Solaris_Encoder encoderJ0208;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+            JIS_X_0208_Solaris_Encoder.getIndex1();
+        private static final String[] j0208Index2 =
+            JIS_X_0208_Solaris_Encoder.getIndex2();
 
         private final Surrogate.Parser sgp = new Surrogate.Parser();
 
@@ -136,9 +136,6 @@
             super(cs);
             encoderJ0201 = new JIS_X_0201.Encoder(cs);
             encoderJ0212 = new JIS_X_0212_Solaris_Encoder(cs);
-            encoderJ0208 = new JIS_X_0208_Solaris_Encoder(cs);
-            j0208Index1 = encoderJ0208.getIndex1();
-            j0208Index2 = encoderJ0208.getIndex2();
         }
 
         protected int encodeSingle(char inputChar, byte[] outputByte) {
--- a/src/share/classes/sun/nio/cs/ext/EUC_TW.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/EUC_TW.java	Sun Jun 13 07:40:36 2010 -0700
@@ -423,7 +423,7 @@
                     if (dst.remaining() < outSize)
                         return CoderResult.OVERFLOW;
                     for (int i = 0; i < outSize; i++)
-                        dst.put((byte)bb[i]);
+                        dst.put(bb[i]);
                     mark += inSize;
                 }
                 return CoderResult.UNDERFLOW;
--- a/src/share/classes/sun/nio/cs/ext/GB18030.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/GB18030.java	Sun Jun 13 07:40:36 2010 -0700
@@ -12339,7 +12339,7 @@
             int start = 0x40, end = 0xFE;
             if (((byte1 < 0) || (byte1 > index1.length))
                 || ((byte2 < start) || (byte2 > end)))
-                return (char)'\uFFFD';
+                return '\uFFFD';
 
             int n = (index1[byte1] & 0xf) * (end - start + 1) + (byte2 - start);
             return index2[index1[byte1] >> 4].charAt(n);
--- a/src/share/classes/sun/nio/cs/ext/HKSCS.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/HKSCS.java	Sun Jun 13 07:40:36 2010 -0700
@@ -43,7 +43,7 @@
 
         private char[][] b2cBmp;
         private char[][] b2cSupp;
-        private static DoubleByte.Decoder big5Dec;
+        private DoubleByte.Decoder big5Dec;
 
         protected Decoder(Charset cs,
                           DoubleByte.Decoder big5Dec,
@@ -355,7 +355,7 @@
                             c2b[hi] = new char[0x100];
                             Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
                         }
-                        c2b[hi][c & 0xff] = (char)bb;
+                        c2b[hi][c & 0xff] = bb;
                     }
                     c++;
                 }
--- a/src/share/classes/sun/nio/cs/ext/ISO2022.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/ISO2022.java	Sun Jun 13 07:40:36 2010 -0700
@@ -104,15 +104,15 @@
             switch(shiftFlag) {
             case SOFlag:
                 tmpIndex = curSODes;
-                tmpDecoder = (CharsetDecoder [])SODecoder;
+                tmpDecoder = SODecoder;
                 break;
             case SS2Flag:
                 tmpIndex = curSS2Des;
-                tmpDecoder = (CharsetDecoder [])SS2Decoder;
+                tmpDecoder = SS2Decoder;
                 break;
             case SS3Flag:
                 tmpIndex = curSS3Des;
-                tmpDecoder = (CharsetDecoder [])SS3Decoder;
+                tmpDecoder = SS3Decoder;
                 break;
             }
 
--- a/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java	Sun Jun 13 07:40:36 2010 -0700
@@ -82,11 +82,11 @@
      * with the sun.io JISAutoDetect implementation
      */
 
-    public byte[] getByteMask1() {
+    public static byte[] getByteMask1() {
         return Decoder.maskTable1;
     }
 
-    public byte[] getByteMask2() {
+    public static byte[] getByteMask2() {
         return Decoder.maskTable2;
     }
 
--- a/src/share/classes/sun/nio/cs/ext/PCK.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/PCK.java	Sun Jun 13 07:40:36 2010 -0700
@@ -101,17 +101,15 @@
     private static class Encoder extends SJIS.Encoder {
 
         private JIS_X_0201.Encoder jis0201;
-        private JIS_X_0208_Solaris_Encoder jis0208;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+            JIS_X_0208_Solaris_Encoder.getIndex1();
+        private static final String[] j0208Index2 =
+            JIS_X_0208_Solaris_Encoder.getIndex2();
 
         private Encoder(Charset cs) {
             super(cs);
             jis0201 = new JIS_X_0201.Encoder(cs);
-            jis0208 = new JIS_X_0208_Solaris_Encoder(cs);
-            j0208Index1 = jis0208.getIndex1();
-            j0208Index2 = jis0208.getIndex2();
         }
 
         protected int encodeDouble(char ch) {
@@ -121,7 +119,7 @@
 
             switch (ch) {
                 case '\u2015':
-                    return (int)0x815C;
+                    return 0x815C;
                 case '\u2014':
                     return 0;
                 default:
--- a/src/share/classes/sun/nio/cs/ext/SJIS.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/share/classes/sun/nio/cs/ext/SJIS.java	Sun Jun 13 07:40:36 2010 -0700
@@ -114,14 +114,14 @@
 
         private JIS_X_0201.Encoder jis0201;
 
-        short[] j0208Index1;
-        String[] j0208Index2;
+        private static final short[] j0208Index1 =
+            JIS_X_0208_Encoder.getIndex1();
+        private static final String[] j0208Index2 =
+            JIS_X_0208_Encoder.getIndex2();
 
         protected Encoder(Charset cs) {
             super(cs);
             jis0201 = new JIS_X_0201.Encoder(cs);
-            j0208Index1 = super.getIndex1();
-            j0208Index2 = super.getIndex2();
         }
 
         protected int encodeSingle(char inputChar) {
--- a/src/solaris/classes/java/lang/UNIXProcess.java.linux	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/solaris/classes/java/lang/UNIXProcess.java.linux	Sun Jun 13 07:40:36 2010 -0700
@@ -25,25 +25,42 @@
 
 package java.lang;
 
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadFactory;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
-/* java.lang.Process subclass in the UNIX environment.
+/**
+ * java.lang.Process subclass in the UNIX environment.
  *
  * @author Mario Wolczko and Ross Knippel.
  * @author Konstantin Kladko (ported to Linux)
+ * @author Martin Buchholz
  */
-
 final class UNIXProcess extends Process {
     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
 
-    private int pid;
+    private final int pid;
     private int exitcode;
     private boolean hasExited;
 
-    private OutputStream stdin_stream;
-    private InputStream  stdout_stream;
-    private InputStream  stderr_stream;
+    private /* final */ OutputStream stdin;
+    private /* final */ InputStream  stdout;
+    private /* final */ InputStream  stderr;
 
     /* this is for the reaping thread */
     private native int waitForProcessExit(int pid);
@@ -51,155 +68,136 @@
     /**
      * Create a process using fork(2) and exec(2).
      *
-     * @param std_fds array of file descriptors.  Indexes 0, 1, and
-     *        2 correspond to standard input, standard output and
-     *        standard error, respectively.  On input, a value of -1
-     *        means to create a pipe to connect child and parent
-     *        processes.  On output, a value which is not -1 is the
-     *        parent pipe fd corresponding to the pipe which has
-     *        been created.  An element of this array is -1 on input
-     *        if and only if it is <em>not</em> -1 on output.
+     * @param fds an array of three file descriptors.
+     *        Indexes 0, 1, and 2 correspond to standard input,
+     *        standard output and standard error, respectively.  On
+     *        input, a value of -1 means to create a pipe to connect
+     *        child and parent processes.  On output, a value which
+     *        is not -1 is the parent pipe fd corresponding to the
+     *        pipe which has been created.  An element of this array
+     *        is -1 on input if and only if it is <em>not</em> -1 on
+     *        output.
      * @return the pid of the subprocess
      */
     private native int forkAndExec(byte[] prog,
                                    byte[] argBlock, int argc,
                                    byte[] envBlock, int envc,
                                    byte[] dir,
-                                   int[] std_fds,
+                                   int[] fds,
                                    boolean redirectErrorStream)
         throws IOException;
 
-    /* In the process constructor we wait on this gate until the process    */
-    /* has been created. Then we return from the constructor.               */
-    /* fork() is called by the same thread which later waits for the process */
-    /* to terminate */
+    /**
+     * The thread factory used to create "process reaper" daemon threads.
+     */
+    private static class ProcessReaperThreadFactory implements ThreadFactory {
+        private final static ThreadGroup group = getRootThreadGroup();
 
-    private static class Gate {
-
-        private boolean exited = false;
-        private IOException savedException;
-
-        synchronized void exit() { /* Opens the gate */
-           exited = true;
-           this.notify();
+        private static ThreadGroup getRootThreadGroup() {
+            return AccessController.doPrivileged
+            (new PrivilegedAction<ThreadGroup> () {
+            public ThreadGroup run() {
+                ThreadGroup root = Thread.currentThread().getThreadGroup();
+                while (root.getParent() != null)
+                    root = root.getParent();
+                return root;
+            }});
         }
 
-        synchronized void waitForExit() { /* wait until the gate is open */
-            boolean interrupted = false;
-            while (!exited) {
-                try {
-                    this.wait();
-                } catch (InterruptedException e) {
-                    interrupted = true;
-                }
-            }
-            if (interrupted) {
-                Thread.currentThread().interrupt();
-            }
-        }
-
-        void setException (IOException e) {
-            savedException = e;
-        }
-
-        IOException getException() {
-            return savedException;
+        public Thread newThread(Runnable grimReaper) {
+            // Our thread stack requirement is quite modest.
+            Thread t = new Thread(group, grimReaper, "process reaper", 32768);
+            t.setDaemon(true);
+            // A small attempt (probably futile) to avoid priority inversion
+            t.setPriority(Thread.MAX_PRIORITY);
+            return t;
         }
     }
 
+    /**
+     * The thread pool of "process reaper" daemon threads.
+     */
+    private static final Executor processReaperExecutor
+        = Executors.newCachedThreadPool(new ProcessReaperThreadFactory());
+
     UNIXProcess(final byte[] prog,
                 final byte[] argBlock, final int argc,
                 final byte[] envBlock, final int envc,
                 final byte[] dir,
-                final int[] std_fds,
+                final int[] fds,
                 final boolean redirectErrorStream)
-    throws IOException {
+            throws IOException {
 
-        final Gate gate = new Gate();
-        /*
-         * For each subprocess forked a corresponding reaper thread
-         * is started.  That thread is the only thread which waits
-         * for the subprocess to terminate and it doesn't hold any
-         * locks while doing so.  This design allows waitFor() and
-         * exitStatus() to be safely executed in parallel (and they
-         * need no native code).
-         */
+        pid = forkAndExec(prog,
+                          argBlock, argc,
+                          envBlock, envc,
+                          dir,
+                          fds,
+                          redirectErrorStream);
 
-        java.security.AccessController.doPrivileged(
-        new java.security.PrivilegedAction<Void>() {
-        public Void run() {
-            Thread t = new Thread("process reaper") {
-                    public void run() {
-                        try {
-                            pid = forkAndExec(prog,
-                                              argBlock, argc,
-                                              envBlock, envc,
-                                              dir,
-                                              std_fds,
-                                              redirectErrorStream);
-                        } catch (IOException e) {
-                            gate.setException(e); /*remember to rethrow later*/
-                            gate.exit();
-                            return;
-                        }
-                        java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<Void>() {
-                    public Void run() {
-                        if (std_fds[0] == -1)
-                            stdin_stream = new ProcessBuilder.NullOutputStream();
-                        else {
-                            FileDescriptor stdin_fd = new FileDescriptor();
-                            fdAccess.set(stdin_fd, std_fds[0]);
-                            stdin_stream = new BufferedOutputStream(
-                                new FileOutputStream(stdin_fd));
-                        }
+        try {
+            AccessController.doPrivileged
+            (new PrivilegedExceptionAction<Void>() {
+                public Void run() throws IOException {
+                    initStreams(fds);
+                    return null;
+                }});
+        } catch (PrivilegedActionException ex) {
+            throw (IOException) ex.getException();
+        }
+    }
 
-                        if (std_fds[1] == -1)
-                            stdout_stream = new ProcessBuilder.NullInputStream();
-                        else {
-                            FileDescriptor stdout_fd = new FileDescriptor();
-                            fdAccess.set(stdout_fd, std_fds[1]);
-                            stdout_stream = new BufferedInputStream(
-                                new FileInputStream(stdout_fd));
-                        }
+    static FileDescriptor newFileDescriptor(int fd) {
+        FileDescriptor fileDescriptor = new FileDescriptor();
+        fdAccess.set(fileDescriptor, fd);
+        return fileDescriptor;
+    }
 
-                        if (std_fds[2] == -1)
-                            stderr_stream = new ProcessBuilder.NullInputStream();
-                        else {
-                            FileDescriptor stderr_fd = new FileDescriptor();
-                            fdAccess.set(stderr_fd, std_fds[2]);
-                            stderr_stream = new FileInputStream(stderr_fd);
-                        }
+    void initStreams(int[] fds) throws IOException {
+        stdin = (fds[0] == -1) ?
+            ProcessBuilder.NullOutputStream.INSTANCE :
+            new ProcessPipeOutputStream(fds[0]);
 
-                        return null; }});
-                        gate.exit(); /* exit from constructor */
-                        int res = waitForProcessExit(pid);
-                        synchronized (UNIXProcess.this) {
-                            hasExited = true;
-                            exitcode = res;
-                            UNIXProcess.this.notifyAll();
-                        }
-                    }
-                };
-                t.setDaemon(true);
-                t.start();
-                return null; }});
-        gate.waitForExit();
-        IOException e = gate.getException();
-        if (e != null)
-            throw new IOException(e.toString());
+        stdout = (fds[1] == -1) ?
+            ProcessBuilder.NullInputStream.INSTANCE :
+            new ProcessPipeInputStream(fds[1]);
+
+        stderr = (fds[2] == -1) ?
+            ProcessBuilder.NullInputStream.INSTANCE :
+            new ProcessPipeInputStream(fds[2]);
+
+        processReaperExecutor.execute(new Runnable() {
+            public void run() {
+                int exitcode = waitForProcessExit(pid);
+                UNIXProcess.this.processExited(exitcode);
+            }});
+    }
+
+    synchronized void processExited(int exitcode) {
+        if (stdout instanceof ProcessPipeInputStream)
+            ((ProcessPipeInputStream) stdout).processExited();
+
+        if (stderr instanceof ProcessPipeInputStream)
+            ((ProcessPipeInputStream) stderr).processExited();
+
+        if (stdin instanceof ProcessPipeOutputStream)
+            ((ProcessPipeOutputStream) stdin).processExited();
+
+        this.exitcode = exitcode;
+        hasExited = true;
+        notifyAll();
     }
 
     public OutputStream getOutputStream() {
-        return stdin_stream;
+        return stdin;
     }
 
     public InputStream getInputStream() {
-        return stdout_stream;
+        return stdout;
     }
 
     public InputStream getErrorStream() {
-        return stderr_stream;
+        return stderr;
     }
 
     public synchronized int waitFor() throws InterruptedException {
@@ -228,13 +226,9 @@
             if (!hasExited)
                 destroyProcess(pid);
         }
-        try {
-            stdin_stream.close();
-            stdout_stream.close();
-            stderr_stream.close();
-        } catch (IOException e) {
-            // ignore
-        }
+        try { stdin.close();  } catch (IOException ignored) {}
+        try { stdout.close(); } catch (IOException ignored) {}
+        try { stderr.close(); } catch (IOException ignored) {}
     }
 
     /* This routine initializes JNI field offsets for the class */
@@ -243,4 +237,77 @@
     static {
         initIDs();
     }
+
+    /**
+     * A buffered input stream for a subprocess pipe file descriptor
+     * that allows the underlying file descriptor to be reclaimed when
+     * the process exits, via the processExited hook.
+     *
+     * This is tricky because we do not want the user-level InputStream to be
+     * closed until the user invokes close(), and we need to continue to be
+     * able to read any buffered data lingering in the OS pipe buffer.
+     */
+    static class ProcessPipeInputStream extends BufferedInputStream {
+        ProcessPipeInputStream(int fd) {
+            super(new FileInputStream(newFileDescriptor(fd)));
+        }
+
+        private static byte[] drainInputStream(InputStream in)
+                throws IOException {
+            if (in == null) return null;
+            int n = 0;
+            int j;
+            byte[] a = null;
+            while ((j = in.available()) > 0) {
+                a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
+                n += in.read(a, n, j);
+            }
+            return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
+        }
+
+        /** Called by the process reaper thread when the process exits. */
+        synchronized void processExited() {
+            // Most BufferedInputStream methods are synchronized, but close()
+            // is not, and so we have to handle concurrent racing close().
+            try {
+                InputStream in = this.in;
+                if (in != null) {
+                    byte[] stragglers = drainInputStream(in);
+                    in.close();
+                    this.in = (stragglers == null) ?
+                        ProcessBuilder.NullInputStream.INSTANCE :
+                        new ByteArrayInputStream(stragglers);
+                    if (buf == null) // asynchronous close()?
+                        this.in = null;
+                }
+            } catch (IOException ignored) {
+                // probably an asynchronous close().
+            }
+        }
+    }
+
+    /**
+     * A buffered output stream for a subprocess pipe file descriptor
+     * that allows the underlying file descriptor to be reclaimed when
+     * the process exits, via the processExited hook.
+     */
+    static class ProcessPipeOutputStream extends BufferedOutputStream {
+        ProcessPipeOutputStream(int fd) {
+            super(new FileOutputStream(newFileDescriptor(fd)));
+        }
+
+        /** Called by the process reaper thread when the process exits. */
+        synchronized void processExited() {
+            OutputStream out = this.out;
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException ignored) {
+                    // We know of no reason to get an IOException, but if
+                    // we do, there's nothing else to do but carry on.
+                }
+                this.out = ProcessBuilder.NullOutputStream.INSTANCE;
+            }
+        }
+    }
 }
--- a/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java	Sun Jun 13 07:40:36 2010 -0700
@@ -43,8 +43,8 @@
      * cannot be used for actual encoding because they are shared across all
      * COMPOUND_TEXT encoders and may be stateful.
      */
-    private static final Map encodingToEncoderMap =
-        Collections.synchronizedMap(new HashMap(21, 1.0f));
+    private static final Map<String,CharsetEncoder> encodingToEncoderMap =
+      Collections.synchronizedMap(new HashMap<String,CharsetEncoder>(21, 1.0f));
     private static final CharsetEncoder latin1Encoder;
     private static final CharsetEncoder defaultEncoder;
     private static final boolean defaultEncodingSupported;
@@ -221,7 +221,7 @@
             out.put((byte)0x1B);
             out.put((byte)0x25);
             out.put((byte)0x2F);
-            out.put((byte)nonStandardBytes[3]);
+            out.put(nonStandardBytes[3]);
 
             int toWrite = Math.min(numBytes - nonStandardBytesOff,
                                    (1 << 14) - 1 - nonStandardEncodingLen);
@@ -313,12 +313,9 @@
         }
 
         // 4. Brute force search of all supported encodings.
-        for (Iterator iter = CompoundTextSupport.getEncodings().iterator();
-             iter.hasNext();)
+        for (String encoding : CompoundTextSupport.getEncodings())
         {
-            String encoding = (String)iter.next();
-            CharsetEncoder enc =
-                (CharsetEncoder)encodingToEncoderMap.get(encoding);
+            CharsetEncoder enc = encodingToEncoderMap.get(encoding);
             if (enc == null) {
                 enc = CompoundTextSupport.getEncoder(encoding);
                 if (enc == null) {
--- a/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java	Sun Jun 13 07:40:36 2010 -0700
@@ -130,13 +130,13 @@
     /**
      * Maps a GL or GR escape sequence to an encoding.
      */
-    private static final Map sequenceToEncodingMap;
+    private static final Map<ControlSequence, String> sequenceToEncodingMap;
 
     /**
      * Indicates whether a particular encoding wants the high bit turned on
      * or off.
      */
-    private static final Map highBitsMap;
+    private static final Map<ControlSequence, Boolean> highBitsMap;
 
     /**
      * Maps an encoding to an escape sequence. Rather than manage two
@@ -144,18 +144,21 @@
      * modify both GL and GR if necessary. This makes the output slightly less
      * efficient, but our code much simpler.
      */
-    private static final Map encodingToSequenceMap;
+    private static final Map<String, ControlSequence> encodingToSequenceMap;
 
     /**
      * The keys of 'encodingToSequenceMap', sorted in preferential order.
      */
-    private static final List encodings;
+    private static final List<String> encodings;
 
     static {
-        HashMap tSequenceToEncodingMap = new HashMap(33, 1.0f);
-        HashMap tHighBitsMap = new HashMap(31, 1.0f);
-        HashMap tEncodingToSequenceMap = new HashMap(21, 1.0f);
-        ArrayList tEncodings = new ArrayList(21);
+        HashMap<ControlSequence, String> tSequenceToEncodingMap =
+            new HashMap<>(33, 1.0f);
+        HashMap<ControlSequence, Boolean> tHighBitsMap =
+            new HashMap<>(31, 1.0f);
+        HashMap<String, ControlSequence> tEncodingToSequenceMap =
+            new HashMap<>(21, 1.0f);
+        ArrayList<String> tEncodings = new ArrayList<>(21);
 
         if (!(isEncodingSupported("US-ASCII") &&
               isEncodingSupported("ISO-8859-1")))
@@ -457,13 +460,12 @@
         return getNonStandardDecoder(escSequence, null);
     }
     static boolean getHighBit(byte[] escSequence) {
-        Boolean bool = (Boolean)highBitsMap.get
-            (new ControlSequence(escSequence));
+        Boolean bool = highBitsMap.get(new ControlSequence(escSequence));
         return (bool == Boolean.TRUE);
     }
     static CharsetDecoder getNonStandardDecoder(byte[] escSequence,
                                                        byte[] encoding) {
-        return getDecoder((String)sequenceToEncodingMap.get
+        return getDecoder(sequenceToEncodingMap.get
             (new ControlSequence(escSequence, encoding)));
     }
     static CharsetDecoder getDecoder(String enc) {
@@ -474,7 +476,7 @@
         try {
             cs = Charset.forName(enc);
         } catch (IllegalArgumentException e) {
-            Class cls;
+            Class<?> cls;
             try {
                 cls = Class.forName("sun.awt.motif." + enc);
             } catch (ClassNotFoundException ee) {
@@ -497,22 +499,20 @@
 
     // For Encoder
     static byte[] getEscapeSequence(String encoding) {
-        ControlSequence seq = (ControlSequence)
-            encodingToSequenceMap.get(encoding);
+        ControlSequence seq = encodingToSequenceMap.get(encoding);
         if (seq != null) {
             return seq.escSequence;
         }
         return null;
     }
     static byte[] getEncoding(String encoding) {
-        ControlSequence seq = (ControlSequence)
-            encodingToSequenceMap.get(encoding);
+        ControlSequence seq = encodingToSequenceMap.get(encoding);
         if (seq != null) {
             return seq.encoding;
         }
         return null;
     }
-    static List getEncodings() {
+    static List<String> getEncodings() {
         return encodings;
     }
     static CharsetEncoder getEncoder(String enc) {
@@ -523,7 +523,7 @@
         try {
             cs = Charset.forName(enc);
         } catch (IllegalArgumentException e) {
-            Class cls;
+            Class<?> cls;
             try {
                 cls = Class.forName("sun.awt.motif." + enc);
             } catch (ClassNotFoundException ee) {
--- a/test/java/lang/ProcessBuilder/Basic.java	Sat Jun 12 00:42:51 2010 -0700
+++ b/test/java/lang/ProcessBuilder/Basic.java	Sun Jun 13 07:40:36 2010 -0700
@@ -37,6 +37,7 @@
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.CountDownLatch;
 import java.security.*;
 import java.util.regex.Pattern;
 import static java.lang.System.getenv;
@@ -252,9 +253,9 @@
         return sb.toString();
     }
 
-    static void print4095(OutputStream s) throws Throwable {
+    static void print4095(OutputStream s, byte b) throws Throwable {
         byte[] bytes = new byte[4095];
-        Arrays.fill(bytes, (byte) '!');
+        Arrays.fill(bytes, b);
         s.write(bytes);         // Might hang!
     }
 
@@ -273,7 +274,9 @@
     public static class JavaChild {
         public static void main(String args[]) throws Throwable {
             String action = args[0];
-            if (action.equals("testIO")) {
+            if (action.equals("sleep")) {
+                Thread.sleep(10 * 60 * 1000L);
+            } else if (action.equals("testIO")) {
                 String expected = "standard input";
                 char[] buf = new char[expected.length()+1];
                 int n = new InputStreamReader(System.in).read(buf,0,buf.length);
@@ -315,7 +318,8 @@
                 printUTF8(new File(System.getProperty("user.dir"))
                           .getCanonicalPath());
             } else if (action.equals("print4095")) {
-                print4095(System.out);
+                print4095(System.out, (byte) '!');
+                print4095(System.err, (byte) 'E');
                 System.exit(5);
             } else if (action.equals("OutErr")) {
                 // You might think the system streams would be
@@ -1717,16 +1721,107 @@
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
-        // This would deadlock, if not for the fact that
+        // Attempt to write 4095 bytes to the pipe buffer without a
+        // reader to drain it would deadlock, if not for the fact that
         // interprocess pipe buffers are at least 4096 bytes.
+        //
+        // Also, check that available reports all the bytes expected
+        // in the pipe buffer, and that I/O operations do the expected
+        // things.
         //----------------------------------------------------------------
         try {
             List<String> childArgs = new ArrayList<String>(javaChildArgs);
             childArgs.add("print4095");
-            Process p = new ProcessBuilder(childArgs).start();
-            print4095(p.getOutputStream()); // Might hang!
-            p.waitFor();                    // Might hang!
+            final int SIZE = 4095;
+            final Process p = new ProcessBuilder(childArgs).start();
+            print4095(p.getOutputStream(), (byte) '!'); // Might hang!
+            p.waitFor();                                // Might hang!
+            equal(SIZE, p.getInputStream().available());
+            equal(SIZE, p.getErrorStream().available());
+            THROWS(IOException.class,
+                   new Fun(){void f() throws IOException {
+                       p.getOutputStream().write((byte) '!');
+                       p.getOutputStream().flush();
+                       }});
+
+            final byte[] bytes = new byte[SIZE + 1];
+            equal(SIZE, p.getInputStream().read(bytes));
+            for (int i = 0; i < SIZE; i++)
+                equal((byte) '!', bytes[i]);
+            equal((byte) 0, bytes[SIZE]);
+
+            equal(SIZE, p.getErrorStream().read(bytes));
+            for (int i = 0; i < SIZE; i++)
+                equal((byte) 'E', bytes[i]);
+            equal((byte) 0, bytes[SIZE]);
+
+            equal(0, p.getInputStream().available());
+            equal(0, p.getErrorStream().available());
+            equal(-1, p.getErrorStream().read());
+            equal(-1, p.getInputStream().read());
+
             equal(p.exitValue(), 5);
+
+            p.getInputStream().close();
+            p.getErrorStream().close();
+            p.getOutputStream().close();
+
+            InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
+            for (final InputStream in : streams) {
+                Fun[] ops = {
+                    new Fun(){void f() throws IOException {
+                        in.read(); }},
+                    new Fun(){void f() throws IOException {
+                        in.read(bytes); }},
+                    new Fun(){void f() throws IOException {
+                        in.available(); }}
+                };
+                for (Fun op : ops) {
+                    try {
+                        op.f();
+                        fail();
+                    } catch (IOException expected) {
+                        check(expected.getMessage()
+                              .matches("[Ss]tream [Cc]losed"));
+                    }
+                }
+            }
+        } catch (Throwable t) { unexpected(t); }
+
+        //----------------------------------------------------------------
+        // Check that reads which are pending when Process.destroy is
+        // called, get EOF, not IOException("Stream closed").
+        //----------------------------------------------------------------
+        try {
+            final int cases = 4;
+            for (int i = 0; i < cases; i++) {
+                final int action = i;
+                List<String> childArgs = new ArrayList<String>(javaChildArgs);
+                childArgs.add("sleep");
+                final byte[] bytes = new byte[10];
+                final Process p = new ProcessBuilder(childArgs).start();
+                final CountDownLatch latch = new CountDownLatch(1);
+                final Thread thread = new Thread() {
+                    public void run() {
+                        try {
+                            latch.countDown();
+                            int r;
+                            switch (action) {
+                            case 0: r = p.getInputStream().read(); break;
+                            case 1: r = p.getErrorStream().read(); break;
+                            case 2: r = p.getInputStream().read(bytes); break;
+                            case 3: r = p.getErrorStream().read(bytes); break;
+                            default: throw new Error();
+                            }
+                            equal(-1, r);
+                        } catch (Throwable t) { unexpected(t); }}};
+
+                thread.start();
+                latch.await();
+                Thread.sleep(10);
+                p.destroy();
+                thread.join();
+            }
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
@@ -1741,7 +1836,6 @@
         } catch (IOException e) {
             new File("./emptyCommand").delete();
             String m = e.getMessage();
-            //e.printStackTrace();
             if (EnglishUnix.is() &&
                 ! matches(m, "Permission denied"))
                 unexpected(e);