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);