6878369: (ch) AsynchronousSocketChannel read/write methods that specify timeouts should not throw IAE
Reviewed-by: forax
--- 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();
}