提交 3e4cf7db 编写于 作者: T tbell

Merge

^build/ ^build/
^dist/ ^dist/
^nbproject/private/ ^nbproject/private/
^make/netbeans/.*/nbproject/private/
^make/netbeans/.*/build/
^make/netbeans/.*/dist/
...@@ -160,7 +160,6 @@ FILES_src = \ ...@@ -160,7 +160,6 @@ FILES_src = \
\ \
sun/nio/ByteBuffered.java \ sun/nio/ByteBuffered.java \
\ \
sun/nio/ch/AbstractFuture.java \
sun/nio/ch/AbstractPollArrayWrapper.java \ sun/nio/ch/AbstractPollArrayWrapper.java \
sun/nio/ch/AllocatedNativeObject.java \ sun/nio/ch/AllocatedNativeObject.java \
sun/nio/ch/AsynchronousChannelGroupImpl.java \ sun/nio/ch/AsynchronousChannelGroupImpl.java \
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="jdwpgen" default="default" basedir=".">
<description>Builds, tests, and runs the project jdwpgen.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="jdwpgen-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>
此差异已折叠。
#FindBugs User Preferences
#Mon Jun 15 13:37:16 PDT 2009
detectorAbnormalFinallyBlockReturn=AbnormalFinallyBlockReturn|false
detectorAbstractClassEmptyMethods=AbstractClassEmptyMethods|false
detectorAbstractOverriddenMethod=AbstractOverriddenMethod|false
detectorArrayBasedCollections=ArrayBasedCollections|false
detectorArrayWrappedCallByReference=ArrayWrappedCallByReference|false
detectorBloatedAssignmentScope=BloatedAssignmentScope|false
detectorBloatedSynchronizedBlock=BloatedSynchronizedBlock|false
detectorClassEnvy=ClassEnvy|false
detectorCollectStatistics=CollectStatistics|false
detectorConfusingAutoboxedOverloading=ConfusingAutoboxedOverloading|false
detectorConstantListIndex=ConstantListIndex|false
detectorCopiedOverriddenMethod=CopiedOverriddenMethod|false
detectorCustomBuiltXML=CustomBuiltXML|false
detectorCyclomaticComplexity=CyclomaticComplexity|false
detectorDateComparison=DateComparison|false
detectorDeclaredRuntimeException=DeclaredRuntimeException|false
detectorDeletingWhileIterating=DeletingWhileIterating|false
detectorDubiousListCollection=DubiousListCollection|false
detectorFieldCouldBeLocal=FieldCouldBeLocal|false
detectorFinalParameters=FinalParameters|false
detectorFloatingPointLoops=FloatingPointLoops|false
detectorInefficientStringBuffering=InefficientStringBuffering|false
detectorInheritanceTypeChecking=InheritanceTypeChecking|false
detectorJDBCVendorReliance=JDBCVendorReliance|false
detectorListIndexedIterating=ListIndexedIterating|false
detectorLiteralStringComparison=LiteralStringComparison|false
detectorLocalSynchronizedCollection=LocalSynchronizedCollection|false
detectorLostExceptionStackTrace=LostExceptionStackTrace|false
detectorManualArrayCopy=ManualArrayCopy|false
detectorMethodReturnsConstant=MethodReturnsConstant|false
detectorNeedlessAutoboxing=NeedlessAutoboxing|false
detectorNeedlessCustomSerialization=NeedlessCustomSerialization|false
detectorNeedlessInstanceRetrieval=NeedlessInstanceRetrieval|false
detectorNeedlessMemberCollectionSynchronization=NeedlessMemberCollectionSynchronization|false
detectorNonCollectionMethodUse=NonCollectionMethodUse|false
detectorNonOwnedSynchronization=NonOwnedSynchronization|false
detectorNonRecycleableTaglibs=NonRecycleableTaglibs|false
detectorOrphanedDOMNode=OrphanedDOMNode|false
detectorOverlyConcreteParameter=OverlyConcreteParameter|false
detectorParallelLists=ParallelLists|false
detectorPartiallyConstructedObjectAccess=PartiallyConstructedObjectAccess|false
detectorPossibleIncompleteSerialization=PossibleIncompleteSerialization|false
detectorPossibleMemoryBloat=PossibleMemoryBloat|false
detectorPossiblyRedundantMethodCalls=PossiblyRedundantMethodCalls|false
detectorSQLInLoop=SQLInLoop|false
detectorSection508Compliance=Section508Compliance|false
detectorSillynessPotPourri=SillynessPotPourri|false
detectorSloppyClassReflection=SloppyClassReflection|false
detectorSluggishGui=SluggishGui|false
detectorSpoiledChildInterfaceImplementor=SpoiledChildInterfaceImplementor|false
detectorSpuriousThreadStates=SpuriousThreadStates|false
detectorStaticArrayCreatedInMethod=StaticArrayCreatedInMethod|false
detectorStaticMethodInstanceInvocation=StaticMethodInstanceInvocation|false
detectorSuspiciousComparatorReturnValues=SuspiciousComparatorReturnValues|false
detectorSuspiciousJDKVersionUse=SuspiciousJDKVersionUse|false
detectorSuspiciousWaitOnConcurrentObject=SuspiciousWaitOnConcurrentObject|false
detectorSyncCollectionIterators=SyncCollectionIterators|false
detectorTailRecursion=TailRecursion|false
detectorUnnecessaryStoreBeforeReturn=UnnecessaryStoreBeforeReturn|false
detectorUnrelatedCollectionContents=UnrelatedCollectionContents|false
detectorUnrelatedReturnValues=UnrelatedReturnValues|false
detectorUseAddAll=UseAddAll|false
detectorUseCharacterParameterizedMethod=UseCharacterParameterizedMethod|false
detectorUseEnumCollections=UseEnumCollections|false
detectorUseSplit=UseSplit|false
detectorUseToArray=UseToArray|false
detector_threshold=2
effort=default
filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false
filter_settings_neg=|
build.xml.data.CRC32=b40e775f
build.xml.script.CRC32=af8dc3cb
build.xml.stylesheet.CRC32=958a1d3e
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=b40e775f
nbproject/build-impl.xml.script.CRC32=624d12c5
nbproject/build-impl.xml.stylesheet.CRC32=65b8de21
application.title=jdwpgen
application.vendor=sun
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/jdwpgen.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.tools-jdwpgen=../../tools/src/build/tools/jdwpgen
file.reference.tools-src=../../tools/src
includes=build/tools/jdwpgen/**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=-Xlint:all
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=true
javadoc.nonavbar=true
javadoc.notree=true
javadoc.private=true
javadoc.splitindex=false
javadoc.use=false
javadoc.version=false
javadoc.windowtitle=
main.class=jdwpgen.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.src.dir=${file.reference.tools-src}
test.src.dir=test
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>jdwpgen</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>
#Path to FindbugsSettingsFile (relative)
findbugs.settings.file=findbugs.settings
...@@ -30,7 +30,7 @@ import java.io.*; ...@@ -30,7 +30,7 @@ import java.io.*;
abstract class AbstractNamedNode extends Node { abstract class AbstractNamedNode extends Node {
NameNode nameNode; NameNode nameNode = null;
String name; String name;
public String name() { public String name() {
......
...@@ -30,7 +30,7 @@ import java.io.*; ...@@ -30,7 +30,7 @@ import java.io.*;
class AltNode extends AbstractGroupNode implements TypeNode { class AltNode extends AbstractGroupNode implements TypeNode {
SelectNode select; SelectNode select = null;
void constrain(Context ctx) { void constrain(Context ctx) {
super.constrain(ctx); super.constrain(ctx);
......
...@@ -33,13 +33,7 @@ class ConstantSetNode extends AbstractNamedNode { ...@@ -33,13 +33,7 @@ class ConstantSetNode extends AbstractNamedNode {
/** /**
* The mapping between a constant and its value. * The mapping between a constant and its value.
*/ */
protected static Map<String, String> constantMap; protected static final Map<String, String> constantMap = new HashMap<String, String>();
ConstantSetNode(){
if (constantMap == null) {
constantMap = new HashMap<String, String>();
}
}
void prune() { void prune() {
List<Node> addons = new ArrayList<Node>(); List<Node> addons = new ArrayList<Node>();
...@@ -95,9 +89,6 @@ class ConstantSetNode extends AbstractNamedNode { ...@@ -95,9 +89,6 @@ class ConstantSetNode extends AbstractNamedNode {
} }
public static String getConstant(String key){ public static String getConstant(String key){
if (constantMap == null) {
return "";
}
String com = constantMap.get(key); String com = constantMap.get(key);
if(com == null){ if(com == null){
return ""; return "";
......
...@@ -25,13 +25,11 @@ ...@@ -25,13 +25,11 @@
package build.tools.jdwpgen; package build.tools.jdwpgen;
import java.util.*;
import java.io.*; import java.io.*;
class Main { class Main {
static String specSource; static String specSource;
static Map nameMap = new HashMap();
static boolean genDebug = true; static boolean genDebug = true;
static void usage() { static void usage() {
...@@ -43,7 +41,6 @@ class Main { ...@@ -43,7 +41,6 @@ class Main {
System.err.println("-doc <doc_output>"); System.err.println("-doc <doc_output>");
System.err.println("-jdi <java_output>"); System.err.println("-jdi <java_output>");
System.err.println("-include <include_file_output>"); System.err.println("-include <include_file_output>");
System.exit(1);
} }
public static void main(String args[]) throws IOException { public static void main(String args[]) throws IOException {
...@@ -66,6 +63,7 @@ class Main { ...@@ -66,6 +63,7 @@ class Main {
} else { } else {
System.err.println("Invalid option: " + arg); System.err.println("Invalid option: " + arg);
usage(); usage();
return;
} }
} else { } else {
specSource = arg; specSource = arg;
...@@ -75,6 +73,7 @@ class Main { ...@@ -75,6 +73,7 @@ class Main {
if (reader == null) { if (reader == null) {
System.err.println("<spec_input> must be specified"); System.err.println("<spec_input> must be specified");
usage(); usage();
return;
} }
Parse parse = new Parse(reader); Parse parse = new Parse(reader);
......
...@@ -36,7 +36,7 @@ abstract class Node { ...@@ -36,7 +36,7 @@ abstract class Node {
int lineno; int lineno;
List<String> commentList = new ArrayList<String>(); List<String> commentList = new ArrayList<String>();
Node parent = null; Node parent = null;
Context context; Context context = null;
static final int maxStructIndent = 5; static final int maxStructIndent = 5;
static int structIndent = 0; // horrible hack static int structIndent = 0; // horrible hack
...@@ -82,7 +82,7 @@ abstract class Node { ...@@ -82,7 +82,7 @@ abstract class Node {
} }
void indent(PrintWriter writer, int depth) { void indent(PrintWriter writer, int depth) {
for (int i = depth; i > 0; --i) { for (int i = 0; i < depth; i++) {
writer.print(" "); writer.print(" ");
} }
} }
...@@ -195,6 +195,6 @@ abstract class Node { ...@@ -195,6 +195,6 @@ abstract class Node {
System.err.println(Main.specSource + ":" + lineno + ": " + System.err.println(Main.specSource + ":" + lineno + ": " +
kind + " - " + errmsg); kind + " - " + errmsg);
System.err.println(); System.err.println();
System.exit(1); throw new RuntimeException("Error: " + errmsg);
} }
} }
...@@ -146,8 +146,12 @@ class Parse { ...@@ -146,8 +146,12 @@ class Parse {
Node node = (Node)proto.getClass().newInstance(); Node node = (Node)proto.getClass().newInstance();
node.set(kind, list, izer.lineno()); node.set(kind, list, izer.lineno());
return node; return node;
} catch (Exception exc) { } catch (InstantiationException exc) {
error(exc.toString()); error(exc.toString());
return null;
} catch (IllegalAccessException exc) {
error(exc.toString());
return null;
} }
} }
} else { } else {
...@@ -166,6 +170,6 @@ class Parse { ...@@ -166,6 +170,6 @@ class Parse {
void error(String errmsg) { void error(String errmsg) {
System.err.println(Main.specSource + ":" + izer.lineno() + System.err.println(Main.specSource + ":" + izer.lineno() +
": " + errmsg); ": " + errmsg);
System.exit(1); throw new RuntimeException("Error: " + errmsg);
} }
} }
...@@ -30,7 +30,7 @@ import java.io.*; ...@@ -30,7 +30,7 @@ import java.io.*;
class RepeatNode extends AbstractTypeNode { class RepeatNode extends AbstractTypeNode {
Node member; Node member = null;
void constrain(Context ctx) { void constrain(Context ctx) {
super.constrain(ctx); super.constrain(ctx);
......
...@@ -30,7 +30,7 @@ import java.io.*; ...@@ -30,7 +30,7 @@ import java.io.*;
class SelectNode extends AbstractGroupNode implements TypeNode { class SelectNode extends AbstractGroupNode implements TypeNode {
AbstractSimpleTypeNode typeNode; AbstractSimpleTypeNode typeNode = null;
void prune() { void prune() {
super.prune(); super.prune();
......
...@@ -129,7 +129,7 @@ public class TextCallbackHandler implements CallbackHandler { ...@@ -129,7 +129,7 @@ public class TextCallbackHandler implements CallbackHandler {
System.err.print(pc.getPrompt()); System.err.print(pc.getPrompt());
System.err.flush(); System.err.flush();
pc.setPassword(Password.readPassword(System.in)); pc.setPassword(Password.readPassword(System.in, pc.isEchoOn()));
} else if (callbacks[i] instanceof ConfirmationCallback) { } else if (callbacks[i] instanceof ConfirmationCallback) {
confirmation = (ConfirmationCallback) callbacks[i]; confirmation = (ConfirmationCallback) callbacks[i];
......
...@@ -51,7 +51,7 @@ public final class Provider extends java.security.Provider { ...@@ -51,7 +51,7 @@ public final class Provider extends java.security.Provider {
" server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)"; " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)";
public Provider() { public Provider() {
super("SunSASL", 1.5, info); super("SunSASL", 1.7d, info);
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
......
...@@ -28,8 +28,12 @@ package java.lang; ...@@ -28,8 +28,12 @@ package java.lang;
/** /**
* Thrown when an application tries to access an enum constant by name * Thrown when an application tries to access an enum constant by name
* and the enum type contains no constant with the specified name. * and the enum type contains no constant with the specified name.
* This exception can be thrown by the {@linkplain
* java.lang.reflect.AnnotatedElement API used to read annotations
* reflectively}.
* *
* @author Josh Bloch * @author Josh Bloch
* @see java.lang.reflect.AnnotatedElement
* @since 1.5 * @since 1.5
*/ */
public class EnumConstantNotPresentException extends RuntimeException { public class EnumConstantNotPresentException extends RuntimeException {
......
...@@ -2301,6 +2301,54 @@ public final class String ...@@ -2301,6 +2301,54 @@ public final class String
* @spec JSR-51 * @spec JSR-51
*/ */
public String[] split(String regex, int limit) { public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.count == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<String>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, count));
off = count;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[] { this };
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, count));
// Construct result
int resultSize = list.size();
if (limit == 0)
while (resultSize > 0 && list.get(resultSize-1).length() == 0)
resultSize--;
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit); return Pattern.compile(regex).split(this, limit);
} }
......
...@@ -35,8 +35,12 @@ package java.lang; ...@@ -35,8 +35,12 @@ package java.lang;
* <p>Note that this exception may be used when undefined type variables * <p>Note that this exception may be used when undefined type variables
* are accessed as well as when types (e.g., classes, interfaces or * are accessed as well as when types (e.g., classes, interfaces or
* annotation types) are loaded. * annotation types) are loaded.
* In particular, this exception can be thrown by the {@linkplain
* java.lang.reflect.AnnotatedElement API used to read annotations
* reflectively}.
* *
* @author Josh Bloch * @author Josh Bloch
* @see java.lang.reflect.AnnotatedElement
* @since 1.5 * @since 1.5
*/ */
public class TypeNotPresentException extends RuntimeException { public class TypeNotPresentException extends RuntimeException {
......
...@@ -28,8 +28,12 @@ package java.lang.annotation; ...@@ -28,8 +28,12 @@ package java.lang.annotation;
/** /**
* Thrown when the annotation parser attempts to read an annotation * Thrown when the annotation parser attempts to read an annotation
* from a class file and determines that the annotation is malformed. * from a class file and determines that the annotation is malformed.
* This error can be thrown by the {@linkplain
* java.lang.reflect.AnnotatedElement API used to read annotations
* reflectively}.
* *
* @author Josh Bloch * @author Josh Bloch
* @see java.lang.reflect.AnnotatedElement
* @since 1.5 * @since 1.5
*/ */
public class AnnotationFormatError extends Error { public class AnnotationFormatError extends Error {
......
...@@ -30,8 +30,12 @@ import java.lang.reflect.Method; ...@@ -30,8 +30,12 @@ import java.lang.reflect.Method;
* Thrown to indicate that a program has attempted to access an element of * Thrown to indicate that a program has attempted to access an element of
* an annotation whose type has changed after the annotation was compiled * an annotation whose type has changed after the annotation was compiled
* (or serialized). * (or serialized).
* This exception can be thrown by the {@linkplain
* java.lang.reflect.AnnotatedElement API used to read annotations
* reflectively}.
* *
* @author Josh Bloch * @author Josh Bloch
* @see java.lang.reflect.AnnotatedElement
* @since 1.5 * @since 1.5
*/ */
public class AnnotationTypeMismatchException extends RuntimeException { public class AnnotationTypeMismatchException extends RuntimeException {
......
...@@ -30,8 +30,12 @@ package java.lang.annotation; ...@@ -30,8 +30,12 @@ package java.lang.annotation;
* an annotation type that was added to the annotation type definition after * an annotation type that was added to the annotation type definition after
* the annotation was compiled (or serialized). This exception will not be * the annotation was compiled (or serialized). This exception will not be
* thrown if the new element has a default value. * thrown if the new element has a default value.
* This exception can be thrown by the {@linkplain
* java.lang.reflect.AnnotatedElement API used to read annotations
* reflectively}.
* *
* @author Josh Bloch * @author Josh Bloch
* @see java.lang.reflect.AnnotatedElement
* @since 1.5 * @since 1.5
*/ */
public class IncompleteAnnotationException extends RuntimeException { public class IncompleteAnnotationException extends RuntimeException {
......
...@@ -50,6 +50,11 @@ import java.lang.annotation.Annotation; ...@@ -50,6 +50,11 @@ import java.lang.annotation.Annotation;
* java.lang.annotation.AnnotationTypeMismatchException} or an * java.lang.annotation.AnnotationTypeMismatchException} or an
* {@link java.lang.annotation.IncompleteAnnotationException}. * {@link java.lang.annotation.IncompleteAnnotationException}.
* *
* @see java.lang.EnumConstantNotPresentException
* @see java.lang.TypeNotPresentException
* @see java.lang.annotation.AnnotationFormatError
* @see java.lang.annotation.AnnotationTypeMismatchException
* @see java.lang.annotation.IncompleteAnnotationException
* @since 1.5 * @since 1.5
* @author Josh Bloch * @author Josh Bloch
*/ */
......
...@@ -56,18 +56,18 @@ public interface AsynchronousByteChannel ...@@ -56,18 +56,18 @@ public interface AsynchronousByteChannel
/** /**
* Reads a sequence of bytes from this channel into the given buffer. * Reads a sequence of bytes from this channel into the given buffer.
* *
* <p> This method initiates an operation to read a sequence of bytes from * <p> This method initiates an asynchronous read operation to read a
* this channel into the given buffer. The method returns a {@link Future} * sequence of bytes from this channel into the given buffer. The {@code
* representing the pending result of the operation. The result of the * handler} parameter is a completion handler that is invoked when the read
* operation, obtained by invoking the {@code Future} 's {@link * operation completes (or fails). The result passed to the completion
* Future#get() get} method, is the number of bytes read or {@code -1} if * handler is the number of bytes read or {@code -1} if no bytes could be
* all bytes have been read and the channel has reached end-of-stream. * read because the channel has reached end-of-stream.
* *
* <p> This method initiates a read operation to read up to <i>r</i> bytes * <p> The read operation may read up to <i>r</i> bytes from the channel,
* from the channel, where <i>r</i> is the number of bytes remaining in the * where <i>r</i> is the number of bytes remaining in the buffer, that is,
* buffer, that is, {@code dst.remaining()} at the time that the read is * {@code dst.remaining()} at the time that the read is attempted. Where
* attempted. Where <i>r</i> is 0, the read operation completes immediately * <i>r</i> is 0, the read operation completes immediately with a result of
* with a result of {@code 0} without initiating an I/O operation. * {@code 0} without initiating an I/O operation.
* *
* <p> Suppose that a byte sequence of length <i>n</i> is read, where * <p> Suppose that a byte sequence of length <i>n</i> is read, where
* <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>. * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
...@@ -79,44 +79,46 @@ public interface AsynchronousByteChannel ...@@ -79,44 +79,46 @@ public interface AsynchronousByteChannel
* <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed. * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
* *
* <p> Buffers are not safe for use by multiple concurrent threads so care * <p> Buffers are not safe for use by multiple concurrent threads so care
* should be taken to not to access the buffer until the operaton has completed. * should be taken to not access the buffer until the operation has
* completed.
* *
* <p> This method may be invoked at any time. Some channel types may not * <p> This method may be invoked at any time. Some channel types may not
* allow more than one read to be outstanding at any given time. If a thread * allow more than one read to be outstanding at any given time. If a thread
* initiates a read operation before a previous read operation has * initiates a read operation before a previous read operation has
* completed then a {@link ReadPendingException} will be thrown. * completed then a {@link ReadPendingException} will be thrown.
* *
* <p> The <tt>handler</tt> parameter is used to specify a {@link
* CompletionHandler}. When the read operation completes the handler's
* {@link CompletionHandler#completed completed} method is executed.
*
*
* @param dst * @param dst
* The buffer into which bytes are to be transferred * The buffer into which bytes are to be transferred
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The completion handler object; can be {@code null} * The completion handler
*
* @return A Future representing the result of the operation
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If the buffer is read-only * If the buffer is read-only
* @throws ReadPendingException * @throws ReadPendingException
* If the channel does not allow more than one read to be outstanding * If the channel does not allow more than one read to be outstanding
* and a previous read has not completed * and a previous read has not completed
* @throws ShutdownChannelGroupException
* If the channel is associated with a {@link AsynchronousChannelGroup
* group} that has terminated
*/ */
<A> Future<Integer> read(ByteBuffer dst, <A> void read(ByteBuffer dst,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler); CompletionHandler<Integer,? super A> handler);
/** /**
* Reads a sequence of bytes from this channel into the given buffer. * Reads a sequence of bytes from this channel into the given buffer.
* *
* <p> An invocation of this method of the form <tt>c.read(dst)</tt> * <p> This method initiates an asynchronous read operation to read a
* behaves in exactly the same manner as the invocation * sequence of bytes from this channel into the given buffer. The method
* <blockquote><pre> * behaves in exactly the same manner as the {@link
* c.read(dst, null, null);</pre></blockquote> * #read(ByteBuffer,Object,CompletionHandler)
* read(ByteBuffer,Object,CompletionHandler)} method except that instead
* of specifying a completion handler, this method returns a {@code Future}
* representing the pending result. The {@code Future}'s {@link Future#get()
* get} method returns the number of bytes read or {@code -1} if no bytes
* could be read because the channel has reached end-of-stream.
* *
* @param dst * @param dst
* The buffer into which bytes are to be transferred * The buffer into which bytes are to be transferred
...@@ -134,17 +136,17 @@ public interface AsynchronousByteChannel ...@@ -134,17 +136,17 @@ public interface AsynchronousByteChannel
/** /**
* Writes a sequence of bytes to this channel from the given buffer. * Writes a sequence of bytes to this channel from the given buffer.
* *
* <p> This method initiates an operation to write a sequence of bytes to * <p> This method initiates an asynchronous write operation to write a
* this channel from the given buffer. This method returns a {@link * sequence of bytes to this channel from the given buffer. The {@code
* Future} representing the pending result of the operation. The result * handler} parameter is a completion handler that is invoked when the write
* of the operation, obtained by invoking the <tt>Future</tt>'s {@link * operation completes (or fails). The result passed to the completion
* Future#get() get} method, is the number of bytes written, possibly zero. * handler is the number of bytes written.
* *
* <p> This method initiates a write operation to write up to <i>r</i> bytes * <p> The write operation may write up to <i>r</i> bytes to the channel,
* to the channel, where <i>r</i> is the number of bytes remaining in the * where <i>r</i> is the number of bytes remaining in the buffer, that is,
* buffer, that is, {@code src.remaining()} at the moment the write is * {@code src.remaining()} at the time that the write is attempted. Where
* attempted. Where <i>r</i> is 0, the write operation completes immediately * <i>r</i> is 0, the write operation completes immediately with a result of
* with a result of {@code 0} without initiating an I/O operation. * {@code 0} without initiating an I/O operation.
* *
* <p> Suppose that a byte sequence of length <i>n</i> is written, where * <p> Suppose that a byte sequence of length <i>n</i> is written, where
* <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>. * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
...@@ -156,41 +158,43 @@ public interface AsynchronousByteChannel ...@@ -156,41 +158,43 @@ public interface AsynchronousByteChannel
* <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed. * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
* *
* <p> Buffers are not safe for use by multiple concurrent threads so care * <p> Buffers are not safe for use by multiple concurrent threads so care
* should be taken to not to access the buffer until the operaton has completed. * should be taken to not access the buffer until the operation has
* completed.
* *
* <p> This method may be invoked at any time. Some channel types may not * <p> This method may be invoked at any time. Some channel types may not
* allow more than one write to be outstanding at any given time. If a thread * allow more than one write to be outstanding at any given time. If a thread
* initiates a write operation before a previous write operation has * initiates a write operation before a previous write operation has
* completed then a {@link WritePendingException} will be thrown. * completed then a {@link WritePendingException} will be thrown.
* *
* <p> The <tt>handler</tt> parameter is used to specify a {@link
* CompletionHandler}. When the write operation completes the handler's
* {@link CompletionHandler#completed completed} method is executed.
*
* @param src * @param src
* The buffer from which bytes are to be retrieved * The buffer from which bytes are to be retrieved
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The completion handler object; can be {@code null} * The completion handler object
*
* @return A Future representing the result of the operation
* *
* @throws WritePendingException * @throws WritePendingException
* If the channel does not allow more than one write to be outstanding * If the channel does not allow more than one write to be outstanding
* and a previous write has not completed * and a previous write has not completed
* @throws ShutdownChannelGroupException
* If the channel is associated with a {@link AsynchronousChannelGroup
* group} that has terminated
*/ */
<A> Future<Integer> write(ByteBuffer src, <A> void write(ByteBuffer src,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler); CompletionHandler<Integer,? super A> handler);
/** /**
* Writes a sequence of bytes to this channel from the given buffer. * Writes a sequence of bytes to this channel from the given buffer.
* *
* <p> An invocation of this method of the form <tt>c.write(src)</tt> * <p> This method initiates an asynchronous write operation to write a
* behaves in exactly the same manner as the invocation * sequence of bytes to this channel from the given buffer. The method
* <blockquote><pre> * behaves in exactly the same manner as the {@link
* c.write(src, null, null);</pre></blockquote> * #write(ByteBuffer,Object,CompletionHandler)
* write(ByteBuffer,Object,CompletionHandler)} method except that instead
* of specifying a completion handler, this method returns a {@code Future}
* representing the pending result. The {@code Future}'s {@link Future#get()
* get} method returns the number of bytes written.
* *
* @param src * @param src
* The buffer from which bytes are to be retrieved * The buffer from which bytes are to be retrieved
......
...@@ -34,7 +34,8 @@ import java.util.concurrent.Future; // javadoc ...@@ -34,7 +34,8 @@ import java.util.concurrent.Future; // javadoc
* *
* <ol> * <ol>
* <li><pre>{@link Future}&lt;V&gt; <em>operation</em>(<em>...</em>)</pre></li> * <li><pre>{@link Future}&lt;V&gt; <em>operation</em>(<em>...</em>)</pre></li>
* <li><pre>Future&lt;V&gt; <em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}&lt;V,? super A&gt handler)</pre></li> * <li><pre>void <em>operation</em>(<em>...</em> A attachment, {@link
* CompletionHandler}&lt;V,? super A&gt; handler)</pre></li>
* </ol> * </ol>
* *
* where <i>operation</i> is the name of the I/O operation (read or write for * where <i>operation</i> is the name of the I/O operation (read or write for
...@@ -48,7 +49,7 @@ import java.util.concurrent.Future; // javadoc ...@@ -48,7 +49,7 @@ import java.util.concurrent.Future; // javadoc
* interface may be used to check if the operation has completed, wait for its * interface may be used to check if the operation has completed, wait for its
* completion, and to retrieve the result. In the second form, a {@link * completion, and to retrieve the result. In the second form, a {@link
* CompletionHandler} is invoked to consume the result of the I/O operation when * CompletionHandler} is invoked to consume the result of the I/O operation when
* it completes, fails, or is cancelled. * it completes or fails.
* *
* <p> A channel that implements this interface is <em>asynchronously * <p> A channel that implements this interface is <em>asynchronously
* closeable</em>: If an I/O operation is outstanding on the channel and the * closeable</em>: If an I/O operation is outstanding on the channel and the
...@@ -63,33 +64,33 @@ import java.util.concurrent.Future; // javadoc ...@@ -63,33 +64,33 @@ import java.util.concurrent.Future; // javadoc
* <h4>Cancellation</h4> * <h4>Cancellation</h4>
* *
* <p> The {@code Future} interface defines the {@link Future#cancel cancel} * <p> The {@code Future} interface defines the {@link Future#cancel cancel}
* method to cancel execution of a task. * method to cancel execution. This causes all threads waiting on the result of
* * the I/O operation to throw {@link java.util.concurrent.CancellationException}.
* <p> Where the {@code cancel} method is invoked with the {@code * Whether the underlying I/O operation can be cancelled is highly implementation
* specific and therefore not specified. Where cancellation leaves the channel,
* or the entity to which it is connected, in an inconsistent state, then the
* channel is put into an implementation specific <em>error state</em> that
* prevents further attempts to initiate I/O operations that are <i>similar</i>
* to the operation that was cancelled. For example, if a read operation is
* cancelled but the implementation cannot guarantee that bytes have not been
* read from the channel then it puts the channel into an error state; further
* attempts to initiate a {@code read} operation cause an unspecified runtime
* exception to be thrown. Similarly, if a write operation is cancelled but the
* implementation cannot guarantee that bytes have not been written to the
* channel then subsequent attempts to initiate a {@code write} will fail with
* an unspecified runtime exception.
*
* <p> Where the {@link Future#cancel cancel} method is invoked with the {@code
* mayInterruptIfRunning} parameter set to {@code true} then the I/O operation * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation
* may be interrupted by closing the channel. This will cause any other I/O * may be interrupted by closing the channel. In that case all threads waiting
* operations outstanding on the channel to complete with the exception {@link * on the result of the I/O operation throw {@code CancellationException} and
* AsynchronousCloseException}. * any other I/O operations outstanding on the channel complete with the
* * exception {@link AsynchronousCloseException}.
* <p> If a {@code CompletionHandler} is specified when initiating an I/O
* operation, and the {@code cancel} method is invoked to cancel the I/O
* operation before it completes, then the {@code CompletionHandler}'s {@link
* CompletionHandler#cancelled cancelled} method is invoked.
*
* <p> If an implementation of this interface supports a means to cancel I/O
* operations, and where cancellation may leave the channel, or the entity to
* which it is connected, in an inconsistent state, then the channel is put into
* an implementation specific <em>error state</em> that prevents further
* attempts to initiate I/O operations on the channel. For example, if a read
* operation is cancelled but the implementation cannot guarantee that bytes
* have not been read from the channel then it puts the channel into error state
* state; further attempts to initiate a {@code read} operation causes an
* unspecified runtime exception to be thrown.
* *
* <p> Where the {@code cancel} method is invoked to cancel read or write * <p> Where the {@code cancel} method is invoked to cancel read or write
* operations then it recommended that all buffers used in the I/O operations be * operations then it is recommended that all buffers used in the I/O operations
* discarded or care taken to ensure that the buffers are not accessed while the * be discarded or care taken to ensure that the buffers are not accessed while
* channel remains open. * the channel remains open.
* *
* @since 1.7 * @since 1.7
*/ */
...@@ -102,7 +103,7 @@ public interface AsynchronousChannel ...@@ -102,7 +103,7 @@ public interface AsynchronousChannel
* *
* <p> Any outstanding asynchronous operations upon this channel will * <p> Any outstanding asynchronous operations upon this channel will
* complete with the exception {@link AsynchronousCloseException}. After a * complete with the exception {@link AsynchronousCloseException}. After a
* channel is closed then further attempts to initiate asynchronous I/O * channel is closed, further attempts to initiate asynchronous I/O
* operations complete immediately with cause {@link ClosedChannelException}. * operations complete immediately with cause {@link ClosedChannelException}.
* *
* <p> This method otherwise behaves exactly as specified by the {@link * <p> This method otherwise behaves exactly as specified by the {@link
......
...@@ -85,9 +85,6 @@ import java.io.IOException; ...@@ -85,9 +85,6 @@ import java.io.IOException;
* public void failed(Throwable exc, Void att) { * public void failed(Throwable exc, Void att) {
* ... * ...
* } * }
* public void cancelled(Void att) {
* ...
* }
* }); * });
* </pre> * </pre>
* *
...@@ -240,11 +237,11 @@ public abstract class AsynchronousServerSocketChannel ...@@ -240,11 +237,11 @@ public abstract class AsynchronousServerSocketChannel
/** /**
* Accepts a connection. * Accepts a connection.
* *
* <p> This method initiates accepting a connection made to this channel's * <p> This method initiates an asynchronous operation to accept a
* socket, returning a {@link Future} representing the pending result * connection made to this channel's socket. The {@code handler} parameter is
* of the operation. The {@code Future}'s {@link Future#get() get} * a completion handler that is invoked when a connection is accepted (or
* method will return the {@link AsynchronousSocketChannel} for the new * the operation fails). The result passed to the completion handler is
* connection on successful completion. * the {@link AsynchronousSocketChannel} to the new connection.
* *
* <p> When a new connection is accepted then the resulting {@code * <p> When a new connection is accepted then the resulting {@code
* AsynchronousSocketChannel} will be bound to the same {@link * AsynchronousSocketChannel} will be bound to the same {@link
...@@ -269,35 +266,35 @@ public abstract class AsynchronousServerSocketChannel ...@@ -269,35 +266,35 @@ public abstract class AsynchronousServerSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return an <tt>Future</tt> object representing the pending result
* *
* @throws AcceptPendingException * @throws AcceptPendingException
* If an accept operation is already in progress on this channel * If an accept operation is already in progress on this channel
* @throws NotYetBoundException * @throws NotYetBoundException
* If this channel's socket has not yet been bound * If this channel's socket has not yet been bound
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
public abstract <A> Future<AsynchronousSocketChannel> public abstract <A> void accept(A attachment,
accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler); CompletionHandler<AsynchronousSocketChannel,? super A> handler);
/** /**
* Accepts a connection. * Accepts a connection.
* *
* <p> This method is equivalent to invoking {@link * <p> This method initiates an asynchronous operation to accept a
* #accept(Object,CompletionHandler)} with the {@code attachment} * connection made to this channel's socket. The method behaves in exactly
* and {@code handler} parameters set to {@code null}. * the same manner as the {@link #accept(Object, CompletionHandler)} method
* except that instead of specifying a completion handler, this method
* returns a {@code Future} representing the pending result. The {@code
* Future}'s {@link Future#get() get} method returns the {@link
* AsynchronousSocketChannel} to the new connection on successful completion.
* *
* @return an <tt>Future</tt> object representing the pending result * @return a {@code Future} object representing the pending result
* *
* @throws AcceptPendingException * @throws AcceptPendingException
* If an accept operation is already in progress on this channel * If an accept operation is already in progress on this channel
* @throws NotYetBoundException * @throws NotYetBoundException
* If this channel's socket has not yet been bound * If this channel's socket has not yet been bound
*/ */
public final Future<AsynchronousSocketChannel> accept() { public abstract Future<AsynchronousSocketChannel> accept();
return accept(null, null);
}
} }
...@@ -274,14 +274,11 @@ public abstract class AsynchronousSocketChannel ...@@ -274,14 +274,11 @@ public abstract class AsynchronousSocketChannel
/** /**
* Connects this channel. * Connects this channel.
* *
* <p> This method initiates an operation to connect this channel, returning * <p> This method initiates an operation to connect this channel. The
* a {@code Future} representing the pending result of the operation. If * {@code handler} parameter is a completion handler that is invoked when
* the connection is successfully established then the {@code Future}'s * the connection is successfully established or connection cannot be
* {@link Future#get() get} method will return {@code null}. If the * established. If the connection cannot be established then the channel is
* connection cannot be established then the channel is closed. In that case, * closed.
* invoking the {@code get} method throws {@link
* java.util.concurrent.ExecutionException} with an {@code IOException} as
* the cause.
* *
* <p> This method performs exactly the same security checks as the {@link * <p> This method performs exactly the same security checks as the {@link
* java.net.Socket} class. That is, if a security manager has been * java.net.Socket} class. That is, if a security manager has been
...@@ -294,9 +291,7 @@ public abstract class AsynchronousSocketChannel ...@@ -294,9 +291,7 @@ public abstract class AsynchronousSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return A {@code Future} object representing the pending result
* *
* @throws UnresolvedAddressException * @throws UnresolvedAddressException
* If the given remote address is not fully resolved * If the given remote address is not fully resolved
...@@ -307,23 +302,26 @@ public abstract class AsynchronousSocketChannel ...@@ -307,23 +302,26 @@ public abstract class AsynchronousSocketChannel
* @throws ConnectionPendingException * @throws ConnectionPendingException
* If a connection operation is already in progress on this channel * If a connection operation is already in progress on this channel
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
* @throws SecurityException * @throws SecurityException
* If a security manager has been installed * If a security manager has been installed
* and it does not permit access to the given remote endpoint * and it does not permit access to the given remote endpoint
* *
* @see #getRemoteAddress * @see #getRemoteAddress
*/ */
public abstract <A> Future<Void> connect(SocketAddress remote, public abstract <A> void connect(SocketAddress remote,
A attachment, A attachment,
CompletionHandler<Void,? super A> handler); CompletionHandler<Void,? super A> handler);
/** /**
* Connects this channel. * Connects this channel.
* *
* <p> This method is equivalent to invoking {@link * <p> This method initiates an operation to connect this channel. This
* #connect(SocketAddress,Object,CompletionHandler)} with the {@code attachment} * method behaves in exactly the same manner as the {@link
* and handler parameters set to {@code null}. * #connect(SocketAddress, Object, CompletionHandler)} method except that
* instead of specifying a completion handler, this method returns a {@code
* Future} representing the pending result. The {@code Future}'s {@link
* Future#get() get} method returns {@code null} on successful completion.
* *
* @param remote * @param remote
* The remote address to which this channel is to be connected * The remote address to which this channel is to be connected
...@@ -342,18 +340,17 @@ public abstract class AsynchronousSocketChannel ...@@ -342,18 +340,17 @@ public abstract class AsynchronousSocketChannel
* If a security manager has been installed * If a security manager has been installed
* and it does not permit access to the given remote endpoint * and it does not permit access to the given remote endpoint
*/ */
public final Future<Void> connect(SocketAddress remote) { public abstract Future<Void> connect(SocketAddress remote);
return connect(remote, null, null);
}
/** /**
* Reads a sequence of bytes from this channel into the given buffer. * Reads a sequence of bytes from this channel into the given buffer.
* *
* <p> This method initiates the reading of a sequence of bytes from this * <p> This method initiates an asynchronous read operation to read a
* channel into the given buffer, returning a {@code Future} representing * sequence of bytes from this channel into the given buffer. The {@code
* the pending result of the operation. The {@code Future}'s {@link * handler} parameter is a completion handler that is invoked when the read
* Future#get() get} method returns the number of bytes read or {@code -1} * operation completes (or fails). The result passed to the completion
* if all bytes have been read and channel has reached end-of-stream. * handler is the number of bytes read or {@code -1} if no bytes could be
* read because the channel has reached end-of-stream.
* *
* <p> If a timeout is specified and the timeout elapses before the operation * <p> If a timeout is specified and the timeout elapses before the operation
* completes then the operation completes with the exception {@link * completes then the operation completes with the exception {@link
...@@ -376,9 +373,7 @@ public abstract class AsynchronousSocketChannel ...@@ -376,9 +373,7 @@ public abstract class AsynchronousSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return A {@code Future} object representing the pending result
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If the {@code timeout} parameter is negative or the buffer is * If the {@code timeout} parameter is negative or the buffer is
...@@ -388,9 +383,9 @@ public abstract class AsynchronousSocketChannel ...@@ -388,9 +383,9 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
public abstract <A> Future<Integer> read(ByteBuffer dst, public abstract <A> void read(ByteBuffer dst,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
...@@ -402,14 +397,14 @@ public abstract class AsynchronousSocketChannel ...@@ -402,14 +397,14 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
@Override @Override
public final <A> Future<Integer> read(ByteBuffer dst, public final <A> void read(ByteBuffer dst,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
} }
/** /**
...@@ -419,16 +414,18 @@ public abstract class AsynchronousSocketChannel ...@@ -419,16 +414,18 @@ public abstract class AsynchronousSocketChannel
* If this channel is not yet connected * If this channel is not yet connected
*/ */
@Override @Override
public final Future<Integer> read(ByteBuffer dst) { public abstract Future<Integer> read(ByteBuffer dst);
return read(dst, 0L, TimeUnit.MILLISECONDS, null, null);
}
/** /**
* Reads a sequence of bytes from this channel into a subsequence of the * Reads a sequence of bytes from this channel into a subsequence of the
* given buffers. This operation, sometimes called a <em>scattering read</em>, * given buffers. This operation, sometimes called a <em>scattering read</em>,
* is often useful when implementing network protocols that group data into * is often useful when implementing network protocols that group data into
* segments consisting of one or more fixed-length headers followed by a * segments consisting of one or more fixed-length headers followed by a
* variable-length body. * variable-length body. The {@code handler} parameter is a completion
* handler that is invoked when the read operation completes (or fails). The
* result passed to the completion handler is the number of bytes read or
* {@code -1} if no bytes could be read because the channel has reached
* end-of-stream.
* *
* <p> This method initiates a read of up to <i>r</i> bytes from this channel, * <p> This method initiates a read of up to <i>r</i> bytes from this channel,
* where <i>r</i> is the total number of bytes remaining in the specified * where <i>r</i> is the total number of bytes remaining in the specified
...@@ -456,11 +453,6 @@ public abstract class AsynchronousSocketChannel ...@@ -456,11 +453,6 @@ public abstract class AsynchronousSocketChannel
* I/O operation is performed with the maximum number of buffers allowed by * I/O operation is performed with the maximum number of buffers allowed by
* the operating system. * the operating system.
* *
* <p> The return value from this method is a {@code Future} representing
* the pending result of the operation. The {@code Future}'s {@link
* Future#get() get} method returns the number of bytes read or {@code -1L}
* if all bytes have been read and the channel has reached end-of-stream.
*
* <p> If a timeout is specified and the timeout elapses before the operation * <p> If a timeout is specified and the timeout elapses before the operation
* completes then it completes with the exception {@link * completes then it completes with the exception {@link
* InterruptedByTimeoutException}. Where a timeout occurs, and the * InterruptedByTimeoutException}. Where a timeout occurs, and the
...@@ -485,9 +477,7 @@ public abstract class AsynchronousSocketChannel ...@@ -485,9 +477,7 @@ public abstract class AsynchronousSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return A {@code Future} object representing the pending result
* *
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException
* If the pre-conditions for the {@code offset} and {@code length} * If the pre-conditions for the {@code offset} and {@code length}
...@@ -500,9 +490,9 @@ public abstract class AsynchronousSocketChannel ...@@ -500,9 +490,9 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
public abstract <A> Future<Long> read(ByteBuffer[] dsts, public abstract <A> void read(ByteBuffer[] dsts,
int offset, int offset,
int length, int length,
long timeout, long timeout,
...@@ -513,10 +503,11 @@ public abstract class AsynchronousSocketChannel ...@@ -513,10 +503,11 @@ public abstract class AsynchronousSocketChannel
/** /**
* Writes a sequence of bytes to this channel from the given buffer. * Writes a sequence of bytes to this channel from the given buffer.
* *
* <p> This method initiates the writing of a sequence of bytes to this channel * <p> This method initiates an asynchronous write operation to write a
* from the given buffer, returning a {@code Future} representing the * sequence of bytes to this channel from the given buffer. The {@code
* pending result of the operation. The {@code Future}'s {@link Future#get() * handler} parameter is a completion handler that is invoked when the write
* get} method will return the number of bytes written. * operation completes (or fails). The result passed to the completion
* handler is the number of bytes written.
* *
* <p> If a timeout is specified and the timeout elapses before the operation * <p> If a timeout is specified and the timeout elapses before the operation
* completes then it completes with the exception {@link * completes then it completes with the exception {@link
...@@ -539,9 +530,7 @@ public abstract class AsynchronousSocketChannel ...@@ -539,9 +530,7 @@ public abstract class AsynchronousSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return A {@code Future} object representing the pending result
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If the {@code timeout} parameter is negative * If the {@code timeout} parameter is negative
...@@ -550,9 +539,9 @@ public abstract class AsynchronousSocketChannel ...@@ -550,9 +539,9 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
public abstract <A> Future<Integer> write(ByteBuffer src, public abstract <A> void write(ByteBuffer src,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
...@@ -563,15 +552,15 @@ public abstract class AsynchronousSocketChannel ...@@ -563,15 +552,15 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
@Override @Override
public final <A> Future<Integer> write(ByteBuffer src, public final <A> void write(ByteBuffer src,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
} }
/** /**
...@@ -580,16 +569,16 @@ public abstract class AsynchronousSocketChannel ...@@ -580,16 +569,16 @@ public abstract class AsynchronousSocketChannel
* If this channel is not yet connected * If this channel is not yet connected
*/ */
@Override @Override
public final Future<Integer> write(ByteBuffer src) { public abstract Future<Integer> write(ByteBuffer src);
return write(src, 0L, TimeUnit.MILLISECONDS, null, null);
}
/** /**
* Writes a sequence of bytes to this channel from a subsequence of the given * Writes a sequence of bytes to this channel from a subsequence of the given
* buffers. This operation, sometimes called a <em>gathering write</em>, is * buffers. This operation, sometimes called a <em>gathering write</em>, is
* often useful when implementing network protocols that group data into * often useful when implementing network protocols that group data into
* segments consisting of one or more fixed-length headers followed by a * segments consisting of one or more fixed-length headers followed by a
* variable-length body. * variable-length body. The {@code handler} parameter is a completion
* handler that is invoked when the write operation completes (or fails).
* The result passed to the completion handler is the number of bytes written.
* *
* <p> This method initiates a write of up to <i>r</i> bytes to this channel, * <p> This method initiates a write of up to <i>r</i> bytes to this channel,
* where <i>r</i> is the total number of bytes remaining in the specified * where <i>r</i> is the total number of bytes remaining in the specified
...@@ -616,10 +605,6 @@ public abstract class AsynchronousSocketChannel ...@@ -616,10 +605,6 @@ public abstract class AsynchronousSocketChannel
* remaining), exceeds this limit, then the I/O operation is performed with * remaining), exceeds this limit, then the I/O operation is performed with
* the maximum number of buffers allowed by the operating system. * the maximum number of buffers allowed by the operating system.
* *
* <p> The return value from this method is a {@code Future} representing
* the pending result of the operation. The {@code Future}'s {@link
* Future#get() get} method will return the number of bytes written.
*
* <p> If a timeout is specified and the timeout elapses before the operation * <p> If a timeout is specified and the timeout elapses before the operation
* completes then it completes with the exception {@link * completes then it completes with the exception {@link
* InterruptedByTimeoutException}. Where a timeout occurs, and the * InterruptedByTimeoutException}. Where a timeout occurs, and the
...@@ -644,9 +629,7 @@ public abstract class AsynchronousSocketChannel ...@@ -644,9 +629,7 @@ public abstract class AsynchronousSocketChannel
* @param attachment * @param attachment
* The object to attach to the I/O operation; can be {@code null} * The object to attach to the I/O operation; can be {@code null}
* @param handler * @param handler
* The handler for consuming the result; can be {@code null} * The handler for consuming the result
*
* @return A {@code Future} object representing the pending result
* *
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException
* If the pre-conditions for the {@code offset} and {@code length} * If the pre-conditions for the {@code offset} and {@code length}
...@@ -658,9 +641,9 @@ public abstract class AsynchronousSocketChannel ...@@ -658,9 +641,9 @@ public abstract class AsynchronousSocketChannel
* @throws NotYetConnectedException * @throws NotYetConnectedException
* If this channel is not yet connected * If this channel is not yet connected
* @throws ShutdownChannelGroupException * @throws ShutdownChannelGroupException
* If a handler is specified, and the channel group is shutdown * If the channel group has terminated
*/ */
public abstract <A> Future<Long> write(ByteBuffer[] srcs, public abstract <A> void write(ByteBuffer[] srcs,
int offset, int offset,
int length, int length,
long timeout, long timeout,
......
...@@ -182,7 +182,6 @@ public final class Channels { ...@@ -182,7 +182,6 @@ public final class Channels {
} }
/** /**
* {@note new}
* Constructs a stream that reads bytes from the given channel. * Constructs a stream that reads bytes from the given channel.
* *
* <p> The stream will not be buffered, and it will not support the {@link * <p> The stream will not be buffered, and it will not support the {@link
...@@ -258,7 +257,6 @@ public final class Channels { ...@@ -258,7 +257,6 @@ public final class Channels {
} }
/** /**
* {@note new}
* Constructs a stream that writes bytes to the given channel. * Constructs a stream that writes bytes to the given channel.
* *
* <p> The stream will not be buffered. The stream will be safe for access * <p> The stream will not be buffered. The stream will be safe for access
......
...@@ -32,11 +32,9 @@ package java.nio.channels; ...@@ -32,11 +32,9 @@ package java.nio.channels;
* handler to be specified to consume the result of an asynchronous operation. * handler to be specified to consume the result of an asynchronous operation.
* The {@link #completed completed} method is invoked when the I/O operation * The {@link #completed completed} method is invoked when the I/O operation
* completes successfully. The {@link #failed failed} method is invoked if the * completes successfully. The {@link #failed failed} method is invoked if the
* I/O operations fails. The {@link #cancelled cancelled} method is invoked when * I/O operations fails. The implementations of these methods should complete
* the I/O operation is cancelled by invoking the {@link * in a timely manner so as to avoid keeping the invoking thread from dispatching
* java.util.concurrent.Future#cancel cancel} method. The implementations of * to other completion handlers.
* these methods should complete in a timely manner so as to avoid keeping the
* invoking thread from dispatching to other completion handlers.
* *
* @param <V> The result type of the I/O operation * @param <V> The result type of the I/O operation
* @param <A> The type of the object attached to the I/O operation * @param <A> The type of the object attached to the I/O operation
...@@ -65,13 +63,4 @@ public interface CompletionHandler<V,A> { ...@@ -65,13 +63,4 @@ public interface CompletionHandler<V,A> {
* The object attached to the I/O operation when it was initiated. * The object attached to the I/O operation when it was initiated.
*/ */
void failed(Throwable exc, A attachment); void failed(Throwable exc, A attachment);
/**
* Invoked when an operation is cancelled by invoking the {@link
* java.util.concurrent.Future#cancel cancel} method.
*
* @param attachment
* The object attached to the I/O operation when it was initiated.
*/
void cancelled(A attachment);
} }
...@@ -39,8 +39,7 @@ import java.util.Collections; ...@@ -39,8 +39,7 @@ import java.util.Collections;
/** /**
* A channel for reading, writing, mapping, and manipulating a file. * A channel for reading, writing, mapping, and manipulating a file.
* *
* <p> {@note revised} * <p> A file channel is a {@link SeekableByteChannel} that is connected to
* A file channel is a {@link SeekableByteChannel} that is connected to
* a file. It has a current <i>position</i> within its file which can * a file. It has a current <i>position</i> within its file which can
* be both {@link #position() <i>queried</i>} and {@link #position(long) * be both {@link #position() <i>queried</i>} and {@link #position(long)
* <i>modified</i>}. The file itself contains a variable-length sequence * <i>modified</i>}. The file itself contains a variable-length sequence
...@@ -151,7 +150,6 @@ import java.util.Collections; ...@@ -151,7 +150,6 @@ import java.util.Collections;
* @author Mike McCloskey * @author Mike McCloskey
* @author JSR-51 Expert Group * @author JSR-51 Expert Group
* @since 1.4 * @since 1.4
* @updated 1.7
*/ */
public abstract class FileChannel public abstract class FileChannel
...@@ -164,7 +162,6 @@ public abstract class FileChannel ...@@ -164,7 +162,6 @@ public abstract class FileChannel
protected FileChannel() { } protected FileChannel() { }
/** /**
* {@note new}
* Opens or creates a file, returning a file channel to access the file. * Opens or creates a file, returning a file channel to access the file.
* *
* <p> The {@code options} parameter determines how the file is opened. * <p> The {@code options} parameter determines how the file is opened.
...@@ -293,7 +290,6 @@ public abstract class FileChannel ...@@ -293,7 +290,6 @@ public abstract class FileChannel
private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0]; private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
/** /**
* {@note new}
* Opens or creates a file, returning a file channel to access the file. * Opens or creates a file, returning a file channel to access the file.
* *
* <p> An invocation of this method behaves in exactly the same way as the * <p> An invocation of this method behaves in exactly the same way as the
......
...@@ -114,7 +114,6 @@ import java.io.IOException; ...@@ -114,7 +114,6 @@ import java.io.IOException;
* @author Mark Reinhold * @author Mark Reinhold
* @author JSR-51 Expert Group * @author JSR-51 Expert Group
* @since 1.4 * @since 1.4
* @updated 1.7
*/ */
public abstract class FileLock { public abstract class FileLock {
...@@ -161,7 +160,7 @@ public abstract class FileLock { ...@@ -161,7 +160,7 @@ public abstract class FileLock {
} }
/** /**
* {@note new} Initializes a new instance of this class. * Initializes a new instance of this class.
* *
* @param channel * @param channel
* The channel upon whose file this lock is held * The channel upon whose file this lock is held
...@@ -199,7 +198,6 @@ public abstract class FileLock { ...@@ -199,7 +198,6 @@ public abstract class FileLock {
} }
/** /**
* {@note revised}
* Returns the file channel upon whose file this lock was acquired. * Returns the file channel upon whose file this lock was acquired.
* *
* <p> This method has been superseded by the {@link #acquiredBy acquiredBy} * <p> This method has been superseded by the {@link #acquiredBy acquiredBy}
...@@ -213,7 +211,6 @@ public abstract class FileLock { ...@@ -213,7 +211,6 @@ public abstract class FileLock {
} }
/** /**
* {@note new}
* Returns the channel upon whose file this lock was acquired. * Returns the channel upon whose file this lock was acquired.
* *
* @return The channel upon whose file this lock was acquired. * @return The channel upon whose file this lock was acquired.
......
...@@ -190,5 +190,5 @@ gen WritePendingException " ...@@ -190,5 +190,5 @@ gen WritePendingException "
gen ShutdownChannelGroupException " gen ShutdownChannelGroupException "
* Unchecked exception thrown when an attempt is made to construct a channel in * Unchecked exception thrown when an attempt is made to construct a channel in
* a group that is shutdown or the completion handler for an I/O operation * a group that is shutdown or the completion handler for an I/O operation
* cannot be invoked because the channel group is shutdown." \ * cannot be invoked because the channel group has terminated." \
-3903801676350154157L -3903801676350154157L
...@@ -285,7 +285,6 @@ ...@@ -285,7 +285,6 @@
* java.lang.NullPointerException NullPointerException} to be thrown. * java.lang.NullPointerException NullPointerException} to be thrown.
* *
* @since 1.4 * @since 1.4
* @updated 1.7
* @author Mark Reinhold * @author Mark Reinhold
* @author JSR-51 Expert Group * @author JSR-51 Expert Group
*/ */
......
...@@ -39,8 +39,6 @@ import java.io.IOException; ...@@ -39,8 +39,6 @@ import java.io.IOException;
* metadata or file attributes. * metadata or file attributes.
* *
* @since 1.7 * @since 1.7
* @see java.io.Inputs
* @see java.io.Outputs
* @see java.nio.file.attribute.Attributes * @see java.nio.file.attribute.Attributes
* @see java.io.File#toPath * @see java.io.File#toPath
*/ */
......
...@@ -674,7 +674,6 @@ public final class Scanner implements Iterator<String> { ...@@ -674,7 +674,6 @@ public final class Scanner implements Iterator<String> {
} }
/** /**
* {@note new}
* Constructs a new <code>Scanner</code> that produces values scanned * Constructs a new <code>Scanner</code> that produces values scanned
* from the specified file. Bytes from the file are converted into * from the specified file. Bytes from the file are converted into
* characters using the underlying platform's * characters using the underlying platform's
...@@ -694,7 +693,6 @@ public final class Scanner implements Iterator<String> { ...@@ -694,7 +693,6 @@ public final class Scanner implements Iterator<String> {
} }
/** /**
* {@note new}
* Constructs a new <code>Scanner</code> that produces values scanned * Constructs a new <code>Scanner</code> that produces values scanned
* from the specified file. Bytes from the file are converted into * from the specified file. Bytes from the file are converted into
* characters using the specified charset. * characters using the specified charset.
......
...@@ -32,8 +32,8 @@ import java.io.IOException; ...@@ -32,8 +32,8 @@ import java.io.IOException;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.AccessController; import java.security.AccessController;
import java.security.AccessControlContext; import java.security.AccessControlContext;
...@@ -65,11 +65,8 @@ abstract class AsynchronousChannelGroupImpl ...@@ -65,11 +65,8 @@ abstract class AsynchronousChannelGroupImpl
private final Queue<Runnable> taskQueue; private final Queue<Runnable> taskQueue;
// group shutdown // group shutdown
// shutdownLock is RW lock so as to allow for concurrent queuing of tasks private final AtomicBoolean shutdown = new AtomicBoolean();
// when using a fixed thread pool.
private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock();
private final Object shutdownNowLock = new Object(); private final Object shutdownNowLock = new Object();
private volatile boolean shutdown;
private volatile boolean terminateInitiated; private volatile boolean terminateInitiated;
AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider, AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider,
...@@ -214,7 +211,7 @@ abstract class AsynchronousChannelGroupImpl ...@@ -214,7 +211,7 @@ abstract class AsynchronousChannelGroupImpl
@Override @Override
public final boolean isShutdown() { public final boolean isShutdown() {
return shutdown; return shutdown.get();
} }
@Override @Override
...@@ -260,17 +257,10 @@ abstract class AsynchronousChannelGroupImpl ...@@ -260,17 +257,10 @@ abstract class AsynchronousChannelGroupImpl
@Override @Override
public final void shutdown() { public final void shutdown() {
shutdownLock.writeLock().lock(); if (shutdown.getAndSet(true)) {
try {
if (shutdown) {
// already shutdown // already shutdown
return; return;
} }
shutdown = true;
} finally {
shutdownLock.writeLock().unlock();
}
// if there are channels in the group then shutdown will continue // if there are channels in the group then shutdown will continue
// when the last channel is closed // when the last channel is closed
if (!isEmpty()) { if (!isEmpty()) {
...@@ -289,12 +279,7 @@ abstract class AsynchronousChannelGroupImpl ...@@ -289,12 +279,7 @@ abstract class AsynchronousChannelGroupImpl
@Override @Override
public final void shutdownNow() throws IOException { public final void shutdownNow() throws IOException {
shutdownLock.writeLock().lock(); shutdown.set(true);
try {
shutdown = true;
} finally {
shutdownLock.writeLock().unlock();
}
synchronized (shutdownNowLock) { synchronized (shutdownNowLock) {
if (!terminateInitiated) { if (!terminateInitiated) {
terminateInitiated = true; terminateInitiated = true;
...@@ -305,6 +290,18 @@ abstract class AsynchronousChannelGroupImpl ...@@ -305,6 +290,18 @@ abstract class AsynchronousChannelGroupImpl
} }
} }
/**
* For use by AsynchronousFileChannel to release resources without shutting
* down the thread pool.
*/
final void detachFromThreadPool() {
if (shutdown.getAndSet(true))
throw new AssertionError("Already shutdown");
if (!isEmpty())
throw new AssertionError("Group not empty");
shutdownHandlerTasks();
}
@Override @Override
public final boolean awaitTermination(long timeout, TimeUnit unit) public final boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException throws InterruptedException
......
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
package sun.nio.ch; package sun.nio.ch;
import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.locks.*; import java.util.concurrent.locks.*;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
...@@ -101,6 +103,33 @@ abstract class AsynchronousFileChannelImpl ...@@ -101,6 +103,33 @@ abstract class AsynchronousFileChannelImpl
// -- file locking -- // -- file locking --
abstract <A> Future<FileLock> implLock(long position,
long size,
boolean shared,
A attachment,
CompletionHandler<FileLock,? super A> handler);
@Override
public final Future<FileLock> lock(long position,
long size,
boolean shared)
{
return implLock(position, size, shared, null, null);
}
@Override
public final <A> void lock(long position,
long size,
boolean shared,
A attachment,
CompletionHandler<FileLock,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implLock(position, size, shared, attachment, handler);
}
private volatile FileLockTable fileLockTable; private volatile FileLockTable fileLockTable;
final void ensureFileLockTableInitialized() throws IOException { final void ensureFileLockTableInitialized() throws IOException {
...@@ -175,4 +204,50 @@ abstract class AsynchronousFileChannelImpl ...@@ -175,4 +204,50 @@ abstract class AsynchronousFileChannelImpl
end(); end();
} }
} }
// -- reading and writing --
abstract <A> Future<Integer> implRead(ByteBuffer dst,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler);
@Override
public final Future<Integer> read(ByteBuffer dst, long position) {
return implRead(dst, position, null, null);
}
@Override
public final <A> void read(ByteBuffer dst,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implRead(dst, position, attachment, handler);
}
abstract <A> Future<Integer> implWrite(ByteBuffer src,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler);
@Override
public final Future<Integer> write(ByteBuffer src, long position) {
return implWrite(src, position, null, null);
}
@Override
public final <A> void write(ByteBuffer src,
long position,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implWrite(src, position, attachment, handler);
}
} }
...@@ -35,6 +35,7 @@ import java.io.IOException; ...@@ -35,6 +35,7 @@ import java.io.IOException;
import java.util.Set; import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import sun.net.NetHooks; import sun.net.NetHooks;
...@@ -108,6 +109,29 @@ abstract class AsynchronousServerSocketChannelImpl ...@@ -108,6 +109,29 @@ abstract class AsynchronousServerSocketChannelImpl
implClose(); implClose();
} }
/**
* Invoked by accept to accept connection
*/
abstract Future<AsynchronousSocketChannel>
implAccept(Object attachment,
CompletionHandler<AsynchronousSocketChannel,Object> handler);
@Override
public final Future<AsynchronousSocketChannel> accept() {
return implAccept(null, null);
}
@Override
@SuppressWarnings("unchecked")
public final <A> void accept(A attachment,
CompletionHandler<AsynchronousSocketChannel,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler);
}
final boolean isAcceptKilled() { final boolean isAcceptKilled() {
return acceptKilled; return acceptKilled;
} }
......
...@@ -183,29 +183,54 @@ abstract class AsynchronousSocketChannelImpl ...@@ -183,29 +183,54 @@ abstract class AsynchronousSocketChannelImpl
killWriting(); killWriting();
} }
/**
* Invoked by connect to initiate the connect operation.
*/
abstract <A> Future<Void> implConnect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler);
@Override
public final Future<Void> connect(SocketAddress remote) {
return implConnect(remote, null, null);
}
@Override
public final <A> void connect(SocketAddress remote,
A attachment,
CompletionHandler<Void,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implConnect(remote, attachment, handler);
}
/** /**
* Invoked by read to initiate the I/O operation. * Invoked by read to initiate the I/O operation.
*/ */
abstract <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts, abstract <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
boolean isScatteringRead, ByteBuffer dst,
ByteBuffer[] dsts,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
CompletionHandler<V,? super A> handler); CompletionHandler<V,? super A> handler);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <V extends Number,A> Future<V> read(ByteBuffer[] dsts, private <V extends Number,A> Future<V> read(boolean isScatteringRead,
boolean isScatteringRead, ByteBuffer dst,
ByteBuffer[] dsts,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A att,
CompletionHandler<V,? super A> handler) CompletionHandler<V,? super A> handler)
{ {
if (!isOpen()) { if (!isOpen()) {
CompletedFuture<V,A> result = CompletedFuture Throwable e = new ClosedChannelException();
.withFailure(this, new ClosedChannelException(), attachment); if (handler == null)
Invoker.invoke(handler, result); return CompletedFuture.withFailure(e);
return result; Invoker.invoke(this, handler, att, null, e);
return null;
} }
if (remoteAddress == null) if (remoteAddress == null)
...@@ -213,13 +238,13 @@ abstract class AsynchronousSocketChannelImpl ...@@ -213,13 +238,13 @@ abstract class AsynchronousSocketChannelImpl
if (timeout < 0L) if (timeout < 0L)
throw new IllegalArgumentException("Negative timeout"); throw new IllegalArgumentException("Negative timeout");
boolean hasSpaceToRead = isScatteringRead || dsts[0].hasRemaining(); boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
boolean shutdown = false; boolean shutdown = false;
// check and update state // check and update state
synchronized (readLock) { synchronized (readLock) {
if (readKilled) if (readKilled)
throw new RuntimeException("Reading not allowed due to timeout or cancellation"); throw new IllegalStateException("Reading not allowed due to timeout or cancellation");
if (reading) if (reading)
throw new ReadPendingException(); throw new ReadPendingException();
if (readShutdown) { if (readShutdown) {
...@@ -234,37 +259,44 @@ abstract class AsynchronousSocketChannelImpl ...@@ -234,37 +259,44 @@ abstract class AsynchronousSocketChannelImpl
// immediately complete with -1 if shutdown for read // immediately complete with -1 if shutdown for read
// immediately complete with 0 if no space remaining // immediately complete with 0 if no space remaining
if (shutdown || !hasSpaceToRead) { if (shutdown || !hasSpaceToRead) {
CompletedFuture<V,A> result; Number result;
if (isScatteringRead) { if (isScatteringRead) {
Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment);
} else { } else {
int value = (shutdown) ? -1 : 0; result = (shutdown) ? -1 : 0;
result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment); }
if (handler == null)
return CompletedFuture.withResult((V)result);
Invoker.invoke(this, handler, att, (V)result, null);
return null;
} }
Invoker.invoke(handler, result);
return result; return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler);
} }
return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler); @Override
public final Future<Integer> read(ByteBuffer dst) {
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null);
} }
@Override @Override
public final <A> Future<Integer> read(ByteBuffer dst, public final <A> void read(ByteBuffer dst,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
if (handler == null)
throw new NullPointerException("'handler' is null");
if (dst.isReadOnly()) if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer"); throw new IllegalArgumentException("Read-only buffer");
ByteBuffer[] bufs = new ByteBuffer[1]; read(false, dst, null, timeout, unit, attachment, handler);
bufs[0] = dst;
return read(bufs, false, timeout, unit, attachment, handler);
} }
@Override @Override
public final <A> Future<Long> read(ByteBuffer[] dsts, public final <A> void read(ByteBuffer[] dsts,
int offset, int offset,
int length, int length,
long timeout, long timeout,
...@@ -272,6 +304,8 @@ abstract class AsynchronousSocketChannelImpl ...@@ -272,6 +304,8 @@ abstract class AsynchronousSocketChannelImpl
A attachment, A attachment,
CompletionHandler<Long,? super A> handler) CompletionHandler<Long,? super A> handler)
{ {
if (handler == null)
throw new NullPointerException("'handler' is null");
if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
ByteBuffer[] bufs = Util.subsequence(dsts, offset, length); ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
...@@ -279,28 +313,30 @@ abstract class AsynchronousSocketChannelImpl ...@@ -279,28 +313,30 @@ abstract class AsynchronousSocketChannelImpl
if (bufs[i].isReadOnly()) if (bufs[i].isReadOnly())
throw new IllegalArgumentException("Read-only buffer"); throw new IllegalArgumentException("Read-only buffer");
} }
return read(bufs, true, timeout, unit, attachment, handler); read(true, null, bufs, timeout, unit, attachment, handler);
} }
/** /**
* Invoked by write to initiate the I/O operation. * Invoked by write to initiate the I/O operation.
*/ */
abstract <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs, abstract <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
boolean isGatheringWrite, ByteBuffer src,
ByteBuffer[] srcs,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
CompletionHandler<V,? super A> handler); CompletionHandler<V,? super A> handler);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <V extends Number,A> Future<V> write(ByteBuffer[] srcs, private <V extends Number,A> Future<V> write(boolean isGatheringWrite,
boolean isGatheringWrite, ByteBuffer src,
ByteBuffer[] srcs,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A att,
CompletionHandler<V,? super A> handler) CompletionHandler<V,? super A> handler)
{ {
boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining(); boolean hasDataToWrite = isGatheringWrite || src.hasRemaining();
boolean closed = false; boolean closed = false;
if (isOpen()) { if (isOpen()) {
...@@ -311,7 +347,7 @@ abstract class AsynchronousSocketChannelImpl ...@@ -311,7 +347,7 @@ abstract class AsynchronousSocketChannelImpl
// check and update state // check and update state
synchronized (writeLock) { synchronized (writeLock) {
if (writeKilled) if (writeKilled)
throw new RuntimeException("Writing not allowed due to timeout or cancellation"); throw new IllegalStateException("Writing not allowed due to timeout or cancellation");
if (writing) if (writing)
throw new WritePendingException(); throw new WritePendingException();
if (writeShutdown) { if (writeShutdown) {
...@@ -327,41 +363,44 @@ abstract class AsynchronousSocketChannelImpl ...@@ -327,41 +363,44 @@ abstract class AsynchronousSocketChannelImpl
// channel is closed or shutdown for write // channel is closed or shutdown for write
if (closed) { if (closed) {
CompletedFuture<V,A> result = CompletedFuture Throwable e = new ClosedChannelException();
.withFailure(this, new ClosedChannelException(), attachment); if (handler == null)
Invoker.invoke(handler, result); return CompletedFuture.withFailure(e);
return result; Invoker.invoke(this, handler, att, null, e);
return null;
} }
// nothing to write so complete immediately // nothing to write so complete immediately
if (!hasDataToWrite) { if (!hasDataToWrite) {
CompletedFuture<V,A> result; Number result = (isGatheringWrite) ? (Number)0L : (Number)0;
if (isGatheringWrite) { if (handler == null)
result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0L, attachment); return CompletedFuture.withResult((V)result);
} else { Invoker.invoke(this, handler, att, (V)result, null);
result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0, attachment); return null;
} }
Invoker.invoke(handler, result);
return result; return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler);
} }
return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler); @Override
public final Future<Integer> write(ByteBuffer src) {
return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null);
} }
@Override @Override
public final <A> Future<Integer> write(ByteBuffer src, public final <A> void write(ByteBuffer src,
long timeout, long timeout,
TimeUnit unit, TimeUnit unit,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
ByteBuffer[] bufs = new ByteBuffer[1]; if (handler == null)
bufs[0] = src; throw new NullPointerException("'handler' is null");
return write(bufs, false, timeout, unit, attachment, handler); write(false, src, null, timeout, unit, attachment, handler);
} }
@Override @Override
public final <A> Future<Long> write(ByteBuffer[] srcs, public final <A> void write(ByteBuffer[] srcs,
int offset, int offset,
int length, int length,
long timeout, long timeout,
...@@ -369,10 +408,12 @@ abstract class AsynchronousSocketChannelImpl ...@@ -369,10 +408,12 @@ abstract class AsynchronousSocketChannelImpl
A attachment, A attachment,
CompletionHandler<Long,? super A> handler) CompletionHandler<Long,? super A> handler)
{ {
if (handler == null)
throw new NullPointerException("'handler' is null");
if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
srcs = Util.subsequence(srcs, offset, length); srcs = Util.subsequence(srcs, offset, length);
return write(srcs, true, timeout, unit, attachment, handler); write(true, null, srcs, timeout, unit, attachment, handler);
} }
@Override @Override
...@@ -461,7 +502,6 @@ abstract class AsynchronousSocketChannelImpl ...@@ -461,7 +502,6 @@ abstract class AsynchronousSocketChannelImpl
} }
@Override @Override
@SuppressWarnings("unchecked")
public final SocketAddress getRemoteAddress() throws IOException { public final SocketAddress getRemoteAddress() throws IOException {
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); throw new ClosedChannelException();
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
package sun.nio.ch; package sun.nio.ch;
import java.nio.channels.AsynchronousChannel; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.io.IOException; import java.io.IOException;
...@@ -35,39 +35,35 @@ import java.io.IOException; ...@@ -35,39 +35,35 @@ import java.io.IOException;
* completed. * completed.
*/ */
final class CompletedFuture<V,A> final class CompletedFuture<V> implements Future<V> {
extends AbstractFuture<V,A>
{
private final V result; private final V result;
private final Throwable exc; private final Throwable exc;
private CompletedFuture(AsynchronousChannel channel, private CompletedFuture(V result, Throwable exc) {
V result,
Throwable exc,
A attachment)
{
super(channel, attachment);
this.result = result; this.result = result;
this.exc = exc; this.exc = exc;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <V,A> CompletedFuture<V,A> withResult(AsynchronousChannel channel, static <V> CompletedFuture<V> withResult(V result) {
V result, return new CompletedFuture<V>(result, null);
A attachment)
{
return new CompletedFuture<V,A>(channel, result, null, attachment);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <V,A> CompletedFuture<V,A> withFailure(AsynchronousChannel channel, static <V> CompletedFuture<V> withFailure(Throwable exc) {
Throwable exc,
A attachment)
{
// exception must be IOException or SecurityException // exception must be IOException or SecurityException
if (!(exc instanceof IOException) && !(exc instanceof SecurityException)) if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
exc = new IOException(exc); exc = new IOException(exc);
return new CompletedFuture(channel, null, exc, attachment); return new CompletedFuture(null, exc);
}
@SuppressWarnings("unchecked")
static <V> CompletedFuture<V> withResult(V result, Throwable exc) {
if (exc == null) {
return withResult(result);
} else {
return withFailure(exc);
}
} }
@Override @Override
...@@ -100,14 +96,4 @@ final class CompletedFuture<V,A> ...@@ -100,14 +96,4 @@ final class CompletedFuture<V,A>
public boolean cancel(boolean mayInterruptIfRunning) { public boolean cancel(boolean mayInterruptIfRunning) {
return false; return false;
} }
@Override
Throwable exception() {
return exc;
}
@Override
V value() {
return result;
}
} }
...@@ -117,33 +117,32 @@ class Invoker { ...@@ -117,33 +117,32 @@ class Invoker {
* Invoke handler without checking the thread identity or number of handlers * Invoke handler without checking the thread identity or number of handlers
* on the thread stack. * on the thread stack.
*/ */
@SuppressWarnings("unchecked")
static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler, static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,
AbstractFuture<V,A> result) A attachment,
V value,
Throwable exc)
{ {
if (handler != null && !result.isCancelled()) {
Throwable exc = result.exception();
if (exc == null) { if (exc == null) {
handler.completed(result.value(), result.attachment()); handler.completed(value, attachment);
} else { } else {
handler.failed(exc, result.attachment()); handler.failed(exc, attachment);
} }
// clear interrupt // clear interrupt
Thread.interrupted(); Thread.interrupted();
} }
}
/** /**
* Invoke handler after incrementing the invoke count. * Invoke handler assuming thread identity already checked
*/ */
static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
CompletionHandler<V,? super A> handler, CompletionHandler<V,? super A> handler,
AbstractFuture<V,A> result) A attachment,
V result,
Throwable exc)
{ {
myGroupAndInvokeCount.incrementInvokeCount(); myGroupAndInvokeCount.incrementInvokeCount();
invokeUnchecked(handler, result); Invoker.invokeUnchecked(handler, attachment, result, exc);
} }
/** /**
...@@ -151,15 +150,16 @@ class Invoker { ...@@ -151,15 +150,16 @@ class Invoker {
* thread pool then the handler is invoked directly, otherwise it is * thread pool then the handler is invoked directly, otherwise it is
* invoked indirectly. * invoked indirectly.
*/ */
static <V,A> void invoke(CompletionHandler<V,? super A> handler, static <V,A> void invoke(AsynchronousChannel channel,
AbstractFuture<V,A> result) CompletionHandler<V,? super A> handler,
A attachment,
V result,
Throwable exc)
{ {
if (handler != null) {
boolean invokeDirect = false; boolean invokeDirect = false;
boolean identityOkay = false; boolean identityOkay = false;
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
if (thisGroupAndInvokeCount != null) { if (thisGroupAndInvokeCount != null) {
AsynchronousChannel channel = result.channel();
if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))
identityOkay = true; identityOkay = true;
if (identityOkay && if (identityOkay &&
...@@ -170,32 +170,32 @@ class Invoker { ...@@ -170,32 +170,32 @@ class Invoker {
} }
} }
if (invokeDirect) { if (invokeDirect) {
thisGroupAndInvokeCount.incrementInvokeCount(); invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc);
invokeUnchecked(handler, result);
} else { } else {
try { try {
invokeIndirectly(handler, result); invokeIndirectly(channel, handler, attachment, result, exc);
} catch (RejectedExecutionException ree) { } catch (RejectedExecutionException ree) {
// channel group shutdown; fallback to invoking directly // channel group shutdown; fallback to invoking directly
// if the current thread has the right identity. // if the current thread has the right identity.
if (identityOkay) { if (identityOkay) {
invokeUnchecked(handler, result); invokeDirect(thisGroupAndInvokeCount,
handler, attachment, result, exc);
} else { } else {
throw new ShutdownChannelGroupException(); throw new ShutdownChannelGroupException();
} }
} }
} }
} }
}
/** /**
* Invokes the handler "indirectly" in the channel group's thread pool. * Invokes the handler indirectly via the channel group's thread pool.
*/ */
static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler, static <V,A> void invokeIndirectly(AsynchronousChannel channel,
final AbstractFuture<V,A> result) final CompletionHandler<V,? super A> handler,
final A attachment,
final V result,
final Throwable exc)
{ {
if (handler != null) {
AsynchronousChannel channel = result.channel();
try { try {
((Groupable)channel).group().executeOnPooledThread(new Runnable() { ((Groupable)channel).group().executeOnPooledThread(new Runnable() {
public void run() { public void run() {
...@@ -203,34 +203,33 @@ class Invoker { ...@@ -203,34 +203,33 @@ class Invoker {
myGroupAndInvokeCount.get(); myGroupAndInvokeCount.get();
if (thisGroupAndInvokeCount != null) if (thisGroupAndInvokeCount != null)
thisGroupAndInvokeCount.setInvokeCount(1); thisGroupAndInvokeCount.setInvokeCount(1);
invokeUnchecked(handler, result); invokeUnchecked(handler, attachment, result, exc);
} }
}); });
} catch (RejectedExecutionException ree) { } catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException(); throw new ShutdownChannelGroupException();
} }
} }
}
/** /**
* Invokes the handler "indirectly" in the given Executor * Invokes the handler "indirectly" in the given Executor
*/ */
static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler, static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
final AbstractFuture<V,A> result, final A attachment,
final V value,
final Throwable exc,
Executor executor) Executor executor)
{ {
if (handler != null) {
try { try {
executor.execute(new Runnable() { executor.execute(new Runnable() {
public void run() { public void run() {
invokeUnchecked(handler, result); invokeUnchecked(handler, attachment, value, exc);
} }
}); });
} catch (RejectedExecutionException ree) { } catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException(); throw new ShutdownChannelGroupException();
} }
} }
}
/** /**
* Invokes the given task on the thread pool associated with the given * Invokes the given task on the thread pool associated with the given
...@@ -258,4 +257,52 @@ class Invoker { ...@@ -258,4 +257,52 @@ class Invoker {
throw new ShutdownChannelGroupException(); throw new ShutdownChannelGroupException();
} }
} }
/**
* Invoke handler with completed result. This method does not check the
* thread identity or the number of handlers on the thread stack.
*/
static <V,A> void invokeUnchecked(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invokeUnchecked(handler,
future.attachment(),
future.value(),
future.exception());
}
}
/**
* Invoke handler with completed result. If the current thread is in the
* channel group's thread pool then the handler is invoked directly,
* otherwise it is invoked indirectly.
*/
static <V,A> void invoke(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invoke(future.channel(),
handler,
future.attachment(),
future.value(),
future.exception());
}
}
/**
* Invoke handler with completed result. The handler is invoked indirectly,
* via the channel group's thread pool.
*/
static <V,A> void invokeIndirectly(PendingFuture<V,A> future) {
assert future.isDone();
CompletionHandler<V,? super A> handler = future.handler();
if (handler != null) {
invokeIndirectly(future.channel(),
handler,
future.attachment(),
future.value(),
future.exception());
}
}
} }
...@@ -34,13 +34,13 @@ import java.io.IOException; ...@@ -34,13 +34,13 @@ import java.io.IOException;
* attachment of an additional arbitrary context object and a timer task. * attachment of an additional arbitrary context object and a timer task.
*/ */
final class PendingFuture<V,A> final class PendingFuture<V,A> implements Future<V> {
extends AbstractFuture<V,A>
{
private static final CancellationException CANCELLED = private static final CancellationException CANCELLED =
new CancellationException(); new CancellationException();
private final AsynchronousChannel channel;
private final CompletionHandler<V,? super A> handler; private final CompletionHandler<V,? super A> handler;
private final A attachment;
// true if result (or exception) is available // true if result (or exception) is available
private volatile boolean haveResult; private volatile boolean haveResult;
...@@ -56,14 +56,14 @@ final class PendingFuture<V,A> ...@@ -56,14 +56,14 @@ final class PendingFuture<V,A>
// optional context object // optional context object
private volatile Object context; private volatile Object context;
PendingFuture(AsynchronousChannel channel, PendingFuture(AsynchronousChannel channel,
CompletionHandler<V,? super A> handler, CompletionHandler<V,? super A> handler,
A attachment, A attachment,
Object context) Object context)
{ {
super(channel, attachment); this.channel = channel;
this.handler = handler; this.handler = handler;
this.attachment = attachment;
this.context = context; this.context = context;
} }
...@@ -71,14 +71,31 @@ final class PendingFuture<V,A> ...@@ -71,14 +71,31 @@ final class PendingFuture<V,A>
CompletionHandler<V,? super A> handler, CompletionHandler<V,? super A> handler,
A attachment) A attachment)
{ {
super(channel, attachment); this.channel = channel;
this.handler = handler; this.handler = handler;
this.attachment = attachment;
}
PendingFuture(AsynchronousChannel channel) {
this(channel, null, null);
}
PendingFuture(AsynchronousChannel channel, Object context) {
this(channel, null, null, context);
}
AsynchronousChannel channel() {
return channel;
} }
CompletionHandler<V,? super A> handler() { CompletionHandler<V,? super A> handler() {
return handler; return handler;
} }
A attachment() {
return attachment;
}
void setContext(Object context) { void setContext(Object context) {
this.context = context; this.context = context;
} }
...@@ -113,36 +130,45 @@ final class PendingFuture<V,A> ...@@ -113,36 +130,45 @@ final class PendingFuture<V,A>
/** /**
* Sets the result, or a no-op if the result or exception is already set. * Sets the result, or a no-op if the result or exception is already set.
*/ */
boolean setResult(V res) { void setResult(V res) {
synchronized (this) { synchronized (this) {
if (haveResult) if (haveResult)
return false; return;
result = res; result = res;
haveResult = true; haveResult = true;
if (timeoutTask != null) if (timeoutTask != null)
timeoutTask.cancel(false); timeoutTask.cancel(false);
if (latch != null) if (latch != null)
latch.countDown(); latch.countDown();
return true;
} }
} }
/** /**
* Sets the result, or a no-op if the result or exception is already set. * Sets the result, or a no-op if the result or exception is already set.
*/ */
boolean setFailure(Throwable x) { void setFailure(Throwable x) {
if (!(x instanceof IOException) && !(x instanceof SecurityException)) if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x); x = new IOException(x);
synchronized (this) { synchronized (this) {
if (haveResult) if (haveResult)
return false; return;
exc = x; exc = x;
haveResult = true; haveResult = true;
if (timeoutTask != null) if (timeoutTask != null)
timeoutTask.cancel(false); timeoutTask.cancel(false);
if (latch != null) if (latch != null)
latch.countDown(); latch.countDown();
return true; }
}
/**
* Sets the result
*/
void setResult(V res, Throwable x) {
if (x == null) {
setResult(res);
} else {
setFailure(x);
} }
} }
...@@ -178,12 +204,10 @@ final class PendingFuture<V,A> ...@@ -178,12 +204,10 @@ final class PendingFuture<V,A>
return result; return result;
} }
@Override
Throwable exception() { Throwable exception() {
return (exc != CANCELLED) ? exc : null; return (exc != CANCELLED) ? exc : null;
} }
@Override
V value() { V value() {
return result; return result;
} }
...@@ -204,33 +228,6 @@ final class PendingFuture<V,A> ...@@ -204,33 +228,6 @@ final class PendingFuture<V,A>
if (haveResult) if (haveResult)
return false; // already completed return false; // already completed
// A shutdown of the channel group will close all channels and
// shutdown the executor. To ensure that the completion handler
// is executed we queue the task while holding the lock.
if (handler != null) {
prepareForWait();
Runnable cancelTask = new Runnable() {
public void run() {
while (!haveResult) {
try {
latch.await();
} catch (InterruptedException ignore) { }
}
handler.cancelled(attachment());
}
};
AsynchronousChannel ch = channel();
if (ch instanceof Groupable) {
((Groupable)ch).group().executeOnPooledThread(cancelTask);
} else {
if (ch instanceof AsynchronousFileChannelImpl) {
((AsynchronousFileChannelImpl)ch).executor().execute(cancelTask);
} else {
throw new AssertionError("Should not get here");
}
}
}
// notify channel // notify channel
if (channel() instanceof Cancellable) if (channel() instanceof Cancellable)
((Cancellable)channel()).onCancel(this); ((Cancellable)channel()).onCancel(this);
...@@ -249,7 +246,7 @@ final class PendingFuture<V,A> ...@@ -249,7 +246,7 @@ final class PendingFuture<V,A>
} catch (IOException ignore) { } } catch (IOException ignore) { }
} }
// release waiters (this also releases the invoker) // release waiters
if (latch != null) if (latch != null)
latch.countDown(); latch.countDown();
return true; return true;
......
...@@ -317,51 +317,71 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -317,51 +317,71 @@ class SimpleAsynchronousDatagramChannelImpl
return new WrappedMembershipKey(this, key); return new WrappedMembershipKey(this, key);
} }
@Override private <A> Future<Integer> implSend(ByteBuffer src,
public <A> Future<Integer> send(ByteBuffer src,
SocketAddress target, SocketAddress target,
long timeout,
TimeUnit unit,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
if (timeout < 0L) int n = 0;
throw new IllegalArgumentException("Negative timeout"); Throwable exc = null;
if (unit == null)
throw new NullPointerException();
CompletedFuture<Integer,A> result;
try { try {
int n = dc.send(src, target); n = dc.send(src, target);
result = CompletedFuture.withResult(this, n, attachment);
} catch (IOException ioe) { } catch (IOException ioe) {
result = CompletedFuture.withFailure(this, ioe, attachment); exc = ioe;
} }
Invoker.invoke(handler, result); if (handler == null)
return result; return CompletedFuture.withResult(n, exc);
Invoker.invoke(this, handler, attachment, n, exc);
return null;
} }
@Override @Override
public <A> Future<Integer> write(ByteBuffer src, public Future<Integer> send(ByteBuffer src, SocketAddress target) {
long timeout, return implSend(src, target, null, null);
TimeUnit unit, }
@Override
public <A> void send(ByteBuffer src,
SocketAddress target,
A attachment, A attachment,
CompletionHandler<Integer,? super A> handler) CompletionHandler<Integer,? super A> handler)
{ {
if (timeout < 0L) if (handler == null)
throw new IllegalArgumentException("Negative timeout"); throw new NullPointerException("'handler' is null");
if (unit == null) implSend(src, target, attachment, handler);
throw new NullPointerException(); }
CompletedFuture<Integer,A> result; private <A> Future<Integer> implWrite(ByteBuffer src,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
int n = 0;
Throwable exc = null;
try { try {
int n = dc.write(src); n = dc.write(src);
result = CompletedFuture.withResult(this, n, attachment);
} catch (IOException ioe) { } catch (IOException ioe) {
result = CompletedFuture.withFailure(this, ioe, attachment); exc = ioe;
} }
Invoker.invoke(handler, result); if (handler == null)
return result; return CompletedFuture.withResult(n, exc);
Invoker.invoke(this, handler, attachment, n, exc);
return null;
}
@Override
public Future<Integer> write(ByteBuffer src) {
return implWrite(src, null, null);
}
@Override
public <A> void write(ByteBuffer src,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implWrite(src, attachment, handler);
} }
/** /**
...@@ -390,8 +410,7 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -390,8 +410,7 @@ class SimpleAsynchronousDatagramChannelImpl
} }
} }
@Override private <A> Future<SocketAddress> implReceive(final ByteBuffer dst,
public <A> Future<SocketAddress> receive(final ByteBuffer dst,
final long timeout, final long timeout,
final TimeUnit unit, final TimeUnit unit,
A attachment, A attachment,
...@@ -406,10 +425,11 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -406,10 +425,11 @@ class SimpleAsynchronousDatagramChannelImpl
// complete immediately if channel closed // complete immediately if channel closed
if (!isOpen()) { if (!isOpen()) {
CompletedFuture<SocketAddress,A> result = CompletedFuture.withFailure(this, Throwable exc = new ClosedChannelException();
new ClosedChannelException(), attachment); if (handler == null)
Invoker.invoke(handler, result); return CompletedFuture.withFailure(exc);
return result; Invoker.invoke(this, handler, attachment, null, exc);
return null;
} }
final AccessControlContext acc = (System.getSecurityManager() == null) ? final AccessControlContext acc = (System.getSecurityManager() == null) ?
...@@ -471,7 +491,7 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -471,7 +491,7 @@ class SimpleAsynchronousDatagramChannelImpl
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result.setFailure(x); result.setFailure(x);
} }
Invoker.invokeUnchecked(handler, result); Invoker.invokeUnchecked(result);
} }
}; };
try { try {
...@@ -483,7 +503,23 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -483,7 +503,23 @@ class SimpleAsynchronousDatagramChannelImpl
} }
@Override @Override
public <A> Future<Integer> read(final ByteBuffer dst, public Future<SocketAddress> receive(ByteBuffer dst) {
return implReceive(dst, 0L, TimeUnit.MILLISECONDS, null, null);
}
@Override
public <A> void receive(ByteBuffer dst,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<SocketAddress,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implReceive(dst, timeout, unit, attachment, handler);
}
private <A> Future<Integer> implRead(final ByteBuffer dst,
final long timeout, final long timeout,
final TimeUnit unit, final TimeUnit unit,
A attachment, A attachment,
...@@ -495,18 +531,20 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -495,18 +531,20 @@ class SimpleAsynchronousDatagramChannelImpl
throw new IllegalArgumentException("Negative timeout"); throw new IllegalArgumentException("Negative timeout");
if (unit == null) if (unit == null)
throw new NullPointerException(); throw new NullPointerException();
// another thread may disconnect before read is initiated
if (!dc.isConnected())
throw new NotYetConnectedException();
// complete immediately if channel closed // complete immediately if channel closed
if (!isOpen()) { if (!isOpen()) {
CompletedFuture<Integer,A> result = CompletedFuture.withFailure(this, Throwable exc = new ClosedChannelException();
new ClosedChannelException(), attachment); if (handler == null)
Invoker.invoke(handler, result); return CompletedFuture.withFailure(exc);
return result; Invoker.invoke(this, handler, attachment, null, exc);
return null;
} }
// another thread may disconnect before read is initiated
if (!dc.isConnected())
throw new NotYetConnectedException();
final PendingFuture<Integer,A> result = final PendingFuture<Integer,A> result =
new PendingFuture<Integer,A>(this, handler, attachment); new PendingFuture<Integer,A>(this, handler, attachment);
Runnable task = new Runnable() { Runnable task = new Runnable() {
...@@ -563,7 +601,7 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -563,7 +601,7 @@ class SimpleAsynchronousDatagramChannelImpl
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result.setFailure(x); result.setFailure(x);
} }
Invoker.invokeUnchecked(handler, result); Invoker.invokeUnchecked(result);
} }
}; };
try { try {
...@@ -574,6 +612,23 @@ class SimpleAsynchronousDatagramChannelImpl ...@@ -574,6 +612,23 @@ class SimpleAsynchronousDatagramChannelImpl
return result; return result;
} }
@Override
public Future<Integer> read(ByteBuffer dst) {
return implRead(dst, 0L, TimeUnit.MILLISECONDS, null, null);
}
@Override
public <A> void read(ByteBuffer dst,
long timeout,
TimeUnit unit,
A attachment,
CompletionHandler<Integer,? super A> handler)
{
if (handler == null)
throw new NullPointerException("'handler' is null");
implRead(dst, timeout, unit, attachment, handler);
}
@Override @Override
public AsynchronousDatagramChannel bind(SocketAddress local) public AsynchronousDatagramChannel bind(SocketAddress local)
throws IOException throws IOException
......
...@@ -50,9 +50,6 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -50,9 +50,6 @@ public class SimpleAsynchronousFileChannelImpl
// Used to make native read and write calls // Used to make native read and write calls
private static final FileDispatcher nd = new FileDispatcherImpl(); private static final FileDispatcher nd = new FileDispatcherImpl();
// indicates if the associated thread pool is the default thread pool
private final boolean isDefaultExecutor;
// Thread-safe set of IDs of native threads, for signalling // Thread-safe set of IDs of native threads, for signalling
private final NativeThreadSet threads = new NativeThreadSet(2); private final NativeThreadSet threads = new NativeThreadSet(2);
...@@ -60,11 +57,9 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -60,11 +57,9 @@ public class SimpleAsynchronousFileChannelImpl
SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj, SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj,
boolean reading, boolean reading,
boolean writing, boolean writing,
ExecutorService executor, ExecutorService executor)
boolean isDefaultexecutor)
{ {
super(fdObj, reading, writing, executor); super(fdObj, reading, writing, executor);
this.isDefaultExecutor = isDefaultexecutor;
} }
public static AsynchronousFileChannel open(FileDescriptor fdo, public static AsynchronousFileChannel open(FileDescriptor fdo,
...@@ -73,17 +68,9 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -73,17 +68,9 @@ public class SimpleAsynchronousFileChannelImpl
ThreadPool pool) ThreadPool pool)
{ {
// Executor is either default or based on pool parameters // Executor is either default or based on pool parameters
ExecutorService executor; ExecutorService executor = (pool == null) ?
boolean isDefaultexecutor; DefaultExecutorHolder.defaultExecutor : pool.executor();
if (pool == null) { return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor);
executor = DefaultExecutorHolder.defaultExecutor;
isDefaultexecutor = true;
} else {
executor = pool.executor();
isDefaultexecutor = false;
}
return new SimpleAsynchronousFileChannelImpl(fdo,
reading, writing, executor, isDefaultexecutor);
} }
@Override @Override
...@@ -114,16 +101,6 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -114,16 +101,6 @@ public class SimpleAsynchronousFileChannelImpl
// close file // close file
nd.close(fdObj); nd.close(fdObj);
// shutdown executor if specific to this channel
if (!isDefaultExecutor) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
executor.shutdown();
return null;
}
});
}
} }
@Override @Override
...@@ -194,10 +171,10 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -194,10 +171,10 @@ public class SimpleAsynchronousFileChannelImpl
} }
@Override @Override
public <A> Future<FileLock> lock(final long position, <A> Future<FileLock> implLock(final long position,
final long size, final long size,
final boolean shared, final boolean shared,
A attachment, final A attachment,
final CompletionHandler<FileLock,? super A> handler) final CompletionHandler<FileLock,? super A> handler)
{ {
if (shared && !reading) if (shared && !reading)
...@@ -208,16 +185,19 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -208,16 +185,19 @@ public class SimpleAsynchronousFileChannelImpl
// add to lock table // add to lock table
final FileLockImpl fli = addToFileLockTable(position, size, shared); final FileLockImpl fli = addToFileLockTable(position, size, shared);
if (fli == null) { if (fli == null) {
CompletedFuture<FileLock,A> result = CompletedFuture Throwable exc = new ClosedChannelException();
.withFailure(this, new ClosedChannelException(), attachment); if (handler == null)
Invoker.invokeIndirectly(handler, result, executor); return CompletedFuture.withFailure(exc);
return result; Invoker.invokeIndirectly(handler, attachment, null, exc, executor);
return null;
} }
final PendingFuture<FileLock,A> result = final PendingFuture<FileLock,A> result = (handler == null) ?
new PendingFuture<FileLock,A>(this, handler, attachment); new PendingFuture<FileLock,A>(this) : null;
Runnable task = new Runnable() { Runnable task = new Runnable() {
public void run() { public void run() {
Throwable exc = null;
int ti = threads.add(); int ti = threads.add();
try { try {
int n; int n;
...@@ -226,31 +206,36 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -226,31 +206,36 @@ public class SimpleAsynchronousFileChannelImpl
do { do {
n = nd.lock(fdObj, true, position, size, shared); n = nd.lock(fdObj, true, position, size, shared);
} while ((n == FileDispatcher.INTERRUPTED) && isOpen()); } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
if (n == FileDispatcher.LOCKED && isOpen()) { if (n != FileDispatcher.LOCKED || !isOpen()) {
result.setResult(fli);
} else {
throw new AsynchronousCloseException(); throw new AsynchronousCloseException();
} }
} catch (IOException x) { } catch (IOException x) {
removeFromFileLockTable(fli); removeFromFileLockTable(fli);
if (!isOpen()) if (!isOpen())
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result.setFailure(x); exc = x;
} finally { } finally {
end(); end();
} }
} finally { } finally {
threads.remove(ti); threads.remove(ti);
} }
Invoker.invokeUnchecked(handler, result); if (handler == null) {
result.setResult(fli, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, fli, exc);
}
} }
}; };
boolean executed = false;
try { try {
executor.execute(task); executor.execute(task);
} catch (RejectedExecutionException ree) { executed = true;
} finally {
if (!executed) {
// rollback // rollback
removeFromFileLockTable(fli); removeFromFileLockTable(fli);
throw new ShutdownChannelGroupException(); }
} }
return result; return result;
} }
...@@ -301,9 +286,9 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -301,9 +286,9 @@ public class SimpleAsynchronousFileChannelImpl
} }
@Override @Override
public <A> Future<Integer> read(final ByteBuffer dst, <A> Future<Integer> implRead(final ByteBuffer dst,
final long position, final long position,
A attachment, final A attachment,
final CompletionHandler<Integer,? super A> handler) final CompletionHandler<Integer,? super A> handler)
{ {
if (position < 0) if (position < 0)
...@@ -315,54 +300,51 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -315,54 +300,51 @@ public class SimpleAsynchronousFileChannelImpl
// complete immediately if channel closed or no space remaining // complete immediately if channel closed or no space remaining
if (!isOpen() || (dst.remaining() == 0)) { if (!isOpen() || (dst.remaining() == 0)) {
CompletedFuture<Integer,A> result; Throwable exc = (isOpen()) ? null : new ClosedChannelException();
if (isOpen()) { if (handler == null)
result = CompletedFuture.withResult(this, 0, attachment); return CompletedFuture.withResult(0, exc);
} else { Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
result = CompletedFuture.withFailure(this, return null;
new ClosedChannelException(), attachment);
}
Invoker.invokeIndirectly(handler, result, executor);
return result;
} }
final PendingFuture<Integer,A> result = final PendingFuture<Integer,A> result = (handler == null) ?
new PendingFuture<Integer,A>(this, handler, attachment); new PendingFuture<Integer,A>(this) : null;
Runnable task = new Runnable() { Runnable task = new Runnable() {
public void run() { public void run() {
int n = 0;
Throwable exc = null;
int ti = threads.add(); int ti = threads.add();
try { try {
begin(); begin();
int n;
do { do {
n = IOUtil.read(fdObj, dst, position, nd, null); n = IOUtil.read(fdObj, dst, position, nd, null);
} while ((n == IOStatus.INTERRUPTED) && isOpen()); } while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n < 0 && !isOpen()) if (n < 0 && !isOpen())
throw new AsynchronousCloseException(); throw new AsynchronousCloseException();
result.setResult(n);
} catch (IOException x) { } catch (IOException x) {
if (!isOpen()) if (!isOpen())
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result.setFailure(x); exc = x;
} finally { } finally {
end(); end();
threads.remove(ti); threads.remove(ti);
} }
Invoker.invokeUnchecked(handler, result); if (handler == null) {
result.setResult(n, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, n, exc);
}
} }
}; };
try {
executor.execute(task); executor.execute(task);
} catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException();
}
return result; return result;
} }
@Override @Override
public <A> Future<Integer> write(final ByteBuffer src, <A> Future<Integer> implWrite(final ByteBuffer src,
final long position, final long position,
A attachment, final A attachment,
final CompletionHandler<Integer,? super A> handler) final CompletionHandler<Integer,? super A> handler)
{ {
if (position < 0) if (position < 0)
...@@ -372,47 +354,44 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -372,47 +354,44 @@ public class SimpleAsynchronousFileChannelImpl
// complete immediately if channel is closed or no bytes remaining // complete immediately if channel is closed or no bytes remaining
if (!isOpen() || (src.remaining() == 0)) { if (!isOpen() || (src.remaining() == 0)) {
CompletedFuture<Integer,A> result; Throwable exc = (isOpen()) ? null : new ClosedChannelException();
if (isOpen()) { if (handler == null)
result = CompletedFuture.withResult(this, 0, attachment); return CompletedFuture.withResult(0, exc);
} else { Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
result = CompletedFuture.withFailure(this, return null;
new ClosedChannelException(), attachment);
}
Invoker.invokeIndirectly(handler, result, executor);
return result;
} }
final PendingFuture<Integer,A> result = final PendingFuture<Integer,A> result = (handler == null) ?
new PendingFuture<Integer,A>(this, handler, attachment); new PendingFuture<Integer,A>(this) : null;
Runnable task = new Runnable() { Runnable task = new Runnable() {
public void run() { public void run() {
int n = 0;
Throwable exc = null;
int ti = threads.add(); int ti = threads.add();
try { try {
begin(); begin();
int n;
do { do {
n = IOUtil.write(fdObj, src, position, nd, null); n = IOUtil.write(fdObj, src, position, nd, null);
} while ((n == IOStatus.INTERRUPTED) && isOpen()); } while ((n == IOStatus.INTERRUPTED) && isOpen());
if (n < 0 && !isOpen()) if (n < 0 && !isOpen())
throw new AsynchronousCloseException(); throw new AsynchronousCloseException();
result.setResult(n);
} catch (IOException x) { } catch (IOException x) {
if (!isOpen()) if (!isOpen())
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result.setFailure(x); exc = x;
} finally { } finally {
end(); end();
threads.remove(ti); threads.remove(ti);
} }
Invoker.invokeUnchecked(handler, result); if (handler == null) {
result.setResult(n, exc);
} else {
Invoker.invokeUnchecked(handler, attachment, n, exc);
}
} }
}; };
try {
executor.execute(task); executor.execute(task);
} catch (RejectedExecutionException ree) {
throw new ShutdownChannelGroupException();
}
return result; return result;
} }
} }
...@@ -388,9 +388,9 @@ abstract class ISO2022 ...@@ -388,9 +388,9 @@ abstract class ISO2022
protected static class Encoder extends CharsetEncoder { protected static class Encoder extends CharsetEncoder {
private final Surrogate.Parser sgp = new Surrogate.Parser(); private final Surrogate.Parser sgp = new Surrogate.Parser();
private final byte SS2 = (byte)0x8e; public static final byte SS2 = (byte)0x8e;
private final byte PLANE2 = (byte)0xA2; public static final byte PLANE2 = (byte)0xA2;
private final byte PLANE3 = (byte)0xA3; public static final byte PLANE3 = (byte)0xA3;
private final byte MSB = (byte)0x80; private final byte MSB = (byte)0x80;
protected final byte maximumDesignatorLength = 4; protected final byte maximumDesignatorLength = 4;
......
...@@ -76,6 +76,15 @@ public class ISO2022_CN_CNS extends ISO2022 implements HistoricallyNamedCharset ...@@ -76,6 +76,15 @@ public class ISO2022_CN_CNS extends ISO2022 implements HistoricallyNamedCharset
} catch (Exception e) { } } catch (Exception e) { }
} }
private byte[] bb = new byte[4];
public boolean canEncode(char c) {
int n = 0;
return (c <= '\u007f' ||
(n = ((EUC_TW.Encoder)ISOEncoder).toEUC(c, bb)) == 2 ||
(n == 4 && bb[0] == SS2 &&
(bb[1] == PLANE2 || bb[1] == PLANE3)));
}
/* /*
* Since ISO2022-CN-CNS possesses a CharsetEncoder * Since ISO2022-CN-CNS possesses a CharsetEncoder
* without the corresponding CharsetDecoder half the * without the corresponding CharsetDecoder half the
......
...@@ -62,7 +62,7 @@ public final class SunProvider extends Provider { ...@@ -62,7 +62,7 @@ public final class SunProvider extends Provider {
public SunProvider() { public SunProvider() {
/* We are the Sun JGSS provider */ /* We are the Sun JGSS provider */
super("SunJGSS", 1.0, INFO); super("SunJGSS", 1.7d, INFO);
AccessController.doPrivileged( AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() { new java.security.PrivilegedAction<Void>() {
......
...@@ -41,6 +41,7 @@ import java.io.IOException; ...@@ -41,6 +41,7 @@ import java.io.IOException;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.File; import java.io.File;
import java.util.Comparator;
import java.util.StringTokenizer; import java.util.StringTokenizer;
/** /**
...@@ -229,10 +230,11 @@ public class KeyTab implements KeyTabConstants { ...@@ -229,10 +230,11 @@ public class KeyTab implements KeyTabConstants {
/** /**
* Reads the service key from the keytab file. * Reads the service key from the keytab file.
* @param service the PrincipalName of the requested service. * @param service the PrincipalName of the requested service.
* @return the last service key in the keytab * @return the last service key in the keytab with the highest kvno
*/ */
public EncryptionKey readServiceKey(PrincipalName service) { public EncryptionKey readServiceKey(PrincipalName service) {
KeyTabEntry entry = null; KeyTabEntry entry = null;
EncryptionKey key = null;
if (entries != null) { if (entries != null) {
// Find latest entry for this service that has an etype // Find latest entry for this service that has an etype
// that has been configured for use // that has been configured for use
...@@ -240,9 +242,12 @@ public class KeyTab implements KeyTabConstants { ...@@ -240,9 +242,12 @@ public class KeyTab implements KeyTabConstants {
entry = entries.elementAt(i); entry = entries.elementAt(i);
if (entry.service.match(service)) { if (entry.service.match(service)) {
if (EType.isSupported(entry.keyType)) { if (EType.isSupported(entry.keyType)) {
return new EncryptionKey(entry.keyblock, if (key == null ||
entry.keyVersion > key.getKeyVersionNumber()) {
key = new EncryptionKey(entry.keyblock,
entry.keyType, entry.keyType,
new Integer(entry.keyVersion)); new Integer(entry.keyVersion));
}
} else if (DEBUG) { } else if (DEBUG) {
System.out.println("Found unsupported keytype (" + System.out.println("Found unsupported keytype (" +
entry.keyType + ") for " + service); entry.keyType + ") for " + service);
...@@ -250,12 +255,13 @@ public class KeyTab implements KeyTabConstants { ...@@ -250,12 +255,13 @@ public class KeyTab implements KeyTabConstants {
} }
} }
} }
return null; return key;
} }
/** /**
* Reads all keys for a service from the keytab file that have * Reads all keys for a service from the keytab file that have
* etypes that have been configured for use. * etypes that have been configured for use. If there are multiple
* keys with same etype, the one with the highest kvno is returned.
* @param service the PrincipalName of the requested service * @param service the PrincipalName of the requested service
* @return an array containing all the service keys * @return an array containing all the service keys
*/ */
...@@ -288,49 +294,39 @@ public class KeyTab implements KeyTabConstants { ...@@ -288,49 +294,39 @@ public class KeyTab implements KeyTabConstants {
size = keys.size(); size = keys.size();
if (size == 0) if (size == 0)
return null; return null;
EncryptionKey[] retVal = new EncryptionKey[size]; EncryptionKey[] retVal = keys.toArray(new EncryptionKey[size]);
// Sort keys according to default_tkt_enctypes // Sort keys according to default_tkt_enctypes
int pos = 0;
EncryptionKey k;
if (DEBUG) { if (DEBUG) {
System.out.println("Ordering keys wrt default_tkt_enctypes list"); System.out.println("Ordering keys wrt default_tkt_enctypes list");
} }
int[] etypes = EType.getDefaults("default_tkt_enctypes");
if (etypes == null || etypes == EType.getBuiltInDefaults()) { final int[] etypes = EType.getDefaults("default_tkt_enctypes");
// Either no supported types specified in default_tkt_enctypes
// or no default_tkt_enctypes entry at all. For both cases, // Sort the keys, k1 is preferred than k2 if:
// just return supported keys in the order retrieved // 1. k1's etype appears earlier in etypes than k2's
for (int i = 0; i < size; i++) { // 2. If same, k1's KVNO is higher
retVal[pos++] = keys.get(i); Arrays.sort(retVal, new Comparator<EncryptionKey>() {
} @Override
} else { public int compare(EncryptionKey o1, EncryptionKey o2) {
for (int j = 0; j < etypes.length && pos < size; j++) { if (etypes != null && etypes != EType.getBuiltInDefaults()) {
int target = etypes[j]; int o1EType = o1.getEType();
for (int i = 0; i < size && pos < size; i++) { int o2EType = o2.getEType();
k = keys.get(i); if (o1EType != o2EType) {
if (k != null && k.getEType() == target) { for (int i=0; i<etypes.length; i++) {
if (DEBUG) { if (etypes[i] == o1EType) {
System.out.println(pos + ": " + k); return -1;
} } else if (etypes[i] == o2EType) {
retVal[pos++] = k; return 1;
keys.set(i, null); // Cleared from consideration
}
}
} }
// copy the rest
for (int i = 0; i < size && pos < size; i++) {
k = keys.get(i);
if (k != null) {
retVal[pos++] = k;
} }
} }
} }
if (pos != size) { return o2.getKeyVersionNumber().intValue()
throw new RuntimeException( - o1.getKeyVersionNumber().intValue();
"Internal Error: did not copy all keys;expecting " + size +
"; got " + pos);
} }
});
return retVal; return retVal;
} }
......
...@@ -46,7 +46,7 @@ public final class Sun extends Provider { ...@@ -46,7 +46,7 @@ public final class Sun extends Provider {
public Sun() { public Sun() {
/* We are the SUN provider */ /* We are the SUN provider */
super("SUN", 1.6, INFO); super("SUN", 1.7, INFO);
// if there is no security manager installed, put directly into // if there is no security manager installed, put directly into
// the provider. Otherwise, create a temporary map and use a // the provider. Otherwise, create a temporary map and use a
......
...@@ -40,7 +40,7 @@ public final class SunPCSC extends Provider { ...@@ -40,7 +40,7 @@ public final class SunPCSC extends Provider {
private static final long serialVersionUID = 6168388284028876579L; private static final long serialVersionUID = 6168388284028876579L;
public SunPCSC() { public SunPCSC() {
super("SunPCSC", 1.6d, "Sun PC/SC provider"); super("SunPCSC", 1.7d, "Sun PC/SC provider");
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
put("TerminalFactory.PC/SC", "sun.security.smartcardio.SunPCSC$Factory"); put("TerminalFactory.PC/SC", "sun.security.smartcardio.SunPCSC$Factory");
......
...@@ -103,7 +103,7 @@ public abstract class SunJSSE extends java.security.Provider { ...@@ -103,7 +103,7 @@ public abstract class SunJSSE extends java.security.Provider {
// standard constructor // standard constructor
protected SunJSSE() { protected SunJSSE() {
super("SunJSSE", 1.6d, info); super("SunJSSE", 1.7d, info);
subclassCheck(); subclassCheck();
if (Boolean.TRUE.equals(fips)) { if (Boolean.TRUE.equals(fips)) {
throw new ProviderException throw new ProviderException
......
/* /*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -37,6 +37,14 @@ import java.util.Arrays; ...@@ -37,6 +37,14 @@ import java.util.Arrays;
public class Password { public class Password {
/** Reads user password from given input stream. */ /** Reads user password from given input stream. */
public static char[] readPassword(InputStream in) throws IOException { public static char[] readPassword(InputStream in) throws IOException {
return readPassword(in, false);
}
/** Reads user password from given input stream.
* @param isEchoOn true if the password should be echoed on the screen
*/
public static char[] readPassword(InputStream in, boolean isEchoOn)
throws IOException {
char[] consoleEntered = null; char[] consoleEntered = null;
byte[] consoleBytes = null; byte[] consoleBytes = null;
...@@ -44,7 +52,7 @@ public class Password { ...@@ -44,7 +52,7 @@ public class Password {
try { try {
// Use the new java.io.Console class // Use the new java.io.Console class
Console con = null; Console con = null;
if (in == System.in && ((con = System.console()) != null)) { if (!isEchoOn && in == System.in && ((con = System.console()) != null)) {
consoleEntered = con.readPassword(); consoleEntered = con.readPassword();
// readPassword returns "" if you just print ENTER, // readPassword returns "" if you just print ENTER,
// to be compatible with old Password class, change to null // to be compatible with old Password class, change to null
......
...@@ -422,7 +422,7 @@ ec_GenerateRandomPrivateKey(const unsigned char *order, int len, ...@@ -422,7 +422,7 @@ ec_GenerateRandomPrivateKey(const unsigned char *order, int len,
*/ */
if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup; if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;
if (randomlen != 2 * len) { if (randomlen != 2 * len) {
goto cleanup; randomlen = 2 * len;
} }
/* No need to generate - random bytes are now supplied */ /* No need to generate - random bytes are now supplied */
/* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/ /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/
......
...@@ -248,12 +248,13 @@ final class EPollPort ...@@ -248,12 +248,13 @@ final class EPollPort
public void run() { public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount(); Invoker.getGroupAndInvokeCount();
final boolean isPooledThread = (myGroupAndInvokeCount != null);
boolean replaceMe = false; boolean replaceMe = false;
Event ev; Event ev;
try { try {
for (;;) { for (;;) {
// reset invoke count // reset invoke count
if (myGroupAndInvokeCount != null) if (isPooledThread)
myGroupAndInvokeCount.resetInvokeCount(); myGroupAndInvokeCount.resetInvokeCount();
try { try {
...@@ -289,7 +290,7 @@ final class EPollPort ...@@ -289,7 +290,7 @@ final class EPollPort
// process event // process event
try { try {
ev.channel().onEvent(ev.events()); ev.channel().onEvent(ev.events(), isPooledThread);
} catch (Error x) { } catch (Error x) {
replaceMe = true; throw x; replaceMe = true; throw x;
} catch (RuntimeException x) { } catch (RuntimeException x) {
......
...@@ -49,7 +49,7 @@ abstract class Port extends AsynchronousChannelGroupImpl { ...@@ -49,7 +49,7 @@ abstract class Port extends AsynchronousChannelGroupImpl {
* Implemented by clients registered with this port. * Implemented by clients registered with this port.
*/ */
interface PollableChannel extends Closeable { interface PollableChannel extends Closeable {
void onEvent(int events); void onEvent(int events, boolean mayInvokeDirect);
} }
// maps fd to "pollable" channel // maps fd to "pollable" channel
...@@ -121,7 +121,7 @@ abstract class Port extends AsynchronousChannelGroupImpl { ...@@ -121,7 +121,7 @@ abstract class Port extends AsynchronousChannelGroupImpl {
final Object attachForeignChannel(final Channel channel, FileDescriptor fd) { final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
int fdVal = IOUtil.fdVal(fd); int fdVal = IOUtil.fdVal(fd);
register(fdVal, new PollableChannel() { register(fdVal, new PollableChannel() {
public void onEvent(int events) { } public void onEvent(int events, boolean mayInvokeDirect) { }
public void close() throws IOException { public void close() throws IOException {
channel.close(); channel.close();
} }
......
...@@ -151,12 +151,13 @@ class SolarisEventPort ...@@ -151,12 +151,13 @@ class SolarisEventPort
public void run() { public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount(); Invoker.getGroupAndInvokeCount();
final boolean isPooledThread = (myGroupAndInvokeCount != null);
boolean replaceMe = false; boolean replaceMe = false;
long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT); long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
try { try {
for (;;) { for (;;) {
// reset invoke count // reset invoke count
if (myGroupAndInvokeCount != null) if (isPooledThread)
myGroupAndInvokeCount.resetInvokeCount(); myGroupAndInvokeCount.resetInvokeCount();
// wait for I/O completion event // wait for I/O completion event
...@@ -205,7 +206,7 @@ class SolarisEventPort ...@@ -205,7 +206,7 @@ class SolarisEventPort
if (ch != null) { if (ch != null) {
replaceMe = true; replaceMe = true;
// no need to translate events // no need to translate events
ch.onEvent(events); ch.onEvent(events, isPooledThread);
} }
} }
} finally { } finally {
......
...@@ -59,10 +59,13 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -59,10 +59,13 @@ class UnixAsynchronousServerSocketChannelImpl
private final Object updateLock = new Object(); private final Object updateLock = new Object();
// pending accept // pending accept
private PendingFuture<AsynchronousSocketChannel,Object> pendingAccept; private boolean acceptPending;
private CompletionHandler<AsynchronousSocketChannel,Object> acceptHandler;
private Object acceptAttachment;
private PendingFuture<AsynchronousSocketChannel,Object> acceptFuture;
// context for permission check when security manager set // context for permission check when security manager set
private AccessControlContext acc; private AccessControlContext acceptAcc;
UnixAsynchronousServerSocketChannelImpl(Port port) UnixAsynchronousServerSocketChannelImpl(Port port)
...@@ -83,15 +86,6 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -83,15 +86,6 @@ class UnixAsynchronousServerSocketChannelImpl
port.register(fdVal, this); port.register(fdVal, this);
} }
// returns and clears the result of a pending accept
private PendingFuture<AsynchronousSocketChannel,Object> grabPendingAccept() {
synchronized (updateLock) {
PendingFuture<AsynchronousSocketChannel,Object> result = pendingAccept;
pendingAccept = null;
return result;
}
}
@Override @Override
void implClose() throws IOException { void implClose() throws IOException {
// remove the mapping // remove the mapping
...@@ -101,17 +95,27 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -101,17 +95,27 @@ class UnixAsynchronousServerSocketChannelImpl
nd.close(fd); nd.close(fd);
// if there is a pending accept then complete it // if there is a pending accept then complete it
final PendingFuture<AsynchronousSocketChannel,Object> result = CompletionHandler<AsynchronousSocketChannel,Object> handler;
grabPendingAccept(); Object att;
if (result != null) { PendingFuture<AsynchronousSocketChannel,Object> future;
synchronized (updateLock) {
if (!acceptPending)
return; // no pending accept
acceptPending = false;
handler = acceptHandler;
att = acceptAttachment;
future = acceptFuture;
}
// discard the stack trace as otherwise it may appear that implClose // discard the stack trace as otherwise it may appear that implClose
// has thrown the exception. // has thrown the exception.
AsynchronousCloseException x = new AsynchronousCloseException(); AsynchronousCloseException x = new AsynchronousCloseException();
x.setStackTrace(new StackTraceElement[0]); x.setStackTrace(new StackTraceElement[0]);
result.setFailure(x); if (handler == null) {
future.setFailure(x);
} else {
// invoke by submitting task rather than directly // invoke by submitting task rather than directly
Invoker.invokeIndirectly(result.handler(), result); Invoker.invokeIndirectly(this, handler, att, null, x);
} }
} }
...@@ -124,15 +128,17 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -124,15 +128,17 @@ class UnixAsynchronousServerSocketChannelImpl
* Invoked by event handling thread when listener socket is polled * Invoked by event handling thread when listener socket is polled
*/ */
@Override @Override
public void onEvent(int events) { public void onEvent(int events, boolean mayInvokeDirect) {
PendingFuture<AsynchronousSocketChannel,Object> result = grabPendingAccept(); synchronized (updateLock) {
if (result == null) if (!acceptPending)
return; // may have been grabbed by asynchronous close return; // may have been grabbed by asynchronous close
acceptPending = false;
}
// attempt to accept connection // attempt to accept connection
FileDescriptor newfd = new FileDescriptor(); FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1]; InetSocketAddress[] isaa = new InetSocketAddress[1];
boolean accepted = false; Throwable exc = null;
try { try {
begin(); begin();
int n = accept0(this.fd, newfd, isaa); int n = accept0(this.fd, newfd, isaa);
...@@ -140,49 +146,52 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -140,49 +146,52 @@ class UnixAsynchronousServerSocketChannelImpl
// spurious wakeup, is this possible? // spurious wakeup, is this possible?
if (n == IOStatus.UNAVAILABLE) { if (n == IOStatus.UNAVAILABLE) {
synchronized (updateLock) { synchronized (updateLock) {
this.pendingAccept = result; acceptPending = true;
} }
port.startPoll(fdVal, Port.POLLIN); port.startPoll(fdVal, Port.POLLIN);
return; return;
} }
// connection accepted
accepted = true;
} catch (Throwable x) { } catch (Throwable x) {
if (x instanceof ClosedChannelException) if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
enableAccept(); exc = x;
result.setFailure(x);
} finally { } finally {
end(); end();
} }
// Connection accepted so finish it when not holding locks. // Connection accepted so finish it when not holding locks.
AsynchronousSocketChannel child = null; AsynchronousSocketChannel child = null;
if (accepted) { if (exc == null) {
try { try {
child = finishAccept(newfd, isaa[0], acc); child = finishAccept(newfd, isaa[0], acceptAcc);
enableAccept();
result.setResult(child);
} catch (Throwable x) { } catch (Throwable x) {
enableAccept();
if (!(x instanceof IOException) && !(x instanceof SecurityException)) if (!(x instanceof IOException) && !(x instanceof SecurityException))
x = new IOException(x); x = new IOException(x);
result.setFailure(x); exc = x;
} }
} }
// copy field befores accept is re-renabled
CompletionHandler<AsynchronousSocketChannel,Object> handler = acceptHandler;
Object att = acceptAttachment;
PendingFuture<AsynchronousSocketChannel,Object> future = acceptFuture;
// re-enable accepting and invoke handler
enableAccept();
if (handler == null) {
future.setResult(child, exc);
// if an async cancel has already cancelled the operation then // if an async cancel has already cancelled the operation then
// close the new channel so as to free resources // close the new channel so as to free resources
if (child != null && result.isCancelled()) { if (child != null && future.isCancelled()) {
try { try {
child.close(); child.close();
} catch (IOException ignore) { } } catch (IOException ignore) { }
} }
} else {
// invoke the handler Invoker.invoke(this, handler, att, child, exc);
Invoker.invoke(result.handler(), result); }
} }
/** /**
...@@ -234,16 +243,18 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -234,16 +243,18 @@ class UnixAsynchronousServerSocketChannelImpl
} }
@Override @Override
@SuppressWarnings("unchecked") Future<AsynchronousSocketChannel> implAccept(Object att,
public <A> Future<AsynchronousSocketChannel> accept(A attachment, CompletionHandler<AsynchronousSocketChannel,Object> handler)
final CompletionHandler<AsynchronousSocketChannel,? super A> handler)
{ {
// complete immediately if channel is closed // complete immediately if channel is closed
if (!isOpen()) { if (!isOpen()) {
CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture Throwable e = new ClosedChannelException();
.withFailure(this, new ClosedChannelException(), attachment); if (handler == null) {
Invoker.invokeIndirectly(handler, result); return CompletedFuture.withFailure(e);
return result; } else {
Invoker.invoke(this, handler, att, null, e);
return null;
}
} }
if (localAddress == null) if (localAddress == null)
throw new NotYetBoundException(); throw new NotYetBoundException();
...@@ -258,25 +269,31 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -258,25 +269,31 @@ class UnixAsynchronousServerSocketChannelImpl
throw new AcceptPendingException(); throw new AcceptPendingException();
// attempt accept // attempt accept
AbstractFuture<AsynchronousSocketChannel,A> result = null;
FileDescriptor newfd = new FileDescriptor(); FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1]; InetSocketAddress[] isaa = new InetSocketAddress[1];
Throwable exc = null;
try { try {
begin(); begin();
int n = accept0(this.fd, newfd, isaa); int n = accept0(this.fd, newfd, isaa);
if (n == IOStatus.UNAVAILABLE) { if (n == IOStatus.UNAVAILABLE) {
// no connection to accept
result = new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment);
// need calling context when there is security manager as // need calling context when there is security manager as
// permission check may be done in a different thread without // permission check may be done in a different thread without
// any application call frames on the stack // any application call frames on the stack
synchronized (this) { PendingFuture<AsynchronousSocketChannel,Object> result = null;
this.acc = (System.getSecurityManager() == null) ? synchronized (updateLock) {
if (handler == null) {
this.acceptHandler = null;
result = new PendingFuture<AsynchronousSocketChannel,Object>(this);
this.acceptFuture = result;
} else {
this.acceptHandler = handler;
this.acceptAttachment = att;
}
this.acceptAcc = (System.getSecurityManager() == null) ?
null : AccessController.getContext(); null : AccessController.getContext();
this.pendingAccept = this.acceptPending = true;
(PendingFuture<AsynchronousSocketChannel,Object>)result;
} }
// register for connections // register for connections
...@@ -287,25 +304,30 @@ class UnixAsynchronousServerSocketChannelImpl ...@@ -287,25 +304,30 @@ class UnixAsynchronousServerSocketChannelImpl
// accept failed // accept failed
if (x instanceof ClosedChannelException) if (x instanceof ClosedChannelException)
x = new AsynchronousCloseException(); x = new AsynchronousCloseException();
result = CompletedFuture.withFailure(this, x, attachment); exc = x;
} finally { } finally {
end(); end();
} }
AsynchronousSocketChannel child = null;
if (exc == null) {
// connection accepted immediately // connection accepted immediately
if (result == null) {
try { try {
AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null); child = finishAccept(newfd, isaa[0], null);
result = CompletedFuture.withResult(this, ch, attachment);
} catch (Throwable x) { } catch (Throwable x) {
result = CompletedFuture.withFailure(this, x, attachment); exc = x;
} }
} }
// re-enable accepting and invoke handler // re-enable accepting before invoking handler
enableAccept(); enableAccept();
Invoker.invokeIndirectly(handler, result);
return result; if (handler == null) {
return CompletedFuture.withResult(child, exc);
} else {
Invoker.invokeIndirectly(this, handler, att, child, exc);
return null;
}
} }
// -- Native methods -- // -- Native methods --
......
...@@ -65,9 +65,6 @@ class UnixPath ...@@ -65,9 +65,6 @@ class UnixPath
// array of offsets of elements in path (created lazily) // array of offsets of elements in path (created lazily)
private volatile int[] offsets; private volatile int[] offsets;
// file permissions (created lazily)
private volatile FilePermission[] perms;
UnixPath(UnixFileSystem fs, byte[] path) { UnixPath(UnixFileSystem fs, byte[] path) {
this.fs = fs; this.fs = fs;
this.path = path; this.path = path;
...@@ -768,46 +765,24 @@ class UnixPath ...@@ -768,46 +765,24 @@ class UnixPath
} }
} }
// create file permissions used for read and write checks
private void checkReadOrWrite(boolean checkRead) {
SecurityManager sm = System.getSecurityManager();
if (sm == null)
return;
if (perms == null) {
synchronized (this) {
if (perms == null) {
FilePermission[] p = new FilePermission[2];
String pathForPermCheck = getPathForPermissionCheck();
p[0] = new FilePermission(pathForPermCheck,
SecurityConstants.FILE_READ_ACTION);
p[1] = new FilePermission(pathForPermCheck,
SecurityConstants.FILE_WRITE_ACTION);
perms = p;
}
}
}
if (checkRead) {
sm.checkPermission(perms[0]);
} else {
sm.checkPermission(perms[1]);
}
}
void checkRead() { void checkRead() {
checkReadOrWrite(true); SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkRead(getPathForPermissionCheck());
} }
void checkWrite() { void checkWrite() {
checkReadOrWrite(false); SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkWrite(getPathForPermissionCheck());
} }
void checkDelete() { void checkDelete() {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null)
// permission not cached
sm.checkDelete(getPathForPermissionCheck()); sm.checkDelete(getPathForPermissionCheck());
} }
}
@Override @Override
public FileStore getFileStore() public FileStore getFileStore()
......
...@@ -34,6 +34,8 @@ import java.util.*; ...@@ -34,6 +34,8 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.security.AccessController;
import sun.security.action.GetPropertyAction;
import sun.misc.Unsafe; import sun.misc.Unsafe;
/** /**
...@@ -44,6 +46,7 @@ import sun.misc.Unsafe; ...@@ -44,6 +46,7 @@ import sun.misc.Unsafe;
class Iocp extends AsynchronousChannelGroupImpl { class Iocp extends AsynchronousChannelGroupImpl {
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long INVALID_HANDLE_VALUE = -1L; private static final long INVALID_HANDLE_VALUE = -1L;
private static final boolean supportsThreadAgnosticIo;
// maps completion key to channel // maps completion key to channel
private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock(); private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock();
...@@ -87,6 +90,13 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -87,6 +90,13 @@ class Iocp extends AsynchronousChannelGroupImpl {
<V,A> PendingFuture<V,A> getByOverlapped(long overlapped); <V,A> PendingFuture<V,A> getByOverlapped(long overlapped);
} }
/**
* Indicates if this operating system supports thread agnostic I/O.
*/
static boolean supportsThreadAgnosticIo() {
return supportsThreadAgnosticIo;
}
// release all resources // release all resources
void implClose() { void implClose() {
synchronized (this) { synchronized (this) {
...@@ -216,8 +226,9 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -216,8 +226,9 @@ class Iocp extends AsynchronousChannelGroupImpl {
} while ((key == 0) || keyToChannel.containsKey(key)); } while ((key == 0) || keyToChannel.containsKey(key));
// associate with I/O completion port // associate with I/O completion port
if (handle != 0L) if (handle != 0L) {
createIoCompletionPort(handle, port, key, 0); createIoCompletionPort(handle, port, key, 0);
}
// setup mapping // setup mapping
keyToChannel.put(key, ch); keyToChannel.put(key, ch);
...@@ -282,7 +293,7 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -282,7 +293,7 @@ class Iocp extends AsynchronousChannelGroupImpl {
/** /**
* Invoked if the I/O operation completes successfully. * Invoked if the I/O operation completes successfully.
*/ */
public void completed(int bytesTransferred); public void completed(int bytesTransferred, boolean canInvokeDirect);
/** /**
* Invoked if the I/O operation fails. * Invoked if the I/O operation fails.
...@@ -305,6 +316,7 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -305,6 +316,7 @@ class Iocp extends AsynchronousChannelGroupImpl {
public void run() { public void run() {
Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
Invoker.getGroupAndInvokeCount(); Invoker.getGroupAndInvokeCount();
boolean canInvokeDirect = (myGroupAndInvokeCount != null);
CompletionStatus ioResult = new CompletionStatus(); CompletionStatus ioResult = new CompletionStatus();
boolean replaceMe = false; boolean replaceMe = false;
...@@ -382,7 +394,7 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -382,7 +394,7 @@ class Iocp extends AsynchronousChannelGroupImpl {
ResultHandler rh = (ResultHandler)result.getContext(); ResultHandler rh = (ResultHandler)result.getContext();
replaceMe = true; // (if error/exception then replace thread) replaceMe = true; // (if error/exception then replace thread)
if (error == 0) { if (error == 0) {
rh.completed(ioResult.bytesTransferred()); rh.completed(ioResult.bytesTransferred(), canInvokeDirect);
} else { } else {
rh.failed(error, translateErrorToIOException(error)); rh.failed(error, translateErrorToIOException(error));
} }
...@@ -433,5 +445,11 @@ class Iocp extends AsynchronousChannelGroupImpl { ...@@ -433,5 +445,11 @@ class Iocp extends AsynchronousChannelGroupImpl {
static { static {
Util.load(); Util.load();
initIDs(); initIDs();
// thread agnostic I/O on Vista/2008 or newer
String osversion = AccessController.doPrivileged(
new GetPropertyAction("os.version"));
String vers[] = osversion.split("\\.");
supportsThreadAgnosticIo = Integer.parseInt(vers[0]) >= 6;
} }
} }
...@@ -113,14 +113,14 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -113,14 +113,14 @@ class WindowsAsynchronousServerSocketChannelImpl
/** /**
* Task to initiate accept operation and to handle result. * Task to initiate accept operation and to handle result.
*/ */
private class AcceptTask<A> implements Runnable, Iocp.ResultHandler { private class AcceptTask implements Runnable, Iocp.ResultHandler {
private final WindowsAsynchronousSocketChannelImpl channel; private final WindowsAsynchronousSocketChannelImpl channel;
private final AccessControlContext acc; private final AccessControlContext acc;
private final PendingFuture<AsynchronousSocketChannel,A> result; private final PendingFuture<AsynchronousSocketChannel,Object> result;
AcceptTask(WindowsAsynchronousSocketChannelImpl channel, AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
AccessControlContext acc, AccessControlContext acc,
PendingFuture<AsynchronousSocketChannel,A> result) PendingFuture<AsynchronousSocketChannel,Object> result)
{ {
this.channel = channel; this.channel = channel;
this.acc = acc; this.acc = acc;
...@@ -222,14 +222,14 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -222,14 +222,14 @@ class WindowsAsynchronousServerSocketChannelImpl
} }
// invoke completion handler // invoke completion handler
Invoker.invokeIndirectly(result.handler(), result); Invoker.invokeIndirectly(result);
} }
/** /**
* Executed when the I/O has completed * Executed when the I/O has completed
*/ */
@Override @Override
public void completed(int bytesTransferred) { public void completed(int bytesTransferred, boolean canInvokeDirect) {
try { try {
// connection accept after group has shutdown // connection accept after group has shutdown
if (iocp.isShutdown()) { if (iocp.isShutdown()) {
...@@ -269,7 +269,7 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -269,7 +269,7 @@ class WindowsAsynchronousServerSocketChannelImpl
} }
// invoke handler (but not directly) // invoke handler (but not directly)
Invoker.invokeIndirectly(result.handler(), result); Invoker.invokeIndirectly(result);
} }
@Override @Override
...@@ -283,19 +283,20 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -283,19 +283,20 @@ class WindowsAsynchronousServerSocketChannelImpl
} else { } else {
result.setFailure(new AsynchronousCloseException()); result.setFailure(new AsynchronousCloseException());
} }
Invoker.invokeIndirectly(result.handler(), result); Invoker.invokeIndirectly(result);
} }
} }
@Override @Override
public <A> Future<AsynchronousSocketChannel> accept(A attachment, Future<AsynchronousSocketChannel> implAccept(Object attachment,
final CompletionHandler<AsynchronousSocketChannel,? super A> handler) final CompletionHandler<AsynchronousSocketChannel,Object> handler)
{ {
if (!isOpen()) { if (!isOpen()) {
CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture Throwable exc = new ClosedChannelException();
.withFailure(this, new ClosedChannelException(), attachment); if (handler == null)
Invoker.invokeIndirectly(handler, result); return CompletedFuture.withFailure(exc);
return result; Invoker.invokeIndirectly(this, handler, attachment, null, exc);
return null;
} }
if (isAcceptKilled()) if (isAcceptKilled())
throw new RuntimeException("Accept not allowed due to cancellation"); throw new RuntimeException("Accept not allowed due to cancellation");
...@@ -319,10 +320,10 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -319,10 +320,10 @@ class WindowsAsynchronousServerSocketChannelImpl
end(); end();
} }
if (ioe != null) { if (ioe != null) {
CompletedFuture<AsynchronousSocketChannel,A> result = if (handler == null)
CompletedFuture.withFailure(this, ioe, attachment); return CompletedFuture.withFailure(ioe);
Invoker.invokeIndirectly(handler, result); Invoker.invokeIndirectly(this, handler, attachment, null, ioe);
return result; return null;
} }
// need calling context when there is security manager as // need calling context when there is security manager as
...@@ -331,20 +332,21 @@ class WindowsAsynchronousServerSocketChannelImpl ...@@ -331,20 +332,21 @@ class WindowsAsynchronousServerSocketChannelImpl
AccessControlContext acc = (System.getSecurityManager() == null) ? AccessControlContext acc = (System.getSecurityManager() == null) ?
null : AccessController.getContext(); null : AccessController.getContext();
PendingFuture<AsynchronousSocketChannel,A> result = PendingFuture<AsynchronousSocketChannel,Object> result =
new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment); new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);
AcceptTask task = new AcceptTask<A>(ch, acc, result); AcceptTask task = new AcceptTask(ch, acc, result);
result.setContext(task); result.setContext(task);
// check and set flag to prevent concurrent accepting // check and set flag to prevent concurrent accepting
if (!accepting.compareAndSet(false, true)) if (!accepting.compareAndSet(false, true))
throw new AcceptPendingException(); throw new AcceptPendingException();
// initiate accept. As I/O operations are tied to the initiating thread // initiate I/O
// then it will only be invoked direcly if this thread is in the thread if (Iocp.supportsThreadAgnosticIo()) {
// pool. If this thread is not in the thread pool when a task is task.run();
// submitted to initiate the accept. } else {
Invoker.invokeOnThreadInThreadPool(this, task); Invoker.invokeOnThreadInThreadPool(this, task);
}
return result; return result;
} }
......
...@@ -46,6 +46,7 @@ class WindowsFileAttributeViews { ...@@ -46,6 +46,7 @@ class WindowsFileAttributeViews {
@Override @Override
public WindowsFileAttributes readAttributes() throws IOException { public WindowsFileAttributes readAttributes() throws IOException {
file.checkRead();
try { try {
return WindowsFileAttributes.get(file, followLinks); return WindowsFileAttributes.get(file, followLinks);
} catch (WindowsException x) { } catch (WindowsException x) {
......
...@@ -246,8 +246,8 @@ class WindowsFileAttributes ...@@ -246,8 +246,8 @@ class WindowsFileAttributes
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? int reparseTag = isReparsePoint(fileAttrs) ?
+ unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
return new WindowsFileAttributes(fileAttrs, return new WindowsFileAttributes(fileAttrs,
creationTime, creationTime,
lastAccessTime, lastAccessTime,
...@@ -275,7 +275,7 @@ class WindowsFileAttributes ...@@ -275,7 +275,7 @@ class WindowsFileAttributes
int reparseTag = 0; int reparseTag = 0;
int fileAttrs = unsafe int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { if (isReparsePoint(fileAttrs)) {
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
try { try {
...@@ -311,7 +311,7 @@ class WindowsFileAttributes ...@@ -311,7 +311,7 @@ class WindowsFileAttributes
// just return the attributes // just return the attributes
int fileAttrs = unsafe int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) if (!isReparsePoint(fileAttrs))
return fromFileAttributeData(address, 0); return fromFileAttributeData(address, 0);
} catch (WindowsException x) { } catch (WindowsException x) {
if (x.lastError() != ERROR_SHARING_VIOLATION) if (x.lastError() != ERROR_SHARING_VIOLATION)
...@@ -358,7 +358,7 @@ class WindowsFileAttributes ...@@ -358,7 +358,7 @@ class WindowsFileAttributes
} }
/** /**
* Returns true if the attribtues are of the same file - both files must * Returns true if the attributes are of the same file - both files must
* be open. * be open.
*/ */
static boolean isSameFile(WindowsFileAttributes attrs1, static boolean isSameFile(WindowsFileAttributes attrs1,
...@@ -370,6 +370,13 @@ class WindowsFileAttributes ...@@ -370,6 +370,13 @@ class WindowsFileAttributes
(attrs1.fileIndexLow == attrs2.fileIndexLow); (attrs1.fileIndexLow == attrs2.fileIndexLow);
} }
/**
* Returns true if the attributes are of a file with a reparse point.
*/
static boolean isReparsePoint(int attributes) {
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
}
// package-private // package-private
int attributes() { int attributes() {
return fileAttrs; return fileAttrs;
...@@ -420,7 +427,7 @@ class WindowsFileAttributes ...@@ -420,7 +427,7 @@ class WindowsFileAttributes
// package private // package private
boolean isReparsePoint() { boolean isReparsePoint() {
return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; return isReparsePoint(fileAttrs);
} }
boolean isDirectoryLink() { boolean isDirectoryLink() {
......
...@@ -283,25 +283,15 @@ class WindowsFileSystem ...@@ -283,25 +283,15 @@ class WindowsFileSystem
} }
} }
// match in uppercase // match in unicode_case_insensitive
StringBuilder sb = new StringBuilder(expr.length()); final Pattern pattern = Pattern.compile(expr,
for (int i=0; i<expr.length(); i++) { Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
sb.append(Character.toUpperCase(expr.charAt(i)));
}
expr = sb.toString();
// return matcher // return matcher
final Pattern pattern = Pattern.compile(expr);
return new PathMatcher() { return new PathMatcher() {
@Override @Override
public boolean matches(Path path) { public boolean matches(Path path) {
// match in uppercase return pattern.matcher(path.toString()).matches();
String s = path.toString();
StringBuilder sb = new StringBuilder(s.length());
for (int i=0; i<s.length(); i++) {
sb.append( Character.toUpperCase(s.charAt(i)) );
}
return pattern.matcher(sb).matches();
} }
}; };
} }
......
...@@ -180,10 +180,12 @@ class WindowsNativeDispatcher { ...@@ -180,10 +180,12 @@ class WindowsNativeDispatcher {
static class FirstFile { static class FirstFile {
private long handle; private long handle;
private String name; private String name;
private int attributes;
private FirstFile() { } private FirstFile() { }
public long handle() { return handle; } public long handle() { return handle; }
public String name() { return name; } public String name() { return name; }
public int attributes() { return attributes; }
} }
private static native void FindFirstFile0(long lpFileName, FirstFile obj) private static native void FindFirstFile0(long lpFileName, FirstFile obj)
throws WindowsException; throws WindowsException;
......
...@@ -58,6 +58,16 @@ Java_sun_nio_ch_Iocp_initIDs(JNIEnv* env, jclass this) ...@@ -58,6 +58,16 @@ Java_sun_nio_ch_Iocp_initIDs(JNIEnv* env, jclass this)
completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J"); completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J");
} }
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Iocp_osMajorVersion(JNIEnv* env, jclass this)
{
OSVERSIONINFOEX ver;
ver.dwOSVersionInfoSize = sizeof(ver);
GetVersionEx((OSVERSIONINFO *) &ver);
return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ?
(jint)(ver.dwMajorVersion) : (jint)0;
}
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this, Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this,
jlong handle, jlong existingPort, jint completionKey, jint concurrency) jlong handle, jlong existingPort, jint completionKey, jint concurrency)
......
此差异已折叠。
此差异已折叠。
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
*/ */
/* @test /* @test
* @bug 4607272 * @bug 4607272 6842687
* @summary Unit test for AsynchronousChannelGroup * @summary Unit test for AsynchronousChannelGroup
* @build Restart * @build Restart
* @run main/othervm -XX:-UseVMInterruptibleIO Restart * @run main/othervm -XX:-UseVMInterruptibleIO Restart
...@@ -111,8 +111,6 @@ public class Restart { ...@@ -111,8 +111,6 @@ public class Restart {
} }
public void failed(Throwable exc, Void att) { public void failed(Throwable exc, Void att) {
} }
public void cancelled(Void att) {
}
}); });
// establish loopback connection which should cause completion // establish loopback connection which should cause completion
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册