6878369: (ch) AsynchronousSocketChannel read/write methods that specify timeouts should not throw IAE
authoralanb
Wed, 24 Nov 2010 09:51:31 +0000
changeset 7298 895772293d6e
parent 7297 906c58a8b849
child 7299 0b68a82ebb55
child 7300 6a391a0ed0da
child 7515 43202796198e
6878369: (ch) AsynchronousSocketChannel read/write methods that specify timeouts should not throw IAE Reviewed-by: forax
jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java
jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java
--- a/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Tue Nov 23 16:52:39 2010 -0800
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Wed Nov 24 09:51:31 2010 +0000
@@ -110,7 +110,8 @@
  * state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O
  * operation is not defined. Buffers should be discarded or at least care must
  * be taken to ensure that the buffers are not accessed while the channel remains
- * open.
+ * open. All methods that accept timeout parameters treat values less than or
+ * equal to zero to mean that the I/O operation does not timeout.
  *
  * @since 1.7
  */
@@ -367,7 +368,7 @@
      * @param   dst
      *          The buffer into which bytes are to be transferred
      * @param   timeout
-     *          The timeout, or {@code 0L} for no timeout
+     *          The maximum time for the I/O operation to complete
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
@@ -376,8 +377,7 @@
      *          The handler for consuming the result
      *
      * @throws  IllegalArgumentException
-     *          If the {@code timeout} parameter is negative or the buffer is
-     *          read-only
+     *          If the buffer is read-only
      * @throws  ReadPendingException
      *          If a read operation is already in progress on this channel
      * @throws  NotYetConnectedException
@@ -471,7 +471,7 @@
      *          The maximum number of buffers to be accessed; must be non-negative
      *          and no larger than {@code dsts.length - offset}
      * @param   timeout
-     *          The timeout, or {@code 0L} for no timeout
+     *          The maximum time for the I/O operation to complete
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
@@ -483,8 +483,7 @@
      *          If the pre-conditions for the {@code offset}  and {@code length}
      *          parameter aren't met
      * @throws  IllegalArgumentException
-     *          If the {@code timeout} parameter is negative, or a buffer is
-     *          read-only
+     *          If the buffer is read-only
      * @throws  ReadPendingException
      *          If a read operation is already in progress on this channel
      * @throws  NotYetConnectedException
@@ -524,7 +523,7 @@
      * @param   src
      *          The buffer from which bytes are to be retrieved
      * @param   timeout
-     *          The timeout, or {@code 0L} for no timeout
+     *          The maximum time for the I/O operation to complete
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
@@ -532,8 +531,6 @@
      * @param   handler
      *          The handler for consuming the result
      *
-     * @throws  IllegalArgumentException
-     *          If the {@code timeout} parameter is negative
      * @throws  WritePendingException
      *          If a write operation is already in progress on this channel
      * @throws  NotYetConnectedException
@@ -623,7 +620,7 @@
      *          The maximum number of buffers to be accessed; must be non-negative
      *          and no larger than {@code srcs.length - offset}
      * @param   timeout
-     *          The timeout, or {@code 0L} for no timeout
+     *          The maximum time for the I/O operation to complete
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
@@ -634,8 +631,6 @@
      * @throws  IndexOutOfBoundsException
      *          If the pre-conditions for the {@code offset}  and {@code length}
      *          parameter aren't met
-     * @throws  IllegalArgumentException
-     *          If the {@code timeout} parameter is negative
      * @throws  WritePendingException
      *          If a write operation is already in progress on this channel
      * @throws  NotYetConnectedException
--- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Tue Nov 23 16:52:39 2010 -0800
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Wed Nov 24 09:51:31 2010 +0000
@@ -235,8 +235,6 @@
 
         if (remoteAddress == null)
             throw new NotYetConnectedException();
-        if (timeout < 0L)
-            throw new IllegalArgumentException("Negative timeout");
 
         boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
         boolean shutdown = false;
@@ -342,8 +340,6 @@
         if (isOpen()) {
             if (remoteAddress == null)
                 throw new NotYetConnectedException();
-             if (timeout < 0L)
-                throw new IllegalArgumentException("Negative timeout");
             // check and update state
             synchronized (writeLock) {
                 if (writeKilled)
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Tue Nov 23 16:52:39 2010 -0800
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Wed Nov 24 09:51:31 2010 +0000
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4607272 6842687
+ * @bug 4607272 6842687 6878369
  * @summary Unit test for AsynchronousSocketChannel
  * @run main/timeout=600 Basic
  */
@@ -712,52 +712,57 @@
     }
 
     static void testTimeout() throws Exception {
+        System.out.println("-- timeouts --");
+        testTimeout(Integer.MIN_VALUE, TimeUnit.SECONDS);
+        testTimeout(-1L, TimeUnit.SECONDS);
+        testTimeout(0L, TimeUnit.SECONDS);
+        testTimeout(2L, TimeUnit.SECONDS);
+    }
+
+    static void testTimeout(final long timeout, final TimeUnit unit) throws Exception {
         Server server = new Server();
         AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
         ch.connect(server.address()).get();
 
-        System.out.println("-- timeout when reading --");
-
         ByteBuffer dst = ByteBuffer.allocate(512);
 
         final AtomicReference<Throwable> readException = new AtomicReference<Throwable>();
 
-        // this read should timeout
-        ch.read(dst, 3, TimeUnit.SECONDS, (Void)null,
-            new CompletionHandler<Integer,Void>()
-        {
+        // this read should timeout if value is > 0
+        ch.read(dst, timeout, unit, null, new CompletionHandler<Integer,Void>() {
             public void completed(Integer result, Void att) {
-                throw new RuntimeException("Should not complete");
+                readException.set(new RuntimeException("Should not complete"));
             }
             public void failed(Throwable exc, Void att) {
                 readException.set(exc);
             }
         });
-        // wait for exception
-        while (readException.get() == null) {
-            Thread.sleep(100);
-        }
-        if (!(readException.get() instanceof InterruptedByTimeoutException))
-            throw new RuntimeException("InterruptedByTimeoutException expected");
+        if (timeout > 0L) {
+            // wait for exception
+            while (readException.get() == null) {
+                Thread.sleep(100);
+            }
+            if (!(readException.get() instanceof InterruptedByTimeoutException))
+                throw new RuntimeException("InterruptedByTimeoutException expected");
 
-        // after a timeout then further reading should throw unspecified runtime exception
-        boolean exceptionThrown = false;
-        try {
-            ch.read(dst);
-        } catch (RuntimeException x) {
-            exceptionThrown = true;
+            // after a timeout then further reading should throw unspecified runtime exception
+            boolean exceptionThrown = false;
+            try {
+                ch.read(dst);
+            } catch (RuntimeException x) {
+                exceptionThrown = true;
+            }
+            if (!exceptionThrown)
+                throw new RuntimeException("RuntimeException expected after timeout.");
+        } else {
+            Thread.sleep(1000);
+            Throwable exc = readException.get();
+            if (exc != null)
+                throw new RuntimeException(exc);
         }
-        if (!exceptionThrown)
-            throw new RuntimeException("RuntimeException expected after timeout.");
-
-
-        System.out.println("-- timeout when writing --");
 
         final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
 
-        final long timeout = 5;
-        final TimeUnit unit = TimeUnit.SECONDS;
-
         // write bytes to fill socket buffer
         ch.write(genBuffer(), timeout, unit, ch,
             new CompletionHandler<Integer,AsynchronousSocketChannel>()
@@ -769,24 +774,32 @@
                 writeException.set(exc);
             }
         });
-
-        // wait for exception
-        while (writeException.get() == null) {
-            Thread.sleep(100);
-        }
-        if (!(writeException.get() instanceof InterruptedByTimeoutException))
-            throw new RuntimeException("InterruptedByTimeoutException expected");
+        if (timeout > 0) {
+            // wait for exception
+            while (writeException.get() == null) {
+                Thread.sleep(100);
+            }
+            if (!(writeException.get() instanceof InterruptedByTimeoutException))
+                throw new RuntimeException("InterruptedByTimeoutException expected");
 
-        // after a timeout then further writing should throw unspecified runtime exception
-        exceptionThrown = false;
-        try {
-            ch.write(genBuffer());
-        } catch (RuntimeException x) {
-            exceptionThrown = true;
+            // after a timeout then further writing should throw unspecified runtime exception
+            boolean exceptionThrown = false;
+            try {
+                ch.write(genBuffer());
+            } catch (RuntimeException x) {
+                exceptionThrown = true;
+            }
+            if (!exceptionThrown)
+                throw new RuntimeException("RuntimeException expected after timeout.");
+        } else {
+            Thread.sleep(1000);
+            Throwable exc = writeException.get();
+            if (exc != null)
+                throw new RuntimeException(exc);
         }
-        if (!exceptionThrown)
-            throw new RuntimeException("RuntimeException expected after timeout.");
 
+        // clean-up
+        server.accept().close();
         ch.close();
         server.close();
     }