diff --git a/make/sun/nio/cs/Makefile b/make/sun/nio/cs/Makefile index ff2f8ca16956e592376b3899bf190fc596db13d6..26437efca824fa8e44395ee67187c37aaa3e2bd5 100644 --- a/make/sun/nio/cs/Makefile +++ b/make/sun/nio/cs/Makefile @@ -37,7 +37,7 @@ PRODUCT = sun # 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 # diff --git a/src/share/classes/java/lang/ProcessBuilder.java b/src/share/classes/java/lang/ProcessBuilder.java index 82fad4a2b42b2f9ca9c45a55ee2ffa9ec3c6922b..97ce45cdf658eccb2d0e29119d4c82c98cae0c40 100644 --- a/src/share/classes/java/lang/ProcessBuilder.java +++ b/src/share/classes/java/lang/ProcessBuilder.java @@ -418,6 +418,8 @@ public final class ProcessBuilder * Implements a null input stream. */ 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 @@ public final class ProcessBuilder * Implements a null output stream. */ 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"); } diff --git a/src/share/classes/sun/io/ByteToCharISO2022.java b/src/share/classes/sun/io/ByteToCharISO2022.java index 4b2e21b56966ab1ef2d32b15d1010ce4fa521ccc..5fef812fd21d884cfe58ee2921d1025ada44203d 100644 --- a/src/share/classes/sun/io/ByteToCharISO2022.java +++ b/src/share/classes/sun/io/ByteToCharISO2022.java @@ -124,15 +124,15 @@ public abstract class ByteToCharISO2022 extends ByteToCharConverter 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; } diff --git a/src/share/classes/sun/io/ByteToCharISO2022JP.java b/src/share/classes/sun/io/ByteToCharISO2022JP.java index 8000870fbba7068d13b8ee0dde4ddd1cbb632857..03027c24732bb80321133256c4969b5bd5514852 100644 --- a/src/share/classes/sun/io/ByteToCharISO2022JP.java +++ b/src/share/classes/sun/io/ByteToCharISO2022JP.java @@ -141,7 +141,7 @@ public class ByteToCharISO2022JP extends ByteToCharJIS0208 { } else { savedSize = 2; savedBytes[0] = (byte)byte1; - savedBytes[1] = (byte)input[readOff + inputSize]; + savedBytes[1] = input[readOff + inputSize]; inputSize++; } break; diff --git a/src/share/classes/sun/io/ByteToCharJISAutoDetect.java b/src/share/classes/sun/io/ByteToCharJISAutoDetect.java index 97a0e88280748ebc8d516ab7909a28651a2a6c31..8f00ef6c233a641d9396c6b39c1eda4bb531fe53 100644 --- a/src/share/classes/sun/io/ByteToCharJISAutoDetect.java +++ b/src/share/classes/sun/io/ByteToCharJISAutoDetect.java @@ -34,14 +34,12 @@ public class ByteToCharJISAutoDetect extends ByteToCharConverter { 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 @@ public class ByteToCharJISAutoDetect extends ByteToCharConverter { 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 @@ public class ByteToCharJISAutoDetect extends ByteToCharConverter { 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 @@ public class ByteToCharJISAutoDetect extends ByteToCharConverter { // 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) { diff --git a/src/share/classes/sun/io/CharToBytePCK.java b/src/share/classes/sun/io/CharToBytePCK.java index 0c877df0e575d399c8ac45dcd3dbbf1b16279a80..9a8d1a76cea142d872f746e2bcf3f518a6a41d16 100644 --- a/src/share/classes/sun/io/CharToBytePCK.java +++ b/src/share/classes/sun/io/CharToBytePCK.java @@ -66,7 +66,7 @@ public class CharToBytePCK extends CharToByteSJIS { switch (ch) { case '\u2015': - return (int)0x815C; + return 0x815C; case '\u2014': return 0; default: diff --git a/src/share/classes/sun/nio/cs/ext/DoubleByte.java b/src/share/classes/sun/nio/cs/ext/DoubleByte.java index f76c9cc7d739d5186a2d49b104212a41dac156ee..265e03c71f4cc75cc834724e88eb2e3ffbbb08a8 100644 --- a/src/share/classes/sun/nio/cs/ext/DoubleByte.java +++ b/src/share/classes/sun/nio/cs/ext/DoubleByte.java @@ -103,7 +103,7 @@ public class DoubleByte { 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 @@ public class DoubleByte { 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); diff --git a/src/share/classes/sun/nio/cs/ext/EUC_JP.java b/src/share/classes/sun/nio/cs/ext/EUC_JP.java index 03de2483456108b17e918d018a9ae169cdb2b0f4..6443de39931537a46474e2bd81addc12d242eea3 100644 --- a/src/share/classes/sun/nio/cs/ext/EUC_JP.java +++ b/src/share/classes/sun/nio/cs/ext/EUC_JP.java @@ -79,8 +79,10 @@ public class EUC_JP 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 @@ public class EUC_JP 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 @@ public class EUC_JP 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 @@ public class EUC_JP 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) { diff --git a/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java b/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java index fbbd30b1324522b68fa286384df00158502d4016..480a4a74067893fcad16793b9722524212249c52 100644 --- a/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java +++ b/src/share/classes/sun/nio/cs/ext/EUC_JP_LINUX.java @@ -65,20 +65,18 @@ public class EUC_JP_LINUX 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 @@ public class EUC_JP_LINUX } 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 @@ public class EUC_JP_LINUX 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) { diff --git a/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java b/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java index 4043dc1ad26591ba81ce2a315f69db38b575b090..b36b76d3c75159670bec9df7598a8e8ec1d67fe3 100644 --- a/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java +++ b/src/share/classes/sun/nio/cs/ext/EUC_JP_Open.java @@ -75,8 +75,12 @@ public class EUC_JP_Open 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 @@ public class EUC_JP_Open 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 @@ public class EUC_JP_Open } 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 @@ public class EUC_JP_Open 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 @@ public class EUC_JP_Open 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 @@ public class EUC_JP_Open 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) { diff --git a/src/share/classes/sun/nio/cs/ext/EUC_TW.java b/src/share/classes/sun/nio/cs/ext/EUC_TW.java index 368b471906b039ef3272ab8a7ae284b8260c6846..a4ae8df6e98de04a71154f409ae257f2c461af55 100644 --- a/src/share/classes/sun/nio/cs/ext/EUC_TW.java +++ b/src/share/classes/sun/nio/cs/ext/EUC_TW.java @@ -423,7 +423,7 @@ public class EUC_TW extends Charset implements HistoricallyNamedCharset 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; diff --git a/src/share/classes/sun/nio/cs/ext/GB18030.java b/src/share/classes/sun/nio/cs/ext/GB18030.java index 20df56007ef3befcb2638de2f519d0a1b5f07aac..acbe23a36d6c74f5e49c7f08baeb53720adc2dd5 100644 --- a/src/share/classes/sun/nio/cs/ext/GB18030.java +++ b/src/share/classes/sun/nio/cs/ext/GB18030.java @@ -12339,7 +12339,7 @@ public class GB18030 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); diff --git a/src/share/classes/sun/nio/cs/ext/HKSCS.java b/src/share/classes/sun/nio/cs/ext/HKSCS.java index d2e118e01e9501c7c2b08ae38d0d5c15e959e860..69002ee2b82d660a5633f899c40085068e9579d0 100644 --- a/src/share/classes/sun/nio/cs/ext/HKSCS.java +++ b/src/share/classes/sun/nio/cs/ext/HKSCS.java @@ -43,7 +43,7 @@ public class HKSCS { 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 @@ public class HKSCS { c2b[hi] = new char[0x100]; Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING); } - c2b[hi][c & 0xff] = (char)bb; + c2b[hi][c & 0xff] = bb; } c++; } diff --git a/src/share/classes/sun/nio/cs/ext/ISO2022.java b/src/share/classes/sun/nio/cs/ext/ISO2022.java index faf8036990ce864992096d947115402e995e47bb..ad4e5978b12beb30029d727d399842e659ec7d21 100644 --- a/src/share/classes/sun/nio/cs/ext/ISO2022.java +++ b/src/share/classes/sun/nio/cs/ext/ISO2022.java @@ -104,15 +104,15 @@ abstract class ISO2022 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; } diff --git a/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java b/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java index 78007a02a089a12a20a4834bfb2e9821861bae56..e190bd587e31e124da33640f87cdca346d2cbe50 100644 --- a/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java +++ b/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java @@ -82,11 +82,11 @@ public class JISAutoDetect * 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; } diff --git a/src/share/classes/sun/nio/cs/ext/PCK.java b/src/share/classes/sun/nio/cs/ext/PCK.java index a11a9dda5c157bc338bf348bff046296663fac5a..2c2387e0001bbf0153abeede7ddaf018097864ed 100644 --- a/src/share/classes/sun/nio/cs/ext/PCK.java +++ b/src/share/classes/sun/nio/cs/ext/PCK.java @@ -101,17 +101,15 @@ public class PCK 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 @@ public class PCK switch (ch) { case '\u2015': - return (int)0x815C; + return 0x815C; case '\u2014': return 0; default: diff --git a/src/share/classes/sun/nio/cs/ext/SJIS.java b/src/share/classes/sun/nio/cs/ext/SJIS.java index 65a03aea1e6366ff330fd06c3085b12b9ed82295..1f8a8ea0ce2cfac3104fd1bcb41ec9ab60c16b6c 100644 --- a/src/share/classes/sun/nio/cs/ext/SJIS.java +++ b/src/share/classes/sun/nio/cs/ext/SJIS.java @@ -114,14 +114,14 @@ public class SJIS 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) { diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.linux b/src/solaris/classes/java/lang/UNIXProcess.java.linux index 00eef09d43111f1b86efd47cac2de9f9cda84924..af68ce18e6b63b4275f9bdc70b9f644af626765e 100644 --- a/src/solaris/classes/java/lang/UNIXProcess.java.linux +++ b/src/solaris/classes/java/lang/UNIXProcess.java.linux @@ -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 @@ final class UNIXProcess extends Process { /** * 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 not -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 not -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 */ - - private static class Gate { - - private boolean exited = false; - private IOException savedException; - - synchronized void exit() { /* Opens the gate */ - exited = true; - this.notify(); - } - - 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(); - } - } + /** + * The thread factory used to create "process reaper" daemon threads. + */ + private static class ProcessReaperThreadFactory implements ThreadFactory { + private final static ThreadGroup group = getRootThreadGroup(); - void setException (IOException e) { - savedException = e; + private static ThreadGroup getRootThreadGroup() { + return AccessController.doPrivileged + (new PrivilegedAction () { + public ThreadGroup run() { + ThreadGroup root = Thread.currentThread().getThreadGroup(); + while (root.getParent() != null) + root = root.getParent(); + return root; + }}); } - 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 { - - 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). - */ - - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - 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() { - 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)); - } - - 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)); - } - - 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); - } - - 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()); + throws IOException { + + pid = forkAndExec(prog, + argBlock, argc, + envBlock, envc, + dir, + fds, + redirectErrorStream); + + try { + AccessController.doPrivileged + (new PrivilegedExceptionAction() { + public Void run() throws IOException { + initStreams(fds); + return null; + }}); + } catch (PrivilegedActionException ex) { + throw (IOException) ex.getException(); + } + } + + static FileDescriptor newFileDescriptor(int fd) { + FileDescriptor fileDescriptor = new FileDescriptor(); + fdAccess.set(fileDescriptor, fd); + return fileDescriptor; + } + + void initStreams(int[] fds) throws IOException { + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new ProcessPipeOutputStream(fds[0]); + + 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 @@ final class UNIXProcess extends Process { 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 @@ final class UNIXProcess extends Process { 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; + } + } + } } diff --git a/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java b/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java index e7cc9c1b112c67c03aa2251b3fb059c135035ac3..d73a21b986420e97e2c339b0e9cc0ca53b0d648e 100644 --- a/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java +++ b/src/solaris/classes/sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java @@ -43,8 +43,8 @@ public class COMPOUND_TEXT_Encoder extends CharsetEncoder { * 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 encodingToEncoderMap = + Collections.synchronizedMap(new HashMap(21, 1.0f)); private static final CharsetEncoder latin1Encoder; private static final CharsetEncoder defaultEncoder; private static final boolean defaultEncodingSupported; @@ -221,7 +221,7 @@ public class COMPOUND_TEXT_Encoder extends CharsetEncoder { 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 @@ public class COMPOUND_TEXT_Encoder extends CharsetEncoder { } // 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) { diff --git a/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java b/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java index 07c87af26aeeffa75f5772a175f51dc0e99e7de7..4f2a047110c7c161fb1dde88de9e430307b76674 100644 --- a/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java +++ b/src/solaris/classes/sun/nio/cs/ext/CompoundTextSupport.java @@ -130,13 +130,13 @@ final class CompoundTextSupport { /** * Maps a GL or GR escape sequence to an encoding. */ - private static final Map sequenceToEncodingMap; + private static final Map sequenceToEncodingMap; /** * Indicates whether a particular encoding wants the high bit turned on * or off. */ - private static final Map highBitsMap; + private static final Map highBitsMap; /** * Maps an encoding to an escape sequence. Rather than manage two @@ -144,18 +144,21 @@ final class CompoundTextSupport { * 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 encodingToSequenceMap; /** * The keys of 'encodingToSequenceMap', sorted in preferential order. */ - private static final List encodings; + private static final List 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 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); if (!(isEncodingSupported("US-ASCII") && isEncodingSupported("ISO-8859-1"))) @@ -457,13 +460,12 @@ final class CompoundTextSupport { 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 @@ final class CompoundTextSupport { 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 @@ final class CompoundTextSupport { // 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 getEncodings() { return encodings; } static CharsetEncoder getEncoder(String enc) { @@ -523,7 +523,7 @@ final class CompoundTextSupport { try { cs = Charset.forName(enc); } catch (IllegalArgumentException e) { - Class cls; + Class cls; try { cls = Class.forName("sun.awt.motif." + enc); } catch (ClassNotFoundException ee) { diff --git a/test/java/lang/ProcessBuilder/Basic.java b/test/java/lang/ProcessBuilder/Basic.java index e14f665a62a370845bff4858f77d159f0ae6727b..f4e3c26d9ee718b235382805c4982a4b72d659f5 100644 --- a/test/java/lang/ProcessBuilder/Basic.java +++ b/test/java/lang/ProcessBuilder/Basic.java @@ -37,6 +37,7 @@ import static java.lang.ProcessBuilder.Redirect.*; 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 @@ public class Basic { 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 class Basic { 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 @@ public class Basic { 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 @@ public class Basic { } 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 childArgs = new ArrayList(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 childArgs = new ArrayList(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 @@ public class Basic { } catch (IOException e) { new File("./emptyCommand").delete(); String m = e.getMessage(); - //e.printStackTrace(); if (EnglishUnix.is() && ! matches(m, "Permission denied")) unexpected(e);