This commit is contained in:
Phil Race 2019-05-02 10:48:56 -07:00
commit 501a6f3423
968 changed files with 30359 additions and 14876 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -261,6 +261,11 @@ public class LineNumberReader extends BufferedReader {
*/
public void mark(int readAheadLimit) throws IOException {
synchronized (lock) {
// If the most recently read character is '\r', then increment the
// read ahead limit as in this case if the next character is '\n',
// two characters would actually be read by the next read().
if (skipLF)
readAheadLimit++;
super.mark(readAheadLimit);
markedLineNumber = lineNumber;
markedSkipLF = skipLF;

View file

@ -1893,6 +1893,16 @@ public abstract class ClassLoader {
* otherwise, if unnamed, it will set the class path to the current
* working directory.
*
* <p> JAR files on the class path may contain a {@code Class-Path} manifest
* attribute to specify dependent JAR files to be included in the class path.
* {@code Class-Path} entries must meet certain conditions for validity (see
* the <a href="{@docRoot}/../specs/jar/jar.html#class-path-attribute">
* JAR File Specification</a> for details). Invalid {@code Class-Path}
* entries are ignored. For debugging purposes, ignored entries can be
* printed to the console if the
* {@systemProperty jdk.net.URLClassPath.showIgnoredClassPathEntries} system
* property is set to {@code true}.
*
* @return The system {@code ClassLoader}
*
* @throws SecurityException

View file

@ -1020,9 +1020,8 @@ public final class String
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
@ -1057,7 +1056,8 @@ public final class String
}
byte v1[] = value;
byte v2[] = sb.getValue();
if (coder() == sb.getCoder()) {
byte coder = coder();
if (coder == sb.getCoder()) {
int n = v1.length;
for (int i = 0; i < n; i++) {
if (v1[i] != v2[i]) {
@ -1065,7 +1065,7 @@ public final class String
}
}
} else {
if (!isLatin1()) { // utf16 str and latin1 abs can never be "equal"
if (coder != LATIN1) { // utf16 str and latin1 abs can never be "equal"
return false;
}
return StringUTF16.contentEquals(v1, v2, len);
@ -1209,12 +1209,13 @@ public final class String
public int compareTo(String anotherString) {
byte v1[] = value;
byte v2[] = anotherString.value;
if (coder() == anotherString.coder()) {
return isLatin1() ? StringLatin1.compareTo(v1, v2)
: StringUTF16.compareTo(v1, v2);
byte coder = coder();
if (coder == anotherString.coder()) {
return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
: StringUTF16.compareTo(v1, v2);
}
return isLatin1() ? StringLatin1.compareToUTF16(v1, v2)
: StringUTF16.compareToLatin1(v1, v2);
return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
: StringUTF16.compareToLatin1(v1, v2);
}
/**
@ -1238,12 +1239,13 @@ public final class String
public int compare(String s1, String s2) {
byte v1[] = s1.value;
byte v2[] = s2.value;
if (s1.coder() == s2.coder()) {
return s1.isLatin1() ? StringLatin1.compareToCI(v1, v2)
: StringUTF16.compareToCI(v1, v2);
byte coder = s1.coder();
if (coder == s2.coder()) {
return coder == LATIN1 ? StringLatin1.compareToCI(v1, v2)
: StringUTF16.compareToCI(v1, v2);
}
return s1.isLatin1() ? StringLatin1.compareToCI_UTF16(v1, v2)
: StringUTF16.compareToCI_Latin1(v1, v2);
return coder == LATIN1 ? StringLatin1.compareToCI_UTF16(v1, v2)
: StringUTF16.compareToCI_Latin1(v1, v2);
}
/** Replaces the de-serialized object. */
@ -1317,7 +1319,8 @@ public final class String
(ooffset > (long)other.length() - len)) {
return false;
}
if (coder() == other.coder()) {
byte coder = coder();
if (coder == other.coder()) {
if (!isLatin1() && (len > 0)) {
toffset = toffset << 1;
ooffset = ooffset << 1;
@ -1329,7 +1332,7 @@ public final class String
}
}
} else {
if (coder() == LATIN1) {
if (coder == LATIN1) {
while (len-- > 0) {
if (StringLatin1.getChar(tv, toffset++) !=
StringUTF16.getChar(ov, ooffset++)) {
@ -1411,12 +1414,13 @@ public final class String
}
byte tv[] = value;
byte ov[] = other.value;
if (coder() == other.coder()) {
return isLatin1()
byte coder = coder();
if (coder == other.coder()) {
return coder == LATIN1
? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len)
: StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len);
}
return isLatin1()
return coder == LATIN1
? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len)
: StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len);
}
@ -1447,15 +1451,16 @@ public final class String
byte pa[] = prefix.value;
int po = 0;
int pc = pa.length;
if (coder() == prefix.coder()) {
int to = isLatin1() ? toffset : toffset << 1;
byte coder = coder();
if (coder == prefix.coder()) {
int to = (coder == LATIN1) ? toffset : toffset << 1;
while (po < pc) {
if (ta[to++] != pa[po++]) {
return false;
}
}
} else {
if (isLatin1()) { // && pcoder == UTF16
if (coder == LATIN1) { // && pcoder == UTF16
return false;
}
// coder == UTF16 && pcoder == LATIN1)
@ -1688,11 +1693,12 @@ public final class String
* or {@code -1} if there is no such occurrence.
*/
public int indexOf(String str) {
if (coder() == str.coder()) {
byte coder = coder();
if (coder == str.coder()) {
return isLatin1() ? StringLatin1.indexOf(value, str.value)
: StringUTF16.indexOf(value, str.value);
}
if (coder() == LATIN1) { // str.coder == UTF16
if (coder == LATIN1) { // str.coder == UTF16
return -1;
}
return StringUTF16.indexOfLatin1(value, str.value);

View file

@ -144,7 +144,7 @@ final class StringConcatHelper {
* @param value boolean value to encode
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, boolean value) {
private static long prepend(long indexCoder, byte[] buf, boolean value) {
int index = (int)indexCoder;
if (indexCoder < UTF16) {
if (value) {
@ -178,17 +178,41 @@ final class StringConcatHelper {
}
/**
* Prepends the stringly representation of byte value into buffer,
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param value byte value to encode
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, byte value) {
return prepend(indexCoder, buf, (int)value);
static long prepend(long indexCoder, byte[] buf, String prefix, boolean value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String prefix, byte value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, (int)value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
@ -201,7 +225,7 @@ final class StringConcatHelper {
* @param value char value to encode
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, char value) {
private static long prepend(long indexCoder, byte[] buf, char value) {
if (indexCoder < UTF16) {
buf[(int)(--indexCoder)] = (byte) (value & 0xFF);
} else {
@ -211,17 +235,41 @@ final class StringConcatHelper {
}
/**
* Prepends the stringly representation of short value into buffer,
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param value short value to encode
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, short value) {
return prepend(indexCoder, buf, (int)value);
static long prepend(long indexCoder, byte[] buf, String prefix, char value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String prefix, short value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, (int)value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
@ -234,7 +282,7 @@ final class StringConcatHelper {
* @param value integer value to encode
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, int value) {
private static long prepend(long indexCoder, byte[] buf, int value) {
if (indexCoder < UTF16) {
return Integer.getChars(value, (int)indexCoder, buf);
} else {
@ -242,6 +290,25 @@ final class StringConcatHelper {
}
}
/**
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String prefix, int value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
* Prepends the stringly representation of long value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
@ -252,7 +319,7 @@ final class StringConcatHelper {
* @param value long value to encode
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, long value) {
private static long prepend(long indexCoder, byte[] buf, long value) {
if (indexCoder < UTF16) {
return Long.getChars(value, (int)indexCoder, buf);
} else {
@ -260,6 +327,25 @@ final class StringConcatHelper {
}
}
/**
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String prefix, long value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
* Prepends the stringly representation of String value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
@ -270,7 +356,7 @@ final class StringConcatHelper {
* @param value String value to encode
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String value) {
private static long prepend(long indexCoder, byte[] buf, String value) {
indexCoder -= value.length();
if (indexCoder < UTF16) {
value.getBytes(buf, (int)indexCoder, String.LATIN1);
@ -280,6 +366,25 @@ final class StringConcatHelper {
return indexCoder;
}
/**
* Prepends constant and the stringly representation of value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @param indexCoder final char index in the buffer, along with coder packed
* into higher bits.
* @param buf buffer to append to
* @param prefix a constant to prepend before value
* @param value boolean value to encode
* @param suffix a constant to prepend after value
* @return updated index (coder value retained)
*/
static long prepend(long indexCoder, byte[] buf, String prefix, String value, String suffix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder;
}
/**
* Instantiates the String with given buffer and coder
* @param buf buffer to use

View file

@ -193,11 +193,6 @@ class Thread implements Runnable {
*/
private final long stackSize;
/*
* JVM-private state that persists after native thread termination.
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/

View file

@ -72,7 +72,7 @@ public interface ClassDesc
*
* @param name the fully qualified (dot-separated) binary class name
* @return a {@linkplain ClassDesc} describing the desired class
* @throws NullPointerException if any argument is {@code null}
* @throws NullPointerException if the argument is {@code null}
* @throws IllegalArgumentException if the name string is not in the
* correct format
*/
@ -123,7 +123,7 @@ public interface ClassDesc
*
* @param descriptor a field descriptor string
* @return a {@linkplain ClassDesc} describing the desired class
* @throws NullPointerException if any argument is {@code null}
* @throws NullPointerException if the argument is {@code null}
* @throws IllegalArgumentException if the name string is not in the
* correct format
* @jvms 4.3.2 Field Descriptors
@ -193,7 +193,7 @@ public interface ClassDesc
*
* @param nestedName the unqualified name of the nested class
* @return a {@linkplain ClassDesc} describing the nested class
* @throws NullPointerException if any argument is {@code null}
* @throws NullPointerException if the argument is {@code null}
* @throws IllegalStateException if this {@linkplain ClassDesc} does not
* describe a class or interface type
* @throws IllegalArgumentException if the nested class name is invalid

View file

@ -25,6 +25,7 @@
package java.lang.invoke;
import jdk.internal.access.SharedSecrets;
import jdk.internal.loader.BootLoader;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
@ -37,6 +38,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -575,19 +577,19 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
// load class
InvokerBytecodeGenerator.maybeDump(classBCName(className), classFile);
Class<?> speciesCode;
MethodHandles.Lookup lookup = IMPL_LOOKUP.in(topClass());
speciesCode = AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Class<?> run() {
try {
return lookup.defineClass(classFile);
} catch (Exception ex) {
throw newInternalError(ex);
}
}
});
ClassLoader cl = topClass.getClassLoader();
ProtectionDomain pd = null;
if (cl != null) {
pd = AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public ProtectionDomain run() {
return topClass().getProtectionDomain();
}
});
}
Class<?> speciesCode = SharedSecrets.getJavaLangAccess()
.defineClass(cl, className, classFile, pd, "_ClassSpecializer_generateConcreteSpeciesCode");
return speciesCode.asSubclass(topClass());
}

View file

@ -31,16 +31,13 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.vm.annotation.ForceInline;
import sun.invoke.util.Wrapper;
import sun.security.action.GetPropertyAction;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@ -1531,27 +1528,33 @@ public final class StringConcatFactory {
if (recipe.getElements().size() == 2) {
// Two object arguments
if (mt.parameterCount() == 2 &&
!mt.parameterType(0).isPrimitive() &&
!mt.parameterType(1).isPrimitive()) {
return SIMPLE;
}
// One element is a constant
if (mt.parameterCount() == 1 && !mt.parameterType(0).isPrimitive()) {
MethodHandle mh = SIMPLE;
// Insert constant element
!mt.parameterType(0).isPrimitive() &&
!mt.parameterType(1).isPrimitive() &&
recipe.getElements().get(0).getTag() == TAG_ARG &&
recipe.getElements().get(1).getTag() == TAG_ARG) {
return SIMPLE;
} else if (mt.parameterCount() == 1 &&
!mt.parameterType(0).isPrimitive()) {
// One Object argument, one constant
MethodHandle mh = SIMPLE;
// First recipe element is a constant
if (recipe.getElements().get(0).getTag() == TAG_CONST &&
recipe.getElements().get(1).getTag() != TAG_CONST) {
recipe.getElements().get(1).getTag() == TAG_ARG) {
// First recipe element is a constant
return MethodHandles.insertArguments(mh, 0,
recipe.getElements().get(0).getValue());
} else if (recipe.getElements().get(1).getTag() == TAG_CONST &&
recipe.getElements().get(0).getTag() != TAG_CONST) {
recipe.getElements().get(0).getTag() == TAG_ARG) {
// Second recipe element is a constant
return MethodHandles.insertArguments(mh, 1,
recipe.getElements().get(1).getValue());
}
// else... fall-through to slow-path
}
// else... fall-through to slow-path
}
// Create filters and obtain filtered parameter types. Filters would be used in the beginning
@ -1579,26 +1582,49 @@ public final class StringConcatFactory {
mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes);
long initialLengthCoder = INITIAL_CODER;
// Mix in prependers. This happens when (byte[], long) = (storage, indexCoder) is already
// known from the combinators below. We are assembling the string backwards, so the index coded
// into indexCoder is the *ending* index.
// We need one prepender per argument, but also need to fold in constants. We do so by greedily
// create prependers that fold in surrounding constants into the argument prepender. This reduces
// the number of unique MH combinator tree shapes we'll create in an application.
String prefixConstant = null, suffixConstant = null;
int pos = -1;
for (RecipeElement el : recipe.getElements()) {
// Do the prepend, and put "new" index at index 1
switch (el.getTag()) {
case TAG_CONST: {
MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 2, el.getValue());
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
1, 0 // indexCoder, storage
);
String constantValue = el.getValue();
// Eagerly update the initialLengthCoder value
initialLengthCoder = (long)mixer(String.class).invoke(initialLengthCoder, constantValue);
if (pos < 0) {
// Collecting into prefixConstant
prefixConstant = prefixConstant == null ? constantValue : prefixConstant + constantValue;
} else {
// Collecting into suffixConstant
suffixConstant = suffixConstant == null ? constantValue : suffixConstant + constantValue;
}
break;
}
case TAG_ARG: {
int pos = el.getArgPos();
MethodHandle prepender = prepender(ptypes[pos]);
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
if (pos >= 0) {
// Flush the previous non-constant arg with any prefix/suffix constant
mh = MethodHandles.filterArgumentsWithCombiner(
mh, 1,
prepender(prefixConstant, ptypes[pos], suffixConstant),
1, 0, // indexCoder, storage
2 + pos // selected argument
);
);
prefixConstant = suffixConstant = null;
}
// Mark the pos of next non-constant arg
pos = el.getArgPos();
break;
}
default:
@ -1606,6 +1632,24 @@ public final class StringConcatFactory {
}
}
// Insert any trailing args, constants
if (pos >= 0) {
mh = MethodHandles.filterArgumentsWithCombiner(
mh, 1,
prepender(prefixConstant, ptypes[pos], suffixConstant),
1, 0, // indexCoder, storage
2 + pos // selected argument
);
} else if (prefixConstant != null) {
assert (suffixConstant == null);
// Sole prefixConstant can only happen if there were no non-constant arguments
mh = MethodHandles.filterArgumentsWithCombiner(
mh, 1,
MethodHandles.insertArguments(prepender(null, String.class, null), 2, prefixConstant),
1, 0 // indexCoder, storage
);
}
// Fold in byte[] instantiation at argument 0
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, NEW_ARRAY,
1 // index
@ -1624,12 +1668,11 @@ public final class StringConcatFactory {
//
// The method handle shape before and after all mixers are combined in is:
// (long, <args>)String = ("indexCoder", <args>)
long initialLengthCoder = INITIAL_CODER;
for (RecipeElement el : recipe.getElements()) {
switch (el.getTag()) {
case TAG_CONST:
String constant = el.getValue();
initialLengthCoder = (long)mixer(String.class).invoke(initialLengthCoder, constant);
// Constants already handled in the code above
break;
case TAG_ARG:
int ac = el.getArgPos();
@ -1661,8 +1704,10 @@ public final class StringConcatFactory {
return mh;
}
private static MethodHandle prepender(Class<?> cl) {
return PREPENDERS.computeIfAbsent(cl, PREPEND);
private static MethodHandle prepender(String prefix, Class<?> cl, String suffix) {
return MethodHandles.insertArguments(
MethodHandles.insertArguments(
PREPENDERS.computeIfAbsent(cl, PREPEND),2, prefix), 3, suffix);
}
private static MethodHandle mixer(Class<?> cl) {
@ -1670,16 +1715,16 @@ public final class StringConcatFactory {
}
// This one is deliberately non-lambdified to optimize startup time:
private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
private static final Function<Class<?>, MethodHandle> PREPEND = new Function<>() {
@Override
public MethodHandle apply(Class<?> c) {
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
Wrapper.asPrimitiveType(c));
String.class, Wrapper.asPrimitiveType(c), String.class);
}
};
// This one is deliberately non-lambdified to optimize startup time:
private static final Function<Class<?>, MethodHandle> MIX = new Function<Class<?>, MethodHandle>() {
private static final Function<Class<?>, MethodHandle> MIX = new Function<>() {
@Override
public MethodHandle apply(Class<?> c) {
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mix", long.class, long.class,

View file

@ -74,6 +74,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
/* indicates connection reset state */
private volatile boolean connectionReset;
/* indicates whether impl is bound */
boolean isBound;
/* indicates whether impl is connected */
volatile boolean isConnected;
/* whether this Socket is a stream (TCP) socket or not (UDP)
*/
protected boolean stream;
@ -105,6 +111,10 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
return isReusePortAvailable;
}
AbstractPlainSocketImpl(boolean isServer) {
super(isServer);
}
/**
* Returns a set of SocketOptions supported by this impl and by this impl's
* socket (Socket or ServerSocket)
@ -148,10 +158,6 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
socketCreate(true);
SocketCleanable.register(fd);
}
if (socket != null)
socket.setCreated();
if (serverSocket != null)
serverSocket.setCreated();
}
/**
@ -180,6 +186,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
it will be passed up the call stack */
}
}
isConnected = connected;
}
}
@ -195,6 +202,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
try {
connectToAddress(address, port, timeout);
isConnected = true;
return;
} catch (IOException e) {
// everything failed
@ -236,6 +244,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
it will be passed up the call stack */
}
}
isConnected = connected;
}
}
@ -393,7 +402,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
synchronized (fdLock) {
if (!closePending && (socket == null || !socket.isBound())) {
if (!closePending && !isBound) {
NetHooks.beforeTcpConnect(fd, address, port);
}
}
@ -407,14 +416,6 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
throw new SocketException ("Socket closed");
}
}
// If we have a ref. to the Socket, then sets the flags
// created, bound & connected to true.
// This is normally done in Socket.connect() but some
// subclasses of Socket may call impl.connect() directly!
if (socket != null) {
socket.setBound();
socket.setConnected();
}
} finally {
releaseFD();
}
@ -433,15 +434,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
throws IOException
{
synchronized (fdLock) {
if (!closePending && (socket == null || !socket.isBound())) {
if (!closePending && !isBound) {
NetHooks.beforeTcpBind(fd, address, lport);
}
}
socketBind(address, lport);
if (socket != null)
socket.setBound();
if (serverSocket != null)
serverSocket.setBound();
isBound = true;
}
/**
@ -727,7 +725,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
socketClose0(false);
}
abstract void socketCreate(boolean isServer) throws IOException;
abstract void socketCreate(boolean stream) throws IOException;
abstract void socketConnect(InetAddress address, int port, int timeout)
throws IOException;
abstract void socketBind(InetAddress address, int port)

View file

@ -51,6 +51,7 @@ import java.util.Set;
private static final Method doTunneling;
private final String server;
private final Socket socket;
private InetSocketAddress external_address;
private HashMap<Integer, Object> optionsMap = new HashMap<>();
@ -75,8 +76,9 @@ import java.util.Set;
}
}
HttpConnectSocketImpl(Proxy proxy, SocketImpl delegate) {
HttpConnectSocketImpl(Proxy proxy, SocketImpl delegate, Socket socket) {
super(delegate);
this.socket = socket;
SocketAddress a = proxy.address();
if ( !(a instanceof InetSocketAddress) )
throw new IllegalArgumentException("Unsupported address type");
@ -96,17 +98,6 @@ import java.util.Set;
connect(new InetSocketAddress(address, port), 0);
}
@Override
void setSocket(Socket socket) {
delegate.socket = socket;
super.setSocket(socket);
}
@Override
void setServerSocket(ServerSocket socket) {
throw new InternalError("should not get here");
}
@Override
protected void connect(SocketAddress endpoint, int timeout)
throws IOException
@ -137,7 +128,7 @@ import java.util.Set;
// update the Sockets impl to the impl from the http Socket
SocketImpl si = httpSocket.impl;
getSocket().setImpl(si);
socket.setImpl(si);
// best effort is made to try and reset options previously set
Set<Map.Entry<Integer,Object>> options = optionsMap.entrySet();

View file

@ -71,11 +71,6 @@ class ServerSocket implements java.io.Closeable {
*/
private SocketImpl impl;
/**
* Are we using an older SocketImpl?
*/
private boolean oldImpl = false;
/**
* Creates a server socket with a user-specified {@code SocketImpl}.
*
@ -87,7 +82,6 @@ class ServerSocket implements java.io.Closeable {
*/
protected ServerSocket(SocketImpl impl) {
this.impl = impl;
impl.setServerSocket(this);
}
/**
@ -270,36 +264,13 @@ class ServerSocket implements java.io.Closeable {
return impl;
}
private void checkOldImpl() {
if (impl == null)
return;
// SocketImpl.connect() is a protected method, therefore we need to use
// getDeclaredMethod, therefore we need permission to access the member
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws NoSuchMethodException {
impl.getClass().getDeclaredMethod("connect",
SocketAddress.class,
int.class);
return null;
}
});
} catch (java.security.PrivilegedActionException e) {
oldImpl = true;
}
}
private void setImpl() {
SocketImplFactory factory = ServerSocket.factory;
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
} else {
impl = SocketImpl.createPlatformSocketImpl(true);
}
if (impl != null)
impl.setServerSocket(this);
}
/**
@ -368,7 +339,7 @@ class ServerSocket implements java.io.Closeable {
public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
if (isBound())
throw new SocketException("Already bound");
if (endpoint == null)
endpoint = new InetSocketAddress(0);
@ -722,8 +693,7 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isBound() {
// Before 1.3 ServerSockets were always bound during creation
return bound || oldImpl;
return bound;
}
/**
@ -866,14 +836,6 @@ class ServerSocket implements java.io.Closeable {
",localport=" + impl.getLocalPort() + "]";
}
void setBound() {
bound = true;
}
void setCreated() {
created = true;
}
/**
* The factory for all server sockets.
*/

View file

@ -71,11 +71,6 @@ class Socket implements java.io.Closeable {
*/
SocketImpl impl;
/**
* Are we using an older SocketImpl?
*/
private boolean oldImpl = false;
/**
* Socket input/output streams
*/
@ -158,8 +153,7 @@ class Socket implements java.io.Closeable {
// create a SOCKS or HTTP SocketImpl that delegates to a platform SocketImpl
SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
impl = (type == Proxy.Type.SOCKS) ? new SocksSocketImpl(p, delegate)
: new HttpConnectSocketImpl(p, delegate);
impl.setSocket(this);
: new HttpConnectSocketImpl(p, delegate, this);
} else {
if (p == Proxy.NO_PROXY) {
// create a platform or custom SocketImpl for the DIRECT case
@ -169,7 +163,6 @@ class Socket implements java.io.Closeable {
} else {
impl = factory.createSocketImpl();
}
impl.setSocket(this);
} else
throw new IllegalArgumentException("Invalid Proxy");
}
@ -188,10 +181,6 @@ class Socket implements java.io.Closeable {
*/
protected Socket(SocketImpl impl) throws SocketException {
this.impl = impl;
if (impl != null) {
checkOldImpl();
this.impl.setSocket(this);
}
}
/**
@ -486,37 +475,8 @@ class Socket implements java.io.Closeable {
}
}
private void checkOldImpl() {
if (impl == null)
return;
// SocketImpl.connect() is a protected method, therefore we need to use
// getDeclaredMethod, therefore we need permission to access the member
oldImpl = AccessController.doPrivileged
(new PrivilegedAction<>() {
public Boolean run() {
Class<?> clazz = impl.getClass();
while (true) {
try {
clazz.getDeclaredMethod("connect", SocketAddress.class, int.class);
return Boolean.FALSE;
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
// java.net.SocketImpl class will always have this abstract method.
// If we have not found it by now in the hierarchy then it does not
// exist, we are an old style impl.
if (clazz.equals(java.net.SocketImpl.class)) {
return Boolean.TRUE;
}
}
}
}
});
}
void setImpl(SocketImpl si) {
impl = si;
impl.setSocket(this);
}
/**
@ -527,14 +487,11 @@ class Socket implements java.io.Closeable {
SocketImplFactory factory = Socket.factory;
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
} else {
// create a SOCKS SocketImpl that delegates to a platform SocketImpl
SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
impl = new SocksSocketImpl(delegate);
}
if (impl != null)
impl.setSocket(this);
}
/**
@ -596,7 +553,7 @@ class Socket implements java.io.Closeable {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isConnected())
if (isConnected())
throw new SocketException("already connected");
if (!(endpoint instanceof InetSocketAddress))
@ -616,15 +573,7 @@ class Socket implements java.io.Closeable {
}
if (!created)
createImpl(true);
if (!oldImpl)
impl.connect(epoint, timeout);
else if (timeout == 0) {
if (epoint.isUnresolved())
impl.connect(addr.getHostName(), port);
else
impl.connect(addr, port);
} else
throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)");
impl.connect(epoint, timeout);
connected = true;
/*
* If the socket was not bound before the connect, it is now because
@ -654,7 +603,7 @@ class Socket implements java.io.Closeable {
public void bind(SocketAddress bindpoint) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
if (isBound())
throw new SocketException("Already bound");
if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress)))
@ -694,18 +643,6 @@ class Socket implements java.io.Closeable {
bound = true;
}
void setCreated() {
created = true;
}
void setBound() {
bound = true;
}
void setConnected() {
connected = true;
}
/**
* Returns the address to which the socket is connected.
* <p>
@ -957,6 +894,7 @@ class Socket implements java.io.Closeable {
private static class SocketInputStream extends InputStream {
private final Socket parent;
private final InputStream in;
SocketInputStream(Socket parent, InputStream in) {
this.parent = parent;
this.in = in;
@ -975,6 +913,7 @@ class Socket implements java.io.Closeable {
public int available() throws IOException {
return in.available();
}
@Override
public void close() throws IOException {
parent.close();
@ -1040,6 +979,7 @@ class Socket implements java.io.Closeable {
public void write(byte b[], int off, int len) throws IOException {
out.write(b, off, len);
}
@Override
public void close() throws IOException {
parent.close();
@ -1672,8 +1612,7 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
public boolean isConnected() {
// Before 1.3 Sockets were always connected during creation
return connected || oldImpl;
return connected;
}
/**
@ -1689,8 +1628,7 @@ class Socket implements java.io.Closeable {
* @see #bind
*/
public boolean isBound() {
// Before 1.3 Sockets were always bound during creation
return bound || oldImpl;
return bound;
}
/**

View file

@ -51,15 +51,9 @@ public abstract class SocketImpl implements SocketOptions {
*/
@SuppressWarnings("unchecked")
static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {
return (S) new PlainSocketImpl();
return (S) new PlainSocketImpl(server);
}
/**
* The actual Socket object.
*/
Socket socket = null;
ServerSocket serverSocket = null;
/**
* The file descriptor object for this socket.
*/
@ -80,6 +74,23 @@ public abstract class SocketImpl implements SocketOptions {
*/
protected int localport;
/**
* Whether this is a server or not.
*/
final boolean isServer;
SocketImpl(boolean isServer) {
this.isServer = isServer;
}
/**
* Initialize a new instance of this class
*/
public SocketImpl() {
this.isServer = false;
}
/**
* Creates either a stream or a datagram socket.
*
@ -300,22 +311,6 @@ public abstract class SocketImpl implements SocketOptions {
return localport;
}
void setSocket(Socket soc) {
this.socket = soc;
}
Socket getSocket() {
return socket;
}
void setServerSocket(ServerSocket soc) {
this.serverSocket = soc;
}
ServerSocket getServerSocket() {
return serverSocket;
}
/**
* Returns the address and port of this socket as a {@code String}.
*
@ -395,11 +390,9 @@ public abstract class SocketImpl implements SocketOptions {
* @since 9
*/
protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
if (name == StandardSocketOptions.SO_KEEPALIVE &&
(getSocket() != null)) {
if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) {
setOption(SocketOptions.SO_KEEPALIVE, value);
} else if (name == StandardSocketOptions.SO_SNDBUF &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) {
setOption(SocketOptions.SO_SNDBUF, value);
} else if (name == StandardSocketOptions.SO_RCVBUF) {
setOption(SocketOptions.SO_RCVBUF, value);
@ -408,13 +401,11 @@ public abstract class SocketImpl implements SocketOptions {
} else if (name == StandardSocketOptions.SO_REUSEPORT &&
supportedOptions().contains(name)) {
setOption(SocketOptions.SO_REUSEPORT, value);
} else if (name == StandardSocketOptions.SO_LINGER &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.SO_LINGER && !isServer) {
setOption(SocketOptions.SO_LINGER, value);
} else if (name == StandardSocketOptions.IP_TOS) {
setOption(SocketOptions.IP_TOS, value);
} else if (name == StandardSocketOptions.TCP_NODELAY &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) {
setOption(SocketOptions.TCP_NODELAY, value);
} else {
throw new UnsupportedOperationException("unsupported option");
@ -438,11 +429,9 @@ public abstract class SocketImpl implements SocketOptions {
*/
@SuppressWarnings("unchecked")
protected <T> T getOption(SocketOption<T> name) throws IOException {
if (name == StandardSocketOptions.SO_KEEPALIVE &&
(getSocket() != null)) {
if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) {
return (T)getOption(SocketOptions.SO_KEEPALIVE);
} else if (name == StandardSocketOptions.SO_SNDBUF &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) {
return (T)getOption(SocketOptions.SO_SNDBUF);
} else if (name == StandardSocketOptions.SO_RCVBUF) {
return (T)getOption(SocketOptions.SO_RCVBUF);
@ -451,13 +440,11 @@ public abstract class SocketImpl implements SocketOptions {
} else if (name == StandardSocketOptions.SO_REUSEPORT &&
supportedOptions().contains(name)) {
return (T)getOption(SocketOptions.SO_REUSEPORT);
} else if (name == StandardSocketOptions.SO_LINGER &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.SO_LINGER && !isServer) {
return (T)getOption(SocketOptions.SO_LINGER);
} else if (name == StandardSocketOptions.IP_TOS) {
return (T)getOption(SocketOptions.IP_TOS);
} else if (name == StandardSocketOptions.TCP_NODELAY &&
(getSocket() != null)) {
} else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) {
return (T)getOption(SocketOptions.TCP_NODELAY);
} else {
throw new UnsupportedOperationException("unsupported option");
@ -504,7 +491,7 @@ public abstract class SocketImpl implements SocketOptions {
* @since 9
*/
protected Set<SocketOption<?>> supportedOptions() {
if (getSocket() != null) {
if (!isServer) {
return socketOptions;
} else {
return serverSocketOptions;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,7 +48,6 @@ class SocketInputStream extends FileInputStream {
private boolean eof;
private AbstractPlainSocketImpl impl = null;
private byte temp[];
private Socket socket = null;
/**
* Creates a new SocketInputStream. Can only be called
@ -59,7 +58,6 @@ class SocketInputStream extends FileInputStream {
SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
super(impl.getFileDescriptor());
this.impl = impl;
socket = impl.getSocket();
}
/**
@ -236,27 +234,16 @@ class SocketInputStream extends FileInputStream {
return eof ? 0 : available;
}
/**
* Closes the stream.
*/
private boolean closing = false;
public void close() throws IOException {
// Prevent recursion. See BugId 4484411
if (closing)
return;
closing = true;
if (socket != null) {
if (!socket.isClosed())
socket.close();
} else
impl.close();
closing = false;
}
void setEOF(boolean eof) {
this.eof = eof;
}
public void close() throws IOException {
// No longer used. Socket.getInputStream returns an
// InputStream which calls Socket.close directly
assert false;
}
/**
* Overrides finalize, the fd is closed by the Socket.
*/

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,7 +45,6 @@ class SocketOutputStream extends FileOutputStream {
private AbstractPlainSocketImpl impl = null;
private byte temp[] = new byte[1];
private Socket socket = null;
/**
* Creates a new SocketOutputStream. Can only be called
@ -56,7 +55,6 @@ class SocketOutputStream extends FileOutputStream {
SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
super(impl.getFileDescriptor());
this.impl = impl;
socket = impl.getSocket();
}
/**
@ -150,21 +148,10 @@ class SocketOutputStream extends FileOutputStream {
socketWrite(b, off, len);
}
/**
* Closes the stream.
*/
private boolean closing = false;
public void close() throws IOException {
// Prevent recursion. See BugId 4484411
if (closing)
return;
closing = true;
if (socket != null) {
if (!socket.isClosed())
socket.close();
} else
impl.close();
closing = false;
// No longer used. Socket.getOutputStream returns an
// OutputStream which calls Socket.close directly
assert false;
}
/**

View file

@ -256,17 +256,6 @@ class SocksSocketImpl extends DelegatingSocketImpl implements SocksConsts {
connect(new InetSocketAddress(address, port), 0);
}
@Override
void setSocket(Socket soc) {
delegate.socket = soc;
super.setSocket(soc);
}
@Override
void setServerSocket(ServerSocket soc) {
throw new InternalError("should not get here");
}
/**
* Connects the Socks Socket to the specified endpoint. It will first
* connect to the SOCKS proxy and negotiate the access. If the proxy

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,13 +23,15 @@
* questions.
*/
/*
*/
package java.nio.channels.spi;
import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.Channel;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.InterruptibleChannel;
import java.util.concurrent.locks.ReentrantLock;
import jdk.internal.access.SharedSecrets;
import sun.nio.ch.Interruptible;
@ -84,8 +86,7 @@ import sun.nio.ch.Interruptible;
public abstract class AbstractInterruptibleChannel
implements Channel, InterruptibleChannel
{
private final Object closeLock = new Object();
private final ReentrantLock closeLock = new ReentrantLock();
private volatile boolean closed;
/**
@ -105,11 +106,14 @@ public abstract class AbstractInterruptibleChannel
* If an I/O error occurs
*/
public final void close() throws IOException {
synchronized (closeLock) {
closeLock.lock();
try {
if (closed)
return;
closed = true;
implCloseChannel();
} finally {
closeLock.unlock();
}
}
@ -153,7 +157,8 @@ public abstract class AbstractInterruptibleChannel
if (interruptor == null) {
interruptor = new Interruptible() {
public void interrupt(Thread target) {
synchronized (closeLock) {
closeLock.lock();
try {
if (closed)
return;
closed = true;
@ -161,6 +166,8 @@ public abstract class AbstractInterruptibleChannel
try {
AbstractInterruptibleChannel.this.implCloseChannel();
} catch (IOException x) { }
} finally {
closeLock.unlock();
}
}};
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,7 +74,7 @@ package java.security;
* </UL>
*
* Keys are generally obtained through key generators, certificates,
* or various Identity classes used to manage keys.
* key stores or other classes used to manage keys.
* Keys may also be obtained from key specifications (transparent
* representations of the underlying key material) through the use of a key
* factory (see {@link KeyFactory}).
@ -119,10 +119,11 @@ public interface Key extends java.io.Serializable {
/**
* Returns the standard algorithm name for this key. For
* example, "DSA" would indicate that this key is a DSA key.
* See the <a href=
* See the key related sections (KeyFactory, KeyGenerator,
* KeyPairGenerator, and SecretKeyFactory) in the <a href=
* "{@docRoot}/../specs/security/standard-names.html">
* Java Security Standard Algorithm Names</a> document
* for more information.
* Java Security Standard Algorithm Names Specification</a>
* for information about standard key algorithm names.
*
* @return the name of the algorithm associated with this key.
*/

View file

@ -1129,6 +1129,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
clone.entrySet = null;
clone.values = null;
clone.descendingMap = null;
clone.adder = null;
clone.buildFromSorted(this);
return clone;
} catch (CloneNotSupportedException e) {

View file

@ -413,8 +413,9 @@ public class CopyOnWriteArrayList<E>
if (oldValue != element) {
es = es.clone();
es[index] = element;
setArray(es);
}
// Ensure volatile write semantics even when oldvalue == element
setArray(es);
return oldValue;
}
}

View file

@ -66,7 +66,7 @@ import java.util.List;
* <p>The {@link Executors} class provides factory methods for the
* executor services provided in this package.
*
* <h3>Usage Examples</h3>
* <h2>Usage Examples</h2>
*
* Here is a sketch of a network service in which threads in a thread
* pool service incoming requests. It uses the preconfigured {@link

View file

@ -65,7 +65,7 @@ package java.util.concurrent;
* <p>The {@link Executors} class provides convenient factory methods for
* the ScheduledExecutorService implementations provided in this package.
*
* <h3>Usage Example</h3>
* <h2>Usage Example</h2>
*
* Here is a class with a method that sets up a ScheduledExecutorService
* to beep every ten seconds for an hour:

View file

@ -922,13 +922,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();

View file

@ -104,7 +104,7 @@ import java.util.concurrent.TimeUnit;
* define a {@code readObject} method that restores this to a known
* initial state upon deserialization.
*
* <h3>Usage</h3>
* <h2>Usage</h2>
*
* <p>To use this class as the basis of a synchronizer, redefine the
* following methods, as applicable, by inspecting and/or modifying
@ -187,7 +187,7 @@ import java.util.concurrent.TimeUnit;
* {@link java.util.Queue} classes, and {@link LockSupport} blocking
* support.
*
* <h3>Usage Examples</h3>
* <h2>Usage Examples</h2>
*
* <p>Here is a non-reentrant mutual exclusion lock class that uses
* the value zero to represent the unlocked state, and one to

View file

@ -138,7 +138,7 @@ import java.util.concurrent.TimeUnit;
* <p>Except where noted, passing a {@code null} value for any parameter
* will result in a {@link NullPointerException} being thrown.
*
* <h3>Implementation Considerations</h3>
* <h2>Implementation Considerations</h2>
*
* <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
* wakeup</em>&quot; is permitted to occur, in

View file

@ -117,7 +117,7 @@ import java.util.concurrent.TimeUnit;
* parameter will result in a {@link NullPointerException} being
* thrown.
*
* <h3>Memory Synchronization</h3>
* <h2>Memory Synchronization</h2>
*
* <p>All {@code Lock} implementations <em>must</em> enforce the same
* memory synchronization semantics as provided by the built-in monitor
@ -136,7 +136,7 @@ import java.util.concurrent.TimeUnit;
* locking/unlocking operations, do not require any memory
* synchronization effects.
*
* <h3>Implementation Considerations</h3>
* <h2>Implementation Considerations</h2>
*
* <p>The three forms of lock acquisition (interruptible,
* non-interruptible, and timed) may differ in their performance

View file

@ -204,7 +204,7 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
* }
* }}</pre>
*
* <h3>Implementation Notes</h3>
* <h2>Implementation Notes</h2>
*
* <p>This lock supports a maximum of 65535 recursive write locks
* and 65535 read locks. Attempts to exceed these limits result in

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -214,6 +214,7 @@ module java.base {
java.sql,
java.sql.rowset,
jdk.dynalink,
jdk.internal.vm.ci,
jdk.scripting.nashorn,
jdk.unsupported;
exports jdk.internal.vm to

View file

@ -146,7 +146,7 @@ public final class ParseUtil {
/**
* Appends the URL escape sequence for the specified char to the
* specified StringBuffer.
* specified character array.
*/
private static int escape(char[] cc, char c, int index) {
cc[index++] = '%';
@ -336,7 +336,7 @@ public final class ParseUtil {
String query,
String fragment)
{
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
if (scheme != null) {
sb.append(scheme);
sb.append(':');
@ -348,7 +348,7 @@ public final class ParseUtil {
return sb.toString();
}
private static void appendSchemeSpecificPart(StringBuffer sb,
private static void appendSchemeSpecificPart(StringBuilder sb,
String opaquePart,
String authority,
String userInfo,
@ -389,7 +389,7 @@ public final class ParseUtil {
}
}
private static void appendAuthority(StringBuffer sb,
private static void appendAuthority(StringBuilder sb,
String authority,
String userInfo,
String host,
@ -437,7 +437,7 @@ public final class ParseUtil {
}
}
private static void appendFragment(StringBuffer sb, String fragment) {
private static void appendFragment(StringBuilder sb, String fragment) {
if (fragment != null) {
sb.append('#');
sb.append(quote(fragment, L_URIC, H_URIC));
@ -449,14 +449,14 @@ public final class ParseUtil {
//
private static String quote(String s, long lowMask, long highMask) {
int n = s.length();
StringBuffer sb = null;
StringBuilder sb = null;
boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c < '\u0080') {
if (!match(c, lowMask, highMask) && !isEscaped(s, i)) {
if (sb == null) {
sb = new StringBuffer();
sb = new StringBuilder();
sb.append(s, 0, i);
}
appendEscape(sb, (byte)c);
@ -468,7 +468,7 @@ public final class ParseUtil {
&& (Character.isSpaceChar(c)
|| Character.isISOControl(c))) {
if (sb == null) {
sb = new StringBuffer();
sb = new StringBuilder();
sb.append(s, 0, i);
}
appendEncoded(sb, c);
@ -493,7 +493,7 @@ public final class ParseUtil {
&& match(s.charAt(pos + 2), L_HEX, H_HEX);
}
private static void appendEncoded(StringBuffer sb, char c) {
private static void appendEncoded(StringBuilder sb, char c) {
ByteBuffer bb = null;
try {
bb = ThreadLocalCoders.encoderFor("UTF-8")
@ -515,7 +515,7 @@ public final class ParseUtil {
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
private static void appendEscape(StringBuffer sb, byte b) {
private static void appendEscape(StringBuilder sb, byte b) {
sb.append('%');
sb.append(hexDigits[(b >> 4) & 0x0f]);
sb.append(hexDigits[(b >> 0) & 0x0f]);

View file

@ -53,6 +53,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import sun.net.ResourceManager;
@ -89,7 +90,8 @@ class DatagramChannelImpl
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
private final ReentrantLock stateLock = new ReentrantLock();
private final Condition stateCondition = stateLock.newCondition();
// -- The following fields are protected by stateLock
@ -179,8 +181,11 @@ class DatagramChannelImpl
: StandardProtocolFamily.INET;
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
synchronized (stateLock) {
stateLock.lock();
try {
this.localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
}
@ -192,27 +197,36 @@ class DatagramChannelImpl
@Override
public DatagramSocket socket() {
synchronized (stateLock) {
stateLock.lock();
try {
if (socket == null)
socket = DatagramSocketAdaptor.create(this);
return socket;
} finally {
stateLock.unlock();
}
}
@Override
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
// Perform security check before returning address
return Net.getRevealedLocalAddress(localAddress);
} finally {
stateLock.unlock();
}
}
@Override
public SocketAddress getRemoteAddress() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
return remoteAddress;
} finally {
stateLock.unlock();
}
}
@ -224,7 +238,8 @@ class DatagramChannelImpl
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.IP_TOS ||
@ -264,6 +279,8 @@ class DatagramChannelImpl
// remaining options don't need any special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value);
return this;
} finally {
stateLock.unlock();
}
}
@ -276,7 +293,8 @@ class DatagramChannelImpl
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.IP_TOS ||
@ -315,6 +333,8 @@ class DatagramChannelImpl
// no special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally {
stateLock.unlock();
}
}
@ -362,7 +382,8 @@ class DatagramChannelImpl
begin();
}
SocketAddress remote;
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
remote = remoteAddress;
if ((remote == null) && mustBeConnected)
@ -371,6 +392,8 @@ class DatagramChannelImpl
bindInternal(null);
if (blocking)
readerThread = NativeThread.current();
} finally {
stateLock.unlock();
}
return remote;
}
@ -384,12 +407,15 @@ class DatagramChannelImpl
throws AsynchronousCloseException
{
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
readerThread = 0;
// notify any thread waiting in implCloseSelectableChannel
if (state == ST_CLOSING) {
stateLock.notifyAll();
stateCondition.signalAll();
}
} finally {
stateLock.unlock();
}
// remove hook for Thread.interrupt
end(completed);
@ -414,21 +440,29 @@ class DatagramChannelImpl
SecurityManager sm = System.getSecurityManager();
if (connected || (sm == null)) {
// connected or no security manager
do {
n = receive(fd, dst, connected);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n == IOStatus.UNAVAILABLE)
n = receive(fd, dst, connected);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = receive(fd, dst, connected);
}
} else if (n == IOStatus.UNAVAILABLE) {
return null;
}
} else {
// Cannot receive into user's buffer when running with a
// security manager and not connected
bb = Util.getTemporaryDirectBuffer(dst.remaining());
for (;;) {
do {
n = receive(fd, bb, connected);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n == IOStatus.UNAVAILABLE)
n = receive(fd, bb, connected);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = receive(fd, bb, connected);
}
} else if (n == IOStatus.UNAVAILABLE) {
return null;
}
InetSocketAddress isa = (InetSocketAddress)sender;
try {
sm.checkAccept(isa.getAddress().getHostAddress(),
@ -493,6 +527,7 @@ class DatagramChannelImpl
return n;
}
@Override
public int send(ByteBuffer src, SocketAddress target)
throws IOException
{
@ -510,9 +545,13 @@ class DatagramChannelImpl
if (!target.equals(remote)) {
throw new AlreadyConnectedException();
}
do {
n = IOUtil.write(fd, src, -1, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = IOUtil.write(fd, src, -1, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = IOUtil.write(fd, src, -1, nd);
}
}
} else {
// not connected
SecurityManager sm = System.getSecurityManager();
@ -524,9 +563,13 @@ class DatagramChannelImpl
sm.checkConnect(ia.getHostAddress(), isa.getPort());
}
}
do {
n = send(fd, src, isa);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = send(fd, src, isa);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = send(fd, src, isa);
}
}
}
} finally {
endWrite(blocking, n > 0);
@ -602,10 +645,13 @@ class DatagramChannelImpl
int n = 0;
try {
beginRead(blocking, true);
do {
n = IOUtil.read(fd, buf, -1, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = IOUtil.read(fd, buf, -1, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = IOUtil.read(fd, buf, -1, nd);
}
}
} finally {
endRead(blocking, n > 0);
assert IOStatus.check(n);
@ -628,10 +674,13 @@ class DatagramChannelImpl
long n = 0;
try {
beginRead(blocking, true);
do {
n = IOUtil.read(fd, dsts, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = IOUtil.read(fd, dsts, offset, length, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = IOUtil.read(fd, dsts, offset, length, nd);
}
}
} finally {
endRead(blocking, n > 0);
assert IOStatus.check(n);
@ -659,7 +708,8 @@ class DatagramChannelImpl
begin();
}
SocketAddress remote;
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
remote = remoteAddress;
if ((remote == null) && mustBeConnected)
@ -668,6 +718,8 @@ class DatagramChannelImpl
bindInternal(null);
if (blocking)
writerThread = NativeThread.current();
} finally {
stateLock.unlock();
}
return remote;
}
@ -681,12 +733,15 @@ class DatagramChannelImpl
throws AsynchronousCloseException
{
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
writerThread = 0;
// notify any thread waiting in implCloseSelectableChannel
if (state == ST_CLOSING) {
stateLock.notifyAll();
stateCondition.signalAll();
}
} finally {
stateLock.unlock();
}
// remove hook for Thread.interrupt
end(completed);
@ -703,9 +758,13 @@ class DatagramChannelImpl
int n = 0;
try {
beginWrite(blocking, true);
do {
n = IOUtil.write(fd, buf, -1, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = IOUtil.write(fd, buf, -1, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = IOUtil.write(fd, buf, -1, nd);
}
}
} finally {
endWrite(blocking, n > 0);
assert IOStatus.check(n);
@ -728,9 +787,13 @@ class DatagramChannelImpl
long n = 0;
try {
beginWrite(blocking, true);
do {
n = IOUtil.write(fd, srcs, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
n = IOUtil.write(fd, srcs, offset, length, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = IOUtil.write(fd, srcs, offset, length, nd);
}
}
} finally {
endWrite(blocking, n > 0);
assert IOStatus.check(n);
@ -747,9 +810,12 @@ class DatagramChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
IOUtil.configureBlocking(fd, block);
} finally {
stateLock.unlock();
}
} finally {
writeLock.unlock();
@ -760,14 +826,20 @@ class DatagramChannelImpl
}
InetSocketAddress localAddress() {
synchronized (stateLock) {
stateLock.lock();
try {
return localAddress;
} finally {
stateLock.unlock();
}
}
InetSocketAddress remoteAddress() {
synchronized (stateLock) {
stateLock.lock();
try {
return remoteAddress;
} finally {
stateLock.unlock();
}
}
@ -777,11 +849,14 @@ class DatagramChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (localAddress != null)
throw new AlreadyBoundException();
bindInternal(local);
} finally {
stateLock.unlock();
}
} finally {
writeLock.unlock();
@ -793,7 +868,7 @@ class DatagramChannelImpl
}
private void bindInternal(SocketAddress local) throws IOException {
assert Thread.holdsLock(stateLock) && (localAddress == null);
assert stateLock.isHeldByCurrentThread() && (localAddress == null);
InetSocketAddress isa;
if (local == null) {
@ -816,8 +891,11 @@ class DatagramChannelImpl
@Override
public boolean isConnected() {
synchronized (stateLock) {
stateLock.lock();
try {
return (state == ST_CONNECTED);
} finally {
stateLock.unlock();
}
}
@ -839,7 +917,8 @@ class DatagramChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (state == ST_CONNECTED)
throw new AlreadyConnectedException();
@ -865,7 +944,7 @@ class DatagramChannelImpl
}
try {
ByteBuffer buf = ByteBuffer.allocate(100);
while (receive(buf) != null) {
while (receive(fd, buf, false) > 0) {
buf.clear();
}
} finally {
@ -873,6 +952,9 @@ class DatagramChannelImpl
IOUtil.configureBlocking(fd, true);
}
}
} finally {
stateLock.unlock();
}
} finally {
writeLock.unlock();
@ -889,7 +971,8 @@ class DatagramChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
stateLock.lock();
try {
if (!isOpen() || (state != ST_CONNECTED))
return this;
@ -903,6 +986,8 @@ class DatagramChannelImpl
// refresh local address
localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
} finally {
writeLock.unlock();
@ -950,7 +1035,8 @@ class DatagramChannelImpl
if (sm != null)
sm.checkMulticast(group);
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
// check the registry to see if we are already a member of the group
@ -1005,6 +1091,8 @@ class DatagramChannelImpl
registry.add(key);
return key;
} finally {
stateLock.unlock();
}
}
@ -1030,7 +1118,8 @@ class DatagramChannelImpl
void drop(MembershipKeyImpl key) {
assert key.channel() == this;
synchronized (stateLock) {
stateLock.lock();
try {
if (!key.isValid())
return;
@ -1051,6 +1140,8 @@ class DatagramChannelImpl
key.invalidate();
registry.remove(key);
} finally {
stateLock.unlock();
}
}
@ -1064,7 +1155,8 @@ class DatagramChannelImpl
assert key.channel() == this;
assert key.sourceAddress() == null;
synchronized (stateLock) {
stateLock.lock();
try {
if (!key.isValid())
throw new IllegalStateException("key is no longer valid");
if (source.isAnyLocalAddress())
@ -1090,6 +1182,8 @@ class DatagramChannelImpl
// ancient kernel
throw new UnsupportedOperationException();
}
} finally {
stateLock.unlock();
}
}
@ -1100,7 +1194,8 @@ class DatagramChannelImpl
assert key.channel() == this;
assert key.sourceAddress() == null;
synchronized (stateLock) {
stateLock.lock();
try {
if (!key.isValid())
throw new IllegalStateException("key is no longer valid");
@ -1120,6 +1215,8 @@ class DatagramChannelImpl
// should not happen
throw new AssertionError(ioe);
}
} finally {
stateLock.unlock();
}
}
@ -1144,7 +1241,8 @@ class DatagramChannelImpl
boolean interrupted = false;
// set state to ST_CLOSING and invalid membership keys
synchronized (stateLock) {
stateLock.lock();
try {
assert state < ST_CLOSING;
blocking = isBlocking();
state = ST_CLOSING;
@ -1152,11 +1250,14 @@ class DatagramChannelImpl
// if member of any multicast groups then invalidate the keys
if (registry != null)
registry.invalidateAll();
} finally {
stateLock.unlock();
}
// wait for any outstanding I/O operations to complete
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
long reader = readerThread;
long writer = writerThread;
@ -1171,12 +1272,14 @@ class DatagramChannelImpl
// wait for blocking I/O operations to end
while (readerThread != 0 || writerThread != 0) {
try {
stateLock.wait();
stateCondition.await();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
} finally {
stateLock.unlock();
}
} else {
// non-blocking mode: wait for read/write to complete
@ -1190,9 +1293,12 @@ class DatagramChannelImpl
}
// set state to ST_KILLPENDING
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
state = ST_KILLPENDING;
} finally {
stateLock.unlock();
}
// close socket if not registered with Selector
@ -1206,7 +1312,8 @@ class DatagramChannelImpl
@Override
public void kill() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
if (state == ST_KILLPENDING) {
state = ST_KILLED;
try {
@ -1216,6 +1323,8 @@ class DatagramChannelImpl
ResourceManager.afterUdpClose();
}
}
} finally {
stateLock.unlock();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,6 +42,7 @@ import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.IllegalBlockingModeException;
import java.util.Objects;
import java.util.Set;
// Make a datagram-socket channel look like a datagram socket.
@ -51,7 +52,7 @@ import java.util.Objects;
// class.
//
public class DatagramSocketAdaptor
class DatagramSocketAdaptor
extends DatagramSocket
{
// The channel being adapted
@ -61,7 +62,7 @@ public class DatagramSocketAdaptor
private volatile int timeout;
// ## super will create a useless impl
private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
private DatagramSocketAdaptor(DatagramChannelImpl dc) {
// Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
// passing a dummy DatagramSocketImpl object to avoid any native
// resource allocation in super class and invoking our bind method
@ -70,12 +71,8 @@ public class DatagramSocketAdaptor
this.dc = dc;
}
public static DatagramSocket create(DatagramChannelImpl dc) {
try {
return new DatagramSocketAdaptor(dc);
} catch (IOException x) {
throw new Error(x);
}
static DatagramSocket create(DatagramChannelImpl dc) {
return new DatagramSocketAdaptor(dc);
}
private void connectInternal(SocketAddress remote)
@ -96,6 +93,7 @@ public class DatagramSocketAdaptor
}
}
@Override
public void bind(SocketAddress local) throws SocketException {
try {
if (local == null)
@ -106,6 +104,7 @@ public class DatagramSocketAdaptor
}
}
@Override
public void connect(InetAddress address, int port) {
try {
connectInternal(new InetSocketAddress(address, port));
@ -114,11 +113,13 @@ public class DatagramSocketAdaptor
}
}
@Override
public void connect(SocketAddress remote) throws SocketException {
Objects.requireNonNull(remote, "Address can't be null");
connectInternal(remote);
}
@Override
public void disconnect() {
try {
dc.disconnect();
@ -127,24 +128,39 @@ public class DatagramSocketAdaptor
}
}
@Override
public boolean isBound() {
return dc.localAddress() != null;
}
@Override
public boolean isConnected() {
return dc.remoteAddress() != null;
}
@Override
public InetAddress getInetAddress() {
InetSocketAddress remote = dc.remoteAddress();
return (remote != null) ? remote.getAddress() : null;
}
@Override
public int getPort() {
InetSocketAddress remote = dc.remoteAddress();
return (remote != null) ? remote.getPort() : -1;
}
@Override
public SocketAddress getRemoteSocketAddress() {
return dc.remoteAddress();
}
@Override
public SocketAddress getLocalSocketAddress() {
return dc.localAddress();
}
@Override
public void send(DatagramPacket p) throws IOException {
synchronized (dc.blockingLock()) {
if (!dc.isBlocking())
@ -198,6 +214,7 @@ public class DatagramSocketAdaptor
}
}
@Override
public void receive(DatagramPacket p) throws IOException {
synchronized (dc.blockingLock()) {
if (!dc.isBlocking())
@ -217,6 +234,7 @@ public class DatagramSocketAdaptor
}
}
@Override
public InetAddress getLocalAddress() {
if (isClosed())
return null;
@ -235,6 +253,7 @@ public class DatagramSocketAdaptor
return result;
}
@Override
public int getLocalPort() {
if (isClosed())
return -1;
@ -248,11 +267,19 @@ public class DatagramSocketAdaptor
return 0;
}
@Override
public void setSoTimeout(int timeout) throws SocketException {
if (!dc.isOpen())
throw new SocketException("Socket is closed");
if (timeout < 0)
throw new IllegalArgumentException("timeout < 0");
this.timeout = timeout;
}
@Override
public int getSoTimeout() throws SocketException {
if (!dc.isOpen())
throw new SocketException("Socket is closed");
return timeout;
}
@ -294,51 +321,62 @@ public class DatagramSocketAdaptor
}
}
@Override
public void setSendBufferSize(int size) throws SocketException {
if (size <= 0)
throw new IllegalArgumentException("Invalid send size");
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
}
@Override
public int getSendBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_SNDBUF);
}
@Override
public void setReceiveBufferSize(int size) throws SocketException {
if (size <= 0)
throw new IllegalArgumentException("Invalid receive size");
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
}
@Override
public int getReceiveBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_RCVBUF);
}
@Override
public void setReuseAddress(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
}
@Override
public boolean getReuseAddress() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
}
@Override
public void setBroadcast(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
}
@Override
public boolean getBroadcast() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
}
@Override
public void setTrafficClass(int tc) throws SocketException {
setIntOption(StandardSocketOptions.IP_TOS, tc);
}
@Override
public int getTrafficClass() throws SocketException {
return getIntOption(StandardSocketOptions.IP_TOS);
}
@Override
public void close() {
try {
dc.close();
@ -347,14 +385,32 @@ public class DatagramSocketAdaptor
}
}
@Override
public boolean isClosed() {
return !dc.isOpen();
}
@Override
public DatagramChannel getChannel() {
return dc;
}
@Override
public <T> DatagramSocket setOption(SocketOption<T> name, T value) throws IOException {
dc.setOption(name, value);
return this;
}
@Override
public <T> T getOption(SocketOption<T> name) throws IOException {
return dc.getOption(name);
}
@Override
public Set<SocketOption<?>> supportedOptions() {
return dc.supportedOptions();
}
/*
* A dummy implementation of DatagramSocketImpl that can be passed to the
* DatagramSocket constructor so that no native resources are allocated in

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketImpl;
import java.net.SocketOption;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Set;
/**
* Dummy SocketImpl for use by the socket adaptors. All methods are overridden
* to throw an error.
*/
class DummySocketImpl extends SocketImpl {
private static final PrivilegedAction<SocketImpl> NEW = DummySocketImpl::new;
private DummySocketImpl() { }
static SocketImpl create() {
return AccessController.doPrivileged(NEW);
}
private static <T> T shouldNotGetHere() {
throw new InternalError("Should not get here");
}
@Override
protected void create(boolean stream) {
shouldNotGetHere();
}
@Override
protected void connect(SocketAddress remote, int millis) {
shouldNotGetHere();
}
@Override
protected void connect(String host, int port) {
shouldNotGetHere();
}
@Override
protected void connect(InetAddress address, int port) {
shouldNotGetHere();
}
@Override
protected void bind(InetAddress host, int port) {
shouldNotGetHere();
}
@Override
protected void listen(int backlog) {
shouldNotGetHere();
}
@Override
protected void accept(SocketImpl si) {
shouldNotGetHere();
}
@Override
protected InputStream getInputStream() {
return shouldNotGetHere();
}
@Override
protected OutputStream getOutputStream() {
return shouldNotGetHere();
}
@Override
protected int available() {
return shouldNotGetHere();
}
@Override
protected void close() {
shouldNotGetHere();
}
@Override
protected Set<SocketOption<?>> supportedOptions() {
return shouldNotGetHere();
}
@Override
protected <T> void setOption(SocketOption<T> opt, T value) {
shouldNotGetHere();
}
@Override
protected <T> T getOption(SocketOption<T> opt) {
return shouldNotGetHere();
}
@Override
public void setOption(int opt, Object value) {
shouldNotGetHere();
}
@Override
public Object getOption(int opt) {
return shouldNotGetHere();
}
@Override
protected void shutdownInput() {
shouldNotGetHere();
}
@Override
protected void shutdownOutput() {
shouldNotGetHere();
}
@Override
protected boolean supportsUrgentData() {
return shouldNotGetHere();
}
@Override
protected void sendUrgentData(int data) {
shouldNotGetHere();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,8 @@ import java.nio.channels.Channel;
import java.io.FileDescriptor;
import java.io.IOException;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* An interface that allows translation (and more!).
*
@ -68,4 +70,40 @@ public interface SelChImpl extends Channel {
void kill() throws IOException;
/**
* Disables the current thread for scheduling purposes until this
* channel is ready for I/O, or asynchronously closed, for up to the
* specified waiting time.
*
* <p> This method does <em>not</em> report which of these caused the
* method to return. Callers should re-check the conditions which caused
* the thread to park.
*
* @param event the event to poll
* @param nanos the timeout to wait; {@code <= 0} to wait indefinitely
*/
default void park(int event, long nanos) throws IOException {
long millis;
if (nanos <= 0) {
millis = -1;
} else {
millis = NANOSECONDS.toMillis(nanos);
}
Net.poll(getFD(), event, millis);
}
/**
* Disables the current thread for scheduling purposes until this
* channel is ready for I/O, or asynchronously closed.
*
* <p> This method does <em>not</em> report which of these caused the
* method to return. Callers should re-check the conditions which caused
* the thread to park.
*
* @param event the event to poll
*/
default void park(int event) throws IOException {
park(event, 0L);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,12 +32,14 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.NotYetBoundException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
// Make a server-socket channel look like a server socket.
@ -56,23 +58,21 @@ class ServerSocketAdaptor // package-private
// Timeout "option" value for accepts
private volatile int timeout;
public static ServerSocket create(ServerSocketChannelImpl ssc) {
try {
return new ServerSocketAdaptor(ssc);
} catch (IOException x) {
throw new Error(x);
}
static ServerSocket create(ServerSocketChannelImpl ssc) {
return new ServerSocketAdaptor(ssc);
}
// ## super will create a useless impl
private ServerSocketAdaptor(ServerSocketChannelImpl ssc) throws IOException {
private ServerSocketAdaptor(ServerSocketChannelImpl ssc) {
super(DummySocketImpl.create());
this.ssc = ssc;
}
@Override
public void bind(SocketAddress local) throws IOException {
bind(local, 50);
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
if (local == null)
local = new InetSocketAddress(0);
@ -83,6 +83,7 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public InetAddress getInetAddress() {
InetSocketAddress local = ssc.localAddress();
if (local == null) {
@ -92,6 +93,7 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public int getLocalPort() {
InetSocketAddress local = ssc.localAddress();
if (local == null) {
@ -101,65 +103,65 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public Socket accept() throws IOException {
synchronized (ssc.blockingLock()) {
try {
if (!ssc.isBound())
throw new NotYetBoundException();
long to = this.timeout;
if (to == 0) {
// for compatibility reasons: accept connection if available
// when configured non-blocking
SocketChannel sc = ssc.accept();
if (sc == null && !ssc.isBlocking())
throw new IllegalBlockingModeException();
return sc.socket();
}
if (!ssc.isBlocking())
SocketChannel sc = null;
try {
int timeout = this.timeout;
if (timeout > 0) {
long nanos = MILLISECONDS.toNanos(timeout);
sc = ssc.blockingAccept(nanos);
} else {
// accept connection if possible when non-blocking (to preserve
// long standing behavior)
sc = ssc.accept();
if (sc == null) {
throw new IllegalBlockingModeException();
for (;;) {
long st = System.currentTimeMillis();
if (ssc.pollAccept(to))
return ssc.accept().socket();
to -= System.currentTimeMillis() - st;
if (to <= 0)
throw new SocketTimeoutException();
}
} catch (Exception x) {
Net.translateException(x);
assert false;
return null; // Never happens
}
} catch (Exception e) {
Net.translateException(e);
}
return sc.socket();
}
@Override
public void close() throws IOException {
ssc.close();
}
@Override
public ServerSocketChannel getChannel() {
return ssc;
}
@Override
public boolean isBound() {
return ssc.isBound();
}
@Override
public boolean isClosed() {
return !ssc.isOpen();
}
@Override
public void setSoTimeout(int timeout) throws SocketException {
if (!ssc.isOpen())
throw new SocketException("Socket is closed");
if (timeout < 0)
throw new IllegalArgumentException("timeout < 0");
this.timeout = timeout;
}
@Override
public int getSoTimeout() throws SocketException {
if (!ssc.isOpen())
throw new SocketException("Socket is closed");
return timeout;
}
@Override
public void setReuseAddress(boolean on) throws SocketException {
try {
ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
@ -168,6 +170,7 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public boolean getReuseAddress() throws SocketException {
try {
return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
@ -177,6 +180,7 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public String toString() {
if (!isBound())
return "ServerSocket[unbound]";
@ -184,6 +188,7 @@ class ServerSocketAdaptor // package-private
",localport=" + getLocalPort() + "]";
}
@Override
public void setReceiveBufferSize(int size) throws SocketException {
// size 0 valid for ServerSocketChannel, invalid for ServerSocket
if (size <= 0)
@ -195,6 +200,7 @@ class ServerSocketAdaptor // package-private
}
}
@Override
public int getReceiveBufferSize() throws SocketException {
try {
return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
@ -203,4 +209,20 @@ class ServerSocketAdaptor // package-private
return -1; // Never happens
}
}
@Override
public <T> ServerSocket setOption(SocketOption<T> name, T value) throws IOException {
ssc.setOption(name, value);
return this;
}
@Override
public <T> T getOption(SocketOption<T> name) throws IOException {
return ssc.getOption(name);
}
@Override
public Set<SocketOption<?>> supportedOptions() {
return ssc.supportedOptions();
}
}

View file

@ -31,10 +31,12 @@ import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.net.SocketTimeoutException;
import java.net.StandardSocketOptions;
import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.NotYetBoundException;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
@ -44,6 +46,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import sun.net.NetHooks;
@ -69,7 +72,8 @@ class ServerSocketChannelImpl
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
private final ReentrantLock stateLock = new ReentrantLock();
private final Condition stateCondition = stateLock.newCondition();
// -- The following fields are protected by stateLock
@ -95,7 +99,7 @@ class ServerSocketChannelImpl
// -- End of fields protected by stateLock
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
ServerSocketChannelImpl(SelectorProvider sp) {
super(sp);
this.fd = Net.serverSocket(true);
this.fdVal = IOUtil.fdVal(fd);
@ -108,8 +112,11 @@ class ServerSocketChannelImpl
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
if (bound) {
synchronized (stateLock) {
stateLock.lock();
try {
localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
}
}
@ -122,20 +129,26 @@ class ServerSocketChannelImpl
@Override
public ServerSocket socket() {
synchronized (stateLock) {
stateLock.lock();
try {
if (socket == null)
socket = ServerSocketAdaptor.create(this);
return socket;
} finally {
stateLock.unlock();
}
}
@Override
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
return (localAddress == null)
? null
: Net.getRevealedLocalAddress(localAddress);
} finally {
stateLock.unlock();
}
}
@ -146,7 +159,8 @@ class ServerSocketChannelImpl
Objects.requireNonNull(name);
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
@ -157,6 +171,8 @@ class ServerSocketChannelImpl
Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this;
} finally {
stateLock.unlock();
}
}
@ -169,7 +185,8 @@ class ServerSocketChannelImpl
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
// SO_REUSEADDR emulated when using exclusive bind
@ -177,6 +194,8 @@ class ServerSocketChannelImpl
}
// no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally {
stateLock.unlock();
}
}
@ -202,7 +221,8 @@ class ServerSocketChannelImpl
@Override
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (localAddress != null)
throw new AlreadyBoundException();
@ -216,6 +236,8 @@ class ServerSocketChannelImpl
Net.bind(fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
return this;
}
@ -229,12 +251,15 @@ class ServerSocketChannelImpl
private void begin(boolean blocking) throws ClosedChannelException {
if (blocking)
begin(); // set blocker to close channel if interrupted
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (localAddress == null)
throw new NotYetBoundException();
if (blocking)
thread = NativeThread.current();
} finally {
stateLock.unlock();
}
}
@ -248,12 +273,15 @@ class ServerSocketChannelImpl
throws AsynchronousCloseException
{
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
thread = 0;
// notify any thread waiting in implCloseSelectableChannel
if (state == ST_CLOSING) {
stateLock.notifyAll();
stateCondition.signalAll();
}
} finally {
stateLock.unlock();
}
end(completed);
}
@ -270,22 +298,82 @@ class ServerSocketChannelImpl
boolean blocking = isBlocking();
try {
begin(blocking);
do {
n = Net.accept(this.fd, newfd, isaa);
} while (n == IOStatus.INTERRUPTED && isOpen());
n = Net.accept(this.fd, newfd, isaa);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = Net.accept(this.fd, newfd, isaa);
}
}
} finally {
end(blocking, n > 0);
assert IOStatus.check(n);
}
} finally {
acceptLock.unlock();
}
if (n < 1)
if (n > 0) {
return finishAccept(newfd, isaa[0]);
} else {
return null;
}
}
InetSocketAddress isa = isaa[0];
/**
* Accepts a new connection with a given timeout. This method requires the
* channel to be configured in blocking mode.
*
* @apiNote This method is for use by the socket adaptor.
*
* @param nanos the timeout, in nanoseconds
* @throws IllegalBlockingModeException if the channel is configured non-blocking
* @throws SocketTimeoutException if the timeout expires
*/
SocketChannel blockingAccept(long nanos) throws IOException {
int n = 0;
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
acceptLock.lock();
try {
// check that channel is configured blocking
if (!isBlocking())
throw new IllegalBlockingModeException();
try {
begin(true);
// change socket to non-blocking
lockedConfigureBlocking(false);
try {
long startNanos = System.nanoTime();
n = Net.accept(fd, newfd, isaa);
while (n == IOStatus.UNAVAILABLE && isOpen()) {
long remainingNanos = nanos - (System.nanoTime() - startNanos);
if (remainingNanos <= 0) {
throw new SocketTimeoutException("Accept timed out");
}
park(Net.POLLIN, remainingNanos);
n = Net.accept(fd, newfd, isaa);
}
} finally {
// restore socket to blocking mode
lockedConfigureBlocking(true);
}
} finally {
end(true, n > 0);
}
} finally {
acceptLock.unlock();
}
assert n > 0;
return finishAccept(newfd, isaa[0]);
}
private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
throws IOException
{
try {
// newly accepted socket is initially in blocking mode
IOUtil.configureBlocking(newfd, true);
@ -306,15 +394,26 @@ class ServerSocketChannelImpl
protected void implConfigureBlocking(boolean block) throws IOException {
acceptLock.lock();
try {
synchronized (stateLock) {
ensureOpen();
IOUtil.configureBlocking(fd, block);
}
lockedConfigureBlocking(block);
} finally {
acceptLock.unlock();
}
}
/**
* Adjust the blocking mode while holding acceptLock.
*/
private void lockedConfigureBlocking(boolean block) throws IOException {
assert acceptLock.isHeldByCurrentThread();
stateLock.lock();
try {
ensureOpen();
IOUtil.configureBlocking(fd, block);
} finally {
stateLock.unlock();
}
}
/**
* Invoked by implCloseChannel to close the channel.
*
@ -336,15 +435,19 @@ class ServerSocketChannelImpl
boolean blocking;
// set state to ST_CLOSING
synchronized (stateLock) {
stateLock.lock();
try {
assert state < ST_CLOSING;
state = ST_CLOSING;
blocking = isBlocking();
} finally {
stateLock.unlock();
}
// wait for any outstanding accept to complete
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
long th = thread;
if (th != 0) {
@ -354,12 +457,14 @@ class ServerSocketChannelImpl
// wait for accept operation to end
while (thread != 0) {
try {
stateLock.wait();
stateCondition.await();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
} finally {
stateLock.unlock();
}
} else {
// non-blocking mode: wait for accept to complete
@ -368,9 +473,12 @@ class ServerSocketChannelImpl
}
// set state to ST_KILLPENDING
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
state = ST_KILLPENDING;
} finally {
stateLock.unlock();
}
// close socket if not registered with Selector
@ -384,11 +492,14 @@ class ServerSocketChannelImpl
@Override
public void kill() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
if (state == ST_KILLPENDING) {
state = ST_KILLED;
nd.close(fd);
}
} finally {
stateLock.unlock();
}
}
@ -396,8 +507,11 @@ class ServerSocketChannelImpl
* Returns true if channel's socket is bound
*/
boolean isBound() {
synchronized (stateLock) {
stateLock.lock();
try {
return localAddress != null;
} finally {
stateLock.unlock();
}
}
@ -405,30 +519,11 @@ class ServerSocketChannelImpl
* Returns the local address, or null if not bound
*/
InetSocketAddress localAddress() {
synchronized (stateLock) {
return localAddress;
}
}
/**
* Poll this channel's socket for a new connection up to the given timeout.
* @return {@code true} if there is a connection to accept
*/
boolean pollAccept(long timeout) throws IOException {
assert Thread.holdsLock(blockingLock()) && isBlocking();
acceptLock.lock();
stateLock.lock();
try {
boolean polled = false;
try {
begin(true);
int events = Net.poll(fd, Net.POLLIN, timeout);
polled = (events != 0);
} finally {
end(true, polled);
}
return polled;
return localAddress;
} finally {
acceptLock.unlock();
stateLock.unlock();
}
}
@ -494,13 +589,16 @@ class ServerSocketChannelImpl
if (!isOpen()) {
sb.append("closed");
} else {
synchronized (stateLock) {
stateLock.lock();
try {
InetSocketAddress addr = localAddress;
if (addr == null) {
sb.append("unbound");
} else {
sb.append(Net.getRevealedLocalAddressAsString(addr));
}
} finally {
stateLock.unlock();
}
}
sb.append(']');

View file

@ -33,18 +33,12 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketOption;
import java.net.SocketTimeoutException;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.SocketChannel;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import static java.util.concurrent.TimeUnit.*;
import java.util.Set;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
// Make a socket channel look like a socket.
//
@ -62,11 +56,11 @@ class SocketAdaptor
private volatile int timeout;
private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
super((SocketImpl) null);
super(DummySocketImpl.create());
this.sc = sc;
}
public static Socket create(SocketChannelImpl sc) {
static Socket create(SocketChannelImpl sc) {
try {
return new SocketAdaptor(sc);
} catch (SocketException e) {
@ -74,70 +68,30 @@ class SocketAdaptor
}
}
public SocketChannel getChannel() {
return sc;
}
// Override this method just to protect against changes in the superclass
//
@Override
public void connect(SocketAddress remote) throws IOException {
connect(remote, 0);
}
@Override
public void connect(SocketAddress remote, int timeout) throws IOException {
if (remote == null)
throw new IllegalArgumentException("connect: The address can't be null");
if (timeout < 0)
throw new IllegalArgumentException("connect: timeout can't be negative");
synchronized (sc.blockingLock()) {
if (!sc.isBlocking())
throw new IllegalBlockingModeException();
try {
// no timeout
if (timeout == 0) {
sc.connect(remote);
return;
}
// timed connect
sc.configureBlocking(false);
try {
if (sc.connect(remote))
return;
} finally {
try {
sc.configureBlocking(true);
} catch (ClosedChannelException e) { }
}
long timeoutNanos = NANOSECONDS.convert(timeout, MILLISECONDS);
long to = timeout;
for (;;) {
long startTime = System.nanoTime();
if (sc.pollConnected(to)) {
boolean connected = sc.finishConnect();
assert connected;
break;
}
timeoutNanos -= System.nanoTime() - startTime;
if (timeoutNanos <= 0) {
try {
sc.close();
} catch (IOException x) { }
throw new SocketTimeoutException();
}
to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
}
} catch (Exception x) {
Net.translateException(x, true);
try {
if (timeout > 0) {
long nanos = MILLISECONDS.toNanos(timeout);
sc.blockingConnect(remote, nanos);
} else {
sc.blockingConnect(remote, Long.MAX_VALUE);
}
} catch (Exception e) {
Net.translateException(e, true);
}
}
@Override
public void bind(SocketAddress local) throws IOException {
try {
sc.bind(local);
@ -146,6 +100,7 @@ class SocketAdaptor
}
}
@Override
public InetAddress getInetAddress() {
InetSocketAddress remote = sc.remoteAddress();
if (remote == null) {
@ -155,6 +110,7 @@ class SocketAdaptor
}
}
@Override
public InetAddress getLocalAddress() {
if (sc.isOpen()) {
InetSocketAddress local = sc.localAddress();
@ -165,6 +121,7 @@ class SocketAdaptor
return new InetSocketAddress(0).getAddress();
}
@Override
public int getPort() {
InetSocketAddress remote = sc.remoteAddress();
if (remote == null) {
@ -174,6 +131,7 @@ class SocketAdaptor
}
}
@Override
public int getLocalPort() {
InetSocketAddress local = sc.localAddress();
if (local == null) {
@ -183,48 +141,27 @@ class SocketAdaptor
}
}
private class SocketInputStream
extends ChannelInputStream
{
private SocketInputStream() {
super(sc);
}
@Override
public SocketAddress getRemoteSocketAddress() {
return sc.remoteAddress();
}
protected int read(ByteBuffer bb)
throws IOException
{
synchronized (sc.blockingLock()) {
if (!sc.isBlocking())
throw new IllegalBlockingModeException();
// no timeout
long to = SocketAdaptor.this.timeout;
if (to == 0)
return sc.read(bb);
// timed read
long timeoutNanos = NANOSECONDS.convert(to, MILLISECONDS);
for (;;) {
long startTime = System.nanoTime();
if (sc.pollRead(to)) {
return sc.read(bb);
}
timeoutNanos -= System.nanoTime() - startTime;
if (timeoutNanos <= 0)
throw new SocketTimeoutException();
to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
}
}
}
@Override
public int available() throws IOException {
return sc.available();
@Override
public SocketAddress getLocalSocketAddress() {
InetSocketAddress local = sc.localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local);
} else {
return null;
}
}
private InputStream socketInputStream = null;
@Override
public SocketChannel getChannel() {
return sc;
}
@Override
public InputStream getInputStream() throws IOException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
@ -232,21 +169,35 @@ class SocketAdaptor
throw new SocketException("Socket is not connected");
if (!sc.isInputOpen())
throw new SocketException("Socket input is shutdown");
if (socketInputStream == null) {
try {
socketInputStream = AccessController.doPrivileged(
new PrivilegedExceptionAction<InputStream>() {
public InputStream run() throws IOException {
return new SocketInputStream();
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException)e.getException();
return new InputStream() {
@Override
public int read() throws IOException {
byte[] a = new byte[1];
int n = read(a, 0, 1);
return (n > 0) ? (a[0] & 0xff) : -1;
}
}
return socketInputStream;
@Override
public int read(byte[] b, int off, int len) throws IOException {
int timeout = SocketAdaptor.this.timeout;
if (timeout > 0) {
long nanos = MILLISECONDS.toNanos(timeout);
return sc.blockingRead(b, off, len, nanos);
} else {
return sc.blockingRead(b, off, len, 0);
}
}
@Override
public int available() throws IOException {
return sc.available();
}
@Override
public void close() throws IOException {
sc.close();
}
};
}
@Override
public OutputStream getOutputStream() throws IOException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
@ -254,18 +205,21 @@ class SocketAdaptor
throw new SocketException("Socket is not connected");
if (!sc.isOutputOpen())
throw new SocketException("Socket output is shutdown");
OutputStream os = null;
try {
os = AccessController.doPrivileged(
new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return Channels.newOutputStream(sc);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException)e.getException();
}
return os;
return new OutputStream() {
@Override
public void write(int b) throws IOException {
byte[] a = new byte[]{(byte) b};
write(a, 0, 1);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
sc.blockingWriteFully(b, off, len);
}
@Override
public void close() throws IOException {
sc.close();
}
};
}
private void setBooleanOption(SocketOption<Boolean> name, boolean value)
@ -306,48 +260,62 @@ class SocketAdaptor
}
}
@Override
public void setTcpNoDelay(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
}
@Override
public boolean getTcpNoDelay() throws SocketException {
return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
}
@Override
public void setSoLinger(boolean on, int linger) throws SocketException {
if (!on)
linger = -1;
setIntOption(StandardSocketOptions.SO_LINGER, linger);
}
@Override
public int getSoLinger() throws SocketException {
return getIntOption(StandardSocketOptions.SO_LINGER);
}
@Override
public void sendUrgentData(int data) throws IOException {
int n = sc.sendOutOfBandData((byte) data);
if (n == 0)
throw new IOException("Socket buffer full");
}
@Override
public void setOOBInline(boolean on) throws SocketException {
setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
}
@Override
public boolean getOOBInline() throws SocketException {
return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
}
@Override
public void setSoTimeout(int timeout) throws SocketException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
if (timeout < 0)
throw new IllegalArgumentException("timeout can't be negative");
throw new IllegalArgumentException("timeout < 0");
this.timeout = timeout;
}
@Override
public int getSoTimeout() throws SocketException {
if (!sc.isOpen())
throw new SocketException("Socket is closed");
return timeout;
}
@Override
public void setSendBufferSize(int size) throws SocketException {
// size 0 valid for SocketChannel, invalid for Socket
if (size <= 0)
@ -355,10 +323,12 @@ class SocketAdaptor
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
}
@Override
public int getSendBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_SNDBUF);
}
@Override
public void setReceiveBufferSize(int size) throws SocketException {
// size 0 valid for SocketChannel, invalid for Socket
if (size <= 0)
@ -366,38 +336,47 @@ class SocketAdaptor
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
}
@Override
public int getReceiveBufferSize() throws SocketException {
return getIntOption(StandardSocketOptions.SO_RCVBUF);
}
@Override
public void setKeepAlive(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
}
@Override
public boolean getKeepAlive() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
}
@Override
public void setTrafficClass(int tc) throws SocketException {
setIntOption(StandardSocketOptions.IP_TOS, tc);
}
@Override
public int getTrafficClass() throws SocketException {
return getIntOption(StandardSocketOptions.IP_TOS);
}
@Override
public void setReuseAddress(boolean on) throws SocketException {
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
}
@Override
public boolean getReuseAddress() throws SocketException {
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
}
@Override
public void close() throws IOException {
sc.close();
}
@Override
public void shutdownInput() throws IOException {
try {
sc.shutdownInput();
@ -406,6 +385,7 @@ class SocketAdaptor
}
}
@Override
public void shutdownOutput() throws IOException {
try {
sc.shutdownOutput();
@ -414,6 +394,7 @@ class SocketAdaptor
}
}
@Override
public String toString() {
if (sc.isConnected())
return "Socket[addr=" + getInetAddress() +
@ -422,23 +403,44 @@ class SocketAdaptor
return "Socket[unconnected]";
}
@Override
public boolean isConnected() {
return sc.isConnected();
}
@Override
public boolean isBound() {
return sc.localAddress() != null;
}
@Override
public boolean isClosed() {
return !sc.isOpen();
}
@Override
public boolean isInputShutdown() {
return !sc.isInputOpen();
}
@Override
public boolean isOutputShutdown() {
return !sc.isOutputOpen();
}
@Override
public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {
sc.setOption(name, value);
return this;
}
@Override
public <T> T getOption(SocketOption<T> name) throws IOException {
return sc.getOption(name);
}
@Override
public Set<SocketOption<?>> supportedOptions() {
return sc.supportedOptions();
}
}

View file

@ -34,6 +34,7 @@ import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOption;
import java.net.SocketTimeoutException;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
@ -42,6 +43,7 @@ import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.NoConnectionPendingException;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
@ -51,6 +53,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import sun.net.ConnectionResetException;
@ -81,7 +84,8 @@ class SocketChannelImpl
// Lock held by any thread that modifies the state fields declared below
// DO NOT invoke a blocking I/O operation while holding this lock!
private final Object stateLock = new Object();
private final ReentrantLock stateLock = new ReentrantLock();
private final Condition stateCondition = stateLock.newCondition();
// Input/Output closed
private volatile boolean isInputClosed;
@ -133,8 +137,11 @@ class SocketChannelImpl
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
if (bound) {
synchronized (stateLock) {
stateLock.lock();
try {
this.localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
}
}
@ -147,10 +154,13 @@ class SocketChannelImpl
super(sp);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
synchronized (stateLock) {
stateLock.lock();
try {
this.localAddress = Net.localAddress(fd);
this.remoteAddress = isa;
this.state = ST_CONNECTED;
} finally {
stateLock.unlock();
}
}
@ -187,26 +197,35 @@ class SocketChannelImpl
@Override
public Socket socket() {
synchronized (stateLock) {
stateLock.lock();
try {
if (socket == null)
socket = SocketAdaptor.create(this);
return socket;
} finally {
stateLock.unlock();
}
}
@Override
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
return Net.getRevealedLocalAddress(localAddress);
} finally {
stateLock.unlock();
}
}
@Override
public SocketAddress getRemoteAddress() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
return remoteAddress;
} finally {
stateLock.unlock();
}
}
@ -218,7 +237,8 @@ class SocketChannelImpl
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.IP_TOS) {
@ -237,6 +257,8 @@ class SocketChannelImpl
// no options that require special handling
Net.setSocketOption(fd, name, value);
return this;
} finally {
stateLock.unlock();
}
}
@ -249,7 +271,8 @@ class SocketChannelImpl
if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
@ -266,6 +289,8 @@ class SocketChannelImpl
// no options that require special handling
return (T) Net.getSocketOption(fd, name);
} finally {
stateLock.unlock();
}
}
@ -307,10 +332,13 @@ class SocketChannelImpl
// set hook for Thread.interrupt
begin();
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpenAndConnected();
// record thread so it can be signalled if needed
readerThread = NativeThread.current();
} finally {
stateLock.unlock();
}
} else {
ensureOpenAndConnected();
@ -327,12 +355,15 @@ class SocketChannelImpl
throws AsynchronousCloseException
{
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
readerThread = 0;
// notify any thread waiting in implCloseSelectableChannel
if (state == ST_CLOSING) {
stateLock.notifyAll();
stateCondition.signalAll();
}
} finally {
stateLock.unlock();
}
// remove hook for Thread.interrupt
end(completed);
@ -362,12 +393,12 @@ class SocketChannelImpl
if (isInputClosed)
return IOStatus.EOF;
n = IOUtil.read(fd, buf, -1, nd);
if (blocking) {
do {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = IOUtil.read(fd, buf, -1, nd);
} while (n == IOStatus.INTERRUPTED && isOpen());
} else {
n = IOUtil.read(fd, buf, -1, nd);
}
}
} catch (ConnectionResetException e) {
connectionReset = true;
@ -404,12 +435,12 @@ class SocketChannelImpl
if (isInputClosed)
return IOStatus.EOF;
n = IOUtil.read(fd, dsts, offset, length, nd);
if (blocking) {
do {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = IOUtil.read(fd, dsts, offset, length, nd);
} while (n == IOStatus.INTERRUPTED && isOpen());
} else {
n = IOUtil.read(fd, dsts, offset, length, nd);
}
}
} catch (ConnectionResetException e) {
connectionReset = true;
@ -436,12 +467,15 @@ class SocketChannelImpl
// set hook for Thread.interrupt
begin();
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpenAndConnected();
if (isOutputClosed)
throw new ClosedChannelException();
// record thread so it can be signalled if needed
writerThread = NativeThread.current();
} finally {
stateLock.unlock();
}
} else {
ensureOpenAndConnected();
@ -458,12 +492,15 @@ class SocketChannelImpl
throws AsynchronousCloseException
{
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
writerThread = 0;
// notify any thread waiting in implCloseSelectableChannel
if (state == ST_CLOSING) {
stateLock.notifyAll();
stateCondition.signalAll();
}
} finally {
stateLock.unlock();
}
// remove hook for Thread.interrupt
end(completed);
@ -480,12 +517,12 @@ class SocketChannelImpl
int n = 0;
try {
beginWrite(blocking);
n = IOUtil.write(fd, buf, -1, nd);
if (blocking) {
do {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = IOUtil.write(fd, buf, -1, nd);
} while (n == IOStatus.INTERRUPTED && isOpen());
} else {
n = IOUtil.write(fd, buf, -1, nd);
}
}
} finally {
endWrite(blocking, n > 0);
@ -510,12 +547,12 @@ class SocketChannelImpl
long n = 0;
try {
beginWrite(blocking);
n = IOUtil.write(fd, srcs, offset, length, nd);
if (blocking) {
do {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = IOUtil.write(fd, srcs, offset, length, nd);
} while (n == IOStatus.INTERRUPTED && isOpen());
} else {
n = IOUtil.write(fd, srcs, offset, length, nd);
}
}
} finally {
endWrite(blocking, n > 0);
@ -562,10 +599,7 @@ class SocketChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
ensureOpen();
IOUtil.configureBlocking(fd, block);
}
lockedConfigureBlocking(block);
} finally {
writeLock.unlock();
}
@ -574,12 +608,29 @@ class SocketChannelImpl
}
}
/**
* Adjust the blocking mode while holding the readLock or writeLock.
*/
private void lockedConfigureBlocking(boolean block) throws IOException {
assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
stateLock.lock();
try {
ensureOpen();
IOUtil.configureBlocking(fd, block);
} finally {
stateLock.unlock();
}
}
/**
* Returns the local address, or null if not bound
*/
InetSocketAddress localAddress() {
synchronized (stateLock) {
stateLock.lock();
try {
return localAddress;
} finally {
stateLock.unlock();
}
}
@ -587,8 +638,11 @@ class SocketChannelImpl
* Returns the remote address, or null if not connected
*/
InetSocketAddress remoteAddress() {
synchronized (stateLock) {
stateLock.lock();
try {
return remoteAddress;
} finally {
stateLock.unlock();
}
}
@ -598,7 +652,8 @@ class SocketChannelImpl
try {
writeLock.lock();
try {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (state == ST_CONNECTIONPENDING)
throw new ConnectionPendingException();
@ -613,6 +668,8 @@ class SocketChannelImpl
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
} finally {
stateLock.unlock();
}
} finally {
writeLock.unlock();
@ -649,7 +706,8 @@ class SocketChannelImpl
// set hook for Thread.interrupt
begin();
}
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
int state = this.state;
if (state == ST_CONNECTED)
@ -667,6 +725,8 @@ class SocketChannelImpl
// record thread so it can be signalled if needed
readerThread = NativeThread.current();
}
} finally {
stateLock.unlock();
}
}
@ -683,43 +743,62 @@ class SocketChannelImpl
endRead(blocking, completed);
if (completed) {
synchronized (stateLock) {
stateLock.lock();
try {
if (state == ST_CONNECTIONPENDING) {
localAddress = Net.localAddress(fd);
state = ST_CONNECTED;
}
} finally {
stateLock.unlock();
}
}
}
@Override
public boolean connect(SocketAddress sa) throws IOException {
/**
* Checks the remote address to which this channel is to be connected.
*/
private InetSocketAddress checkRemote(SocketAddress sa) throws IOException {
InetSocketAddress isa = Net.checkAddress(sa);
SecurityManager sm = System.getSecurityManager();
if (sm != null)
if (sm != null) {
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
}
if (isa.getAddress().isAnyLocalAddress()) {
return new InetSocketAddress(InetAddress.getLocalHost(), isa.getPort());
} else {
return isa;
}
}
InetAddress ia = isa.getAddress();
if (ia.isAnyLocalAddress())
ia = InetAddress.getLocalHost();
@Override
public boolean connect(SocketAddress remote) throws IOException {
InetSocketAddress isa = checkRemote(remote);
try {
readLock.lock();
try {
writeLock.lock();
try {
int n = 0;
boolean blocking = isBlocking();
boolean connected = false;
try {
beginConnect(blocking, isa);
do {
n = Net.connect(fd, ia, isa.getPort());
} while (n == IOStatus.INTERRUPTED && isOpen());
int n = Net.connect(fd, isa.getAddress(), isa.getPort());
if (n > 0) {
connected = true;
} else if (blocking) {
assert IOStatus.okayToRetry(n);
boolean polled = false;
while (!polled && isOpen()) {
park(Net.POLLOUT);
polled = Net.pollConnectNow(fd);
}
connected = polled && isOpen();
}
} finally {
endConnect(blocking, (n > 0));
endConnect(blocking, connected);
}
assert IOStatus.check(n);
return n > 0;
return connected;
} finally {
writeLock.unlock();
}
@ -744,7 +823,8 @@ class SocketChannelImpl
// set hook for Thread.interrupt
begin();
}
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (state != ST_CONNECTIONPENDING)
throw new NoConnectionPendingException();
@ -752,6 +832,8 @@ class SocketChannelImpl
// record thread so it can be signalled if needed
readerThread = NativeThread.current();
}
} finally {
stateLock.unlock();
}
}
@ -768,11 +850,14 @@ class SocketChannelImpl
endRead(blocking, completed);
if (completed) {
synchronized (stateLock) {
stateLock.lock();
try {
if (state == ST_CONNECTIONPENDING) {
localAddress = Net.localAddress(fd);
state = ST_CONNECTED;
}
} finally {
stateLock.unlock();
}
}
}
@ -792,13 +877,14 @@ class SocketChannelImpl
boolean connected = false;
try {
beginFinishConnect(blocking);
boolean polled = Net.pollConnectNow(fd);
if (blocking) {
do {
connected = Net.pollConnect(fd, -1);
} while (!connected && isOpen());
} else {
connected = Net.pollConnect(fd, 0);
while (!polled && isOpen()) {
park(Net.POLLOUT);
polled = Net.pollConnectNow(fd);
}
}
connected = polled && isOpen();
} finally {
endFinishConnect(blocking, connected);
}
@ -843,16 +929,20 @@ class SocketChannelImpl
boolean interrupted = false;
// set state to ST_CLOSING
synchronized (stateLock) {
stateLock.lock();
try {
assert state < ST_CLOSING;
blocking = isBlocking();
connected = (state == ST_CONNECTED);
state = ST_CLOSING;
} finally {
stateLock.unlock();
}
// wait for any outstanding I/O operations to complete
if (blocking) {
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
long reader = readerThread;
long writer = writerThread;
@ -868,12 +958,14 @@ class SocketChannelImpl
// wait for blocking I/O operations to end
while (readerThread != 0 || writerThread != 0) {
try {
stateLock.wait();
stateCondition.await();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
} finally {
stateLock.unlock();
}
} else {
// non-blocking mode: wait for read/write to complete
@ -887,7 +979,8 @@ class SocketChannelImpl
}
// set state to ST_KILLPENDING
synchronized (stateLock) {
stateLock.lock();
try {
assert state == ST_CLOSING;
// if connected and the channel is registered with a Selector then
// shutdown the output if possible so that the peer reads EOF. If
@ -908,6 +1001,8 @@ class SocketChannelImpl
} catch (IOException ignore) { }
}
state = ST_KILLPENDING;
} finally {
stateLock.unlock();
}
// close socket if not registered with Selector
@ -921,17 +1016,21 @@ class SocketChannelImpl
@Override
public void kill() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
if (state == ST_KILLPENDING) {
state = ST_KILLED;
nd.close(fd);
}
} finally {
stateLock.unlock();
}
}
@Override
public SocketChannel shutdownInput() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (!isConnected())
throw new NotYetConnectedException();
@ -943,12 +1042,15 @@ class SocketChannelImpl
isInputClosed = true;
}
return this;
} finally {
stateLock.unlock();
}
}
@Override
public SocketChannel shutdownOutput() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpen();
if (!isConnected())
throw new NotYetConnectedException();
@ -960,6 +1062,8 @@ class SocketChannelImpl
isOutputClosed = true;
}
return this;
} finally {
stateLock.unlock();
}
}
@ -972,58 +1076,223 @@ class SocketChannelImpl
}
/**
* Poll this channel's socket for reading up to the given timeout.
* @return {@code true} if the socket is polled
* Waits for a connection attempt to finish with a timeout
* @throws SocketTimeoutException if the connect timeout elapses
*/
boolean pollRead(long timeout) throws IOException {
boolean blocking = isBlocking();
assert Thread.holdsLock(blockingLock()) && blocking;
private boolean finishTimedConnect(long nanos) throws IOException {
long startNanos = System.nanoTime();
boolean polled = Net.pollConnectNow(fd);
while (!polled && isOpen()) {
long remainingNanos = nanos - (System.nanoTime() - startNanos);
if (remainingNanos <= 0) {
throw new SocketTimeoutException("Connect timed out");
}
park(Net.POLLOUT, remainingNanos);
polled = Net.pollConnectNow(fd);
}
return polled && isOpen();
}
/**
* Attempts to establish a connection to the given socket address with a
* timeout. Closes the socket if connection cannot be established.
*
* @apiNote This method is for use by the socket adaptor.
*
* @throws IllegalBlockingModeException if the channel is non-blocking
* @throws SocketTimeoutException if the read timeout elapses
*/
void blockingConnect(SocketAddress remote, long nanos) throws IOException {
InetSocketAddress isa = checkRemote(remote);
try {
readLock.lock();
try {
writeLock.lock();
try {
if (!isBlocking())
throw new IllegalBlockingModeException();
boolean connected = false;
try {
beginConnect(true, isa);
// change socket to non-blocking
lockedConfigureBlocking(false);
try {
int n = Net.connect(fd, isa.getAddress(), isa.getPort());
connected = (n > 0) ? true : finishTimedConnect(nanos);
} finally {
// restore socket to blocking mode
lockedConfigureBlocking(true);
}
} finally {
endConnect(true, connected);
}
} finally {
writeLock.unlock();
}
} finally {
readLock.unlock();
}
} catch (IOException ioe) {
// connect failed, close the channel
close();
throw SocketExceptions.of(ioe, isa);
}
}
/**
* Attempts to read bytes from the socket into the given byte array.
*/
private int tryRead(byte[] b, int off, int len) throws IOException {
ByteBuffer dst = Util.getTemporaryDirectBuffer(len);
assert dst.position() == 0;
try {
int n = nd.read(fd, ((DirectBuffer)dst).address(), len);
if (n > 0) {
dst.get(b, off, n);
}
return n;
} finally{
Util.offerFirstTemporaryDirectBuffer(dst);
}
}
/**
* Reads bytes from the socket into the given byte array with a timeout.
* @throws SocketTimeoutException if the read timeout elapses
*/
private int timedRead(byte[] b, int off, int len, long nanos) throws IOException {
long startNanos = System.nanoTime();
int n = tryRead(b, off, len);
while (n == IOStatus.UNAVAILABLE && isOpen()) {
long remainingNanos = nanos - (System.nanoTime() - startNanos);
if (remainingNanos <= 0) {
throw new SocketTimeoutException("Read timed out");
}
park(Net.POLLIN, remainingNanos);
n = tryRead(b, off, len);
}
return n;
}
/**
* Reads bytes from the socket into the given byte array.
*
* @apiNote This method is for use by the socket adaptor.
*
* @throws IllegalBlockingModeException if the channel is non-blocking
* @throws SocketTimeoutException if the read timeout elapses
*/
int blockingRead(byte[] b, int off, int len, long nanos) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
// nothing to do
return 0;
}
readLock.lock();
try {
boolean polled = false;
// check that channel is configured blocking
if (!isBlocking())
throw new IllegalBlockingModeException();
int n = 0;
try {
beginRead(blocking);
int events = Net.poll(fd, Net.POLLIN, timeout);
polled = (events != 0);
beginRead(true);
// check if connection has been reset
if (connectionReset)
throwConnectionReset();
// check if input is shutdown
if (isInputClosed)
return IOStatus.EOF;
if (nanos > 0) {
// change socket to non-blocking
lockedConfigureBlocking(false);
try {
n = timedRead(b, off, len, nanos);
} finally {
// restore socket to blocking mode
lockedConfigureBlocking(true);
}
} else {
// read, no timeout
n = tryRead(b, off, len);
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = tryRead(b, off, len);
}
}
} catch (ConnectionResetException e) {
connectionReset = true;
throwConnectionReset();
} finally {
endRead(blocking, polled);
endRead(true, n > 0);
if (n <= 0 && isInputClosed)
return IOStatus.EOF;
}
return polled;
assert n > 0 || n == -1;
return n;
} finally {
readLock.unlock();
}
}
/**
* Poll this channel's socket for a connection, up to the given timeout.
* @return {@code true} if the socket is polled
* Attempts to write a sequence of bytes to the socket from the given
* byte array.
*/
boolean pollConnected(long timeout) throws IOException {
boolean blocking = isBlocking();
assert Thread.holdsLock(blockingLock()) && blocking;
readLock.lock();
private int tryWrite(byte[] b, int off, int len) throws IOException {
ByteBuffer src = Util.getTemporaryDirectBuffer(len);
assert src.position() == 0;
try {
writeLock.lock();
src.put(b, off, len);
return nd.write(fd, ((DirectBuffer)src).address(), len);
} finally {
Util.offerFirstTemporaryDirectBuffer(src);
}
}
/**
* Writes a sequence of bytes to the socket from the given byte array.
*
* @apiNote This method is for use by the socket adaptor.
*/
void blockingWriteFully(byte[] b, int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
// nothing to do
return;
}
writeLock.lock();
try {
// check that channel is configured blocking
if (!isBlocking())
throw new IllegalBlockingModeException();
// loop until all bytes have been written
int pos = off;
int end = off + len;
beginWrite(true);
try {
boolean polled = false;
try {
beginFinishConnect(blocking);
int events = Net.poll(fd, Net.POLLCONN, timeout);
polled = (events != 0);
} finally {
// invoke endFinishConnect with completed = false so that
// the state is not changed to ST_CONNECTED. The socket
// adaptor will use finishConnect to finish.
endFinishConnect(blocking, /*completed*/false);
while (pos < end && isOpen()) {
int size = end - pos;
int n = tryWrite(b, pos, size);
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLOUT);
n = tryWrite(b, pos, size);
}
if (n > 0) {
pos += n;
}
}
return polled;
} finally {
writeLock.unlock();
endWrite(true, pos >= end);
}
} finally {
readLock.unlock();
writeLock.unlock();
}
}
@ -1031,13 +1300,16 @@ class SocketChannelImpl
* Return the number of bytes in the socket input buffer.
*/
int available() throws IOException {
synchronized (stateLock) {
stateLock.lock();
try {
ensureOpenAndConnected();
if (isInputClosed) {
return 0;
} else {
return Net.available(fd);
}
} finally {
stateLock.unlock();
}
}
@ -1117,7 +1389,8 @@ class SocketChannelImpl
if (!isOpen())
sb.append("closed");
else {
synchronized (stateLock) {
stateLock.lock();
try {
switch (state) {
case ST_UNCONNECTED:
sb.append("unconnected");
@ -1142,6 +1415,8 @@ class SocketChannelImpl
sb.append(" remote=");
sb.append(remoteAddress().toString());
}
} finally {
stateLock.unlock();
}
}
sb.append(']');

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -109,7 +109,9 @@ enum {
JVM_CONSTANT_MethodType = 16, // JSR 292
JVM_CONSTANT_Dynamic = 17,
JVM_CONSTANT_InvokeDynamic = 18,
JVM_CONSTANT_ExternalMax = 18
JVM_CONSTANT_Module = 19,
JVM_CONSTANT_Package = 20,
JVM_CONSTANT_ExternalMax = 20
};
/* JVM_CONSTANT_MethodHandle subtypes */

View file

@ -27,12 +27,19 @@
#include "java_net_InetAddress.h"
int IPv4_supported();
int IPv6_supported();
int reuseport_supported();
static int IPv4_available;
static int IPv6_available;
static int REUSEPORT_available;
JNIEXPORT jint JNICALL ipv4_available()
{
return IPv4_available;
}
JNIEXPORT jint JNICALL ipv6_available()
{
return IPv6_available;
@ -68,6 +75,7 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
* check now whether we have IPv6 on this platform and if the
* supporting socket APIs are available
*/
IPv4_available = IPv4_supported();
IPv6_available = IPv6_supported() & (!preferIPv4Stack);
/* check if SO_REUSEPORT is supported on this platform */

View file

@ -126,6 +126,7 @@ void NET_ThrowCurrent(JNIEnv *env, char *msg);
jfieldID NET_GetFileDescriptorID(JNIEnv *env);
JNIEXPORT jint JNICALL ipv4_available();
JNIEXPORT jint JNICALL ipv6_available();
JNIEXPORT jint JNICALL reuseport_available();