From b908f575d5460791182c1e53d01c803b57ff5134 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 4 Jun 2010 15:37:22 -0600 Subject: [PATCH] fix several blocking SocketChannel bugs In java-nio.cpp, we can't use GetPrimitiveArrayCritical when reading from or writing to blocking sockets since it may block the rest of the VM indefinitely. In SelectableChannel.java, we can't use a null test on SelectableChannel.key to determine whether the channel is open since it might never be registered with a Selector. According to the Sun documentation, a SelectableChannel is open as soon as it's created, so that's what we now implement. --- classpath/java-nio.cpp | 60 +++++++++++++++---- .../java/nio/channels/SelectableChannel.java | 8 +-- .../java/nio/channels/SocketChannel.java | 8 +-- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 540cb89364..4b052d98b1 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -428,13 +428,32 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e, jint socket, jbyteArray buffer, jint offset, - jint length) + jint length, + jboolean blocking) { - jboolean isCopy; - uint8_t *buf = static_cast - (e->GetPrimitiveArrayCritical(buffer, &isCopy)); - int r = ::doRead(socket, buf + offset, length); - e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + int r; + if (blocking) { + uint8_t* buf = static_cast(allocate(e, length)); + if (buf) { + r = ::doRead(socket, buf, length); + if (r > 0) { + e->SetByteArrayRegion + (buffer, offset, r, reinterpret_cast(buf)); + } + free(buf); + } else { + return 0; + } + } else { + jboolean isCopy; + uint8_t* buf = static_cast + (e->GetPrimitiveArrayCritical(buffer, &isCopy)); + + r = ::doRead(socket, buf + offset, length); + + e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + } + if (r < 0) { if (eagain()) { return 0; @@ -453,13 +472,30 @@ Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e, jint socket, jbyteArray buffer, jint offset, - jint length) + jint length, + jboolean blocking) { - jboolean isCopy; - uint8_t *buf = static_cast - (e->GetPrimitiveArrayCritical(buffer, &isCopy)); - int r = ::doWrite(socket, buf + offset, length); - e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + int r; + if (blocking) { + uint8_t* buf = static_cast(allocate(e, length)); + if (buf) { + e->GetByteArrayRegion + (buffer, offset, length, reinterpret_cast(buf)); + r = ::doWrite(socket, buf, length); + free(buf); + } else { + return 0; + } + } else { + jboolean isCopy; + uint8_t* buf = static_cast + (e->GetPrimitiveArrayCritical(buffer, &isCopy)); + + r = ::doWrite(socket, buf + offset, length); + + e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + } + if (r < 0) { if (eagain()) { return 0; diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index 126dc9d935..7cec3b69aa 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -15,6 +15,7 @@ import java.nio.ByteBuffer; public abstract class SelectableChannel implements Channel { private SelectionKey key; + private boolean open = true; abstract int socketFD(); @@ -30,12 +31,11 @@ public abstract class SelectableChannel implements Channel { } public boolean isOpen() { - return key != null; + return open; } public void close() throws IOException { - if (key != null) { - key = null; - } + open = false; + key = null; } } diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index 809142a56f..25da62684c 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -92,7 +92,7 @@ public class SocketChannel extends SelectableChannel byte[] array = b.array(); if (array == null) throw new NullPointerException(); - int r = natRead(socket, array, b.arrayOffset() + b.position(), b.remaining()); + int r = natRead(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); if (r > 0) { b.position(b.position() + r); } @@ -108,7 +108,7 @@ public class SocketChannel extends SelectableChannel byte[] array = b.array(); if (array == null) throw new NullPointerException(); - int w = natWrite(socket, array, b.arrayOffset() + b.position(), b.remaining()); + int w = natWrite(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); if (w > 0) { b.position(b.position() + w); } @@ -139,9 +139,9 @@ public class SocketChannel extends SelectableChannel throws IOException; private static native boolean natFinishConnect(int socket) throws IOException; - private static native int natRead(int socket, byte[] buffer, int offset, int length) + private static native int natRead(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; - private static native int natWrite(int socket, byte[] buffer, int offset, int length) + private static native int natWrite(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; private static native void natThrowWriteError(int socket) throws IOException; private static native void natCloseSocket(int socket);