6878369: (ch) AsynchronousSocketChannel read/write methods that specify timeouts should not throw IAE

Reviewed-by: forax
This commit is contained in:
Alan Bateman 2010-11-24 09:51:31 +00:00
parent fac39410b5
commit b6b4b5086c
3 changed files with 65 additions and 61 deletions

View File

@ -110,7 +110,8 @@ import java.nio.ByteBuffer;
* state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O * 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 * 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 * 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 * @since 1.7
*/ */
@ -367,7 +368,7 @@ public abstract class AsynchronousSocketChannel
* @param dst * @param dst
* The buffer into which bytes are to be transferred * The buffer into which bytes are to be transferred
* @param timeout * @param timeout
* The timeout, or {@code 0L} for no timeout * The maximum time for the I/O operation to complete
* @param unit * @param unit
* The time unit of the {@code timeout} argument * The time unit of the {@code timeout} argument
* @param attachment * @param attachment
@ -376,8 +377,7 @@ public abstract class AsynchronousSocketChannel
* The handler for consuming the result * The handler for consuming the result
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If the {@code timeout} parameter is negative or the buffer is * If the buffer is read-only
* read-only
* @throws ReadPendingException * @throws ReadPendingException
* If a read operation is already in progress on this channel * If a read operation is already in progress on this channel
* @throws NotYetConnectedException * @throws NotYetConnectedException
@ -471,7 +471,7 @@ public abstract class AsynchronousSocketChannel
* The maximum number of buffers to be accessed; must be non-negative * The maximum number of buffers to be accessed; must be non-negative
* and no larger than {@code dsts.length - offset} * and no larger than {@code dsts.length - offset}
* @param timeout * @param timeout
* The timeout, or {@code 0L} for no timeout * The maximum time for the I/O operation to complete
* @param unit * @param unit
* The time unit of the {@code timeout} argument * The time unit of the {@code timeout} argument
* @param attachment * @param attachment
@ -483,8 +483,7 @@ public abstract class AsynchronousSocketChannel
* If the pre-conditions for the {@code offset} and {@code length} * If the pre-conditions for the {@code offset} and {@code length}
* parameter aren't met * parameter aren't met
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If the {@code timeout} parameter is negative, or a buffer is * If the buffer is read-only
* read-only
* @throws ReadPendingException * @throws ReadPendingException
* If a read operation is already in progress on this channel * If a read operation is already in progress on this channel
* @throws NotYetConnectedException * @throws NotYetConnectedException
@ -524,7 +523,7 @@ public abstract class AsynchronousSocketChannel
* @param src * @param src
* The buffer from which bytes are to be retrieved * The buffer from which bytes are to be retrieved
* @param timeout * @param timeout
* The timeout, or {@code 0L} for no timeout * The maximum time for the I/O operation to complete
* @param unit * @param unit
* The time unit of the {@code timeout} argument * The time unit of the {@code timeout} argument
* @param attachment * @param attachment
@ -532,8 +531,6 @@ public abstract class AsynchronousSocketChannel
* @param handler * @param handler
* The handler for consuming the result * The handler for consuming the result
* *
* @throws IllegalArgumentException
* If the {@code timeout} parameter is negative
* @throws WritePendingException * @throws WritePendingException
* If a write operation is already in progress on this channel * If a write operation is already in progress on this channel
* @throws NotYetConnectedException * @throws NotYetConnectedException
@ -623,7 +620,7 @@ public abstract class AsynchronousSocketChannel
* The maximum number of buffers to be accessed; must be non-negative * The maximum number of buffers to be accessed; must be non-negative
* and no larger than {@code srcs.length - offset} * and no larger than {@code srcs.length - offset}
* @param timeout * @param timeout
* The timeout, or {@code 0L} for no timeout * The maximum time for the I/O operation to complete
* @param unit * @param unit
* The time unit of the {@code timeout} argument * The time unit of the {@code timeout} argument
* @param attachment * @param attachment
@ -634,8 +631,6 @@ public abstract class AsynchronousSocketChannel
* @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}
* parameter aren't met * parameter aren't met
* @throws IllegalArgumentException
* If the {@code timeout} parameter is negative
* @throws WritePendingException * @throws WritePendingException
* If a write operation is already in progress on this channel * If a write operation is already in progress on this channel
* @throws NotYetConnectedException * @throws NotYetConnectedException

View File

@ -235,8 +235,6 @@ abstract class AsynchronousSocketChannelImpl
if (remoteAddress == null) if (remoteAddress == null)
throw new NotYetConnectedException(); throw new NotYetConnectedException();
if (timeout < 0L)
throw new IllegalArgumentException("Negative timeout");
boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining(); boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
boolean shutdown = false; boolean shutdown = false;
@ -342,8 +340,6 @@ abstract class AsynchronousSocketChannelImpl
if (isOpen()) { if (isOpen()) {
if (remoteAddress == null) if (remoteAddress == null)
throw new NotYetConnectedException(); throw new NotYetConnectedException();
if (timeout < 0L)
throw new IllegalArgumentException("Negative timeout");
// check and update state // check and update state
synchronized (writeLock) { synchronized (writeLock) {
if (writeKilled) if (writeKilled)

View File

@ -22,7 +22,7 @@
*/ */
/* @test /* @test
* @bug 4607272 6842687 * @bug 4607272 6842687 6878369
* @summary Unit test for AsynchronousSocketChannel * @summary Unit test for AsynchronousSocketChannel
* @run main/timeout=600 Basic * @run main/timeout=600 Basic
*/ */
@ -712,27 +712,32 @@ public class Basic {
} }
static void testTimeout() throws Exception { 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(); Server server = new Server();
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(); AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
ch.connect(server.address()).get(); ch.connect(server.address()).get();
System.out.println("-- timeout when reading --");
ByteBuffer dst = ByteBuffer.allocate(512); ByteBuffer dst = ByteBuffer.allocate(512);
final AtomicReference<Throwable> readException = new AtomicReference<Throwable>(); final AtomicReference<Throwable> readException = new AtomicReference<Throwable>();
// this read should timeout // this read should timeout if value is > 0
ch.read(dst, 3, TimeUnit.SECONDS, (Void)null, ch.read(dst, timeout, unit, null, new CompletionHandler<Integer,Void>() {
new CompletionHandler<Integer,Void>()
{
public void completed(Integer result, Void att) { 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) { public void failed(Throwable exc, Void att) {
readException.set(exc); readException.set(exc);
} }
}); });
if (timeout > 0L) {
// wait for exception // wait for exception
while (readException.get() == null) { while (readException.get() == null) {
Thread.sleep(100); Thread.sleep(100);
@ -749,15 +754,15 @@ public class Basic {
} }
if (!exceptionThrown) if (!exceptionThrown)
throw new RuntimeException("RuntimeException expected after timeout."); throw new RuntimeException("RuntimeException expected after timeout.");
} else {
Thread.sleep(1000);
System.out.println("-- timeout when writing --"); Throwable exc = readException.get();
if (exc != null)
throw new RuntimeException(exc);
}
final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>(); final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
final long timeout = 5;
final TimeUnit unit = TimeUnit.SECONDS;
// write bytes to fill socket buffer // write bytes to fill socket buffer
ch.write(genBuffer(), timeout, unit, ch, ch.write(genBuffer(), timeout, unit, ch,
new CompletionHandler<Integer,AsynchronousSocketChannel>() new CompletionHandler<Integer,AsynchronousSocketChannel>()
@ -769,7 +774,7 @@ public class Basic {
writeException.set(exc); writeException.set(exc);
} }
}); });
if (timeout > 0) {
// wait for exception // wait for exception
while (writeException.get() == null) { while (writeException.get() == null) {
Thread.sleep(100); Thread.sleep(100);
@ -778,7 +783,7 @@ public class Basic {
throw new RuntimeException("InterruptedByTimeoutException expected"); throw new RuntimeException("InterruptedByTimeoutException expected");
// after a timeout then further writing should throw unspecified runtime exception // after a timeout then further writing should throw unspecified runtime exception
exceptionThrown = false; boolean exceptionThrown = false;
try { try {
ch.write(genBuffer()); ch.write(genBuffer());
} catch (RuntimeException x) { } catch (RuntimeException x) {
@ -786,7 +791,15 @@ public class Basic {
} }
if (!exceptionThrown) if (!exceptionThrown)
throw new RuntimeException("RuntimeException expected after timeout."); throw new RuntimeException("RuntimeException expected after timeout.");
} else {
Thread.sleep(1000);
Throwable exc = writeException.get();
if (exc != null)
throw new RuntimeException(exc);
}
// clean-up
server.accept().close();
ch.close(); ch.close();
server.close(); server.close();
} }