summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2011-05-10 19:33:42 -0700
committerElliott Hughes <enh@google.com>2011-05-11 10:21:59 -0700
commita7bb29434692e01aed843b88cd042628bab74a23 (patch)
tree20274bfd8b0b5ea45e8f89570fae6b64f0a072ea
parent897b649912d132bef7e07c9f6612d0a3f880cec0 (diff)
downloadlibcore-a7bb29434692e01aed843b88cd042628bab74a23.zip
libcore-a7bb29434692e01aed843b88cd042628bab74a23.tar.gz
libcore-a7bb29434692e01aed843b88cd042628bab74a23.tar.bz2
Clean up the select(2) implementation.
I wasn't planning on touching this code (since I want to replace it), but the purported "fix" for http://code.google.com/p/android/issues/detail?id=6309 was actually a regression. The supplied test fails on the RI. This patch replaces the bogus test with new tests, and reverts the old "fix". This was found while trying to work out what "true" and "false" return values from OSNetworkSystem.select are supposed to mean. This patch also switches to a more traditional int return value. Bug: 3107501 Change-Id: Iddce55e081d440b7eb3ddcf94db7d0739dc89c70
-rw-r--r--dalvik/src/main/java/dalvik/system/BlockGuard.java6
-rw-r--r--luni/src/main/java/java/nio/SelectorImpl.java29
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java68
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java55
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp52
-rw-r--r--luni/src/test/java/libcore/java/nio/SelectorTest.java70
-rw-r--r--support/src/test/java/tests/net/StuckServer.java18
7 files changed, 100 insertions, 198 deletions
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index f3008c8..73ec3c7 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -233,11 +233,9 @@ public final class BlockGuard {
mNetwork.sendUrgentData(fd, value);
}
- public boolean select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs,
- int numReadable, int numWritable, long timeout, int[] flags)
- throws SocketException {
+ public int select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs, long timeout, int[] flags) throws SocketException {
BlockGuard.getThreadPolicy().onNetwork();
- return mNetwork.select(readFDs, writeFDs, numReadable, numWritable, timeout, flags);
+ return mNetwork.select(readFDs, writeFDs, timeout, flags);
}
public void close(FileDescriptor aFD) throws IOException {
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index 925c1e2..b53479e 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -45,15 +45,11 @@ import org.apache.harmony.luni.platform.Platform;
*/
final class SelectorImpl extends AbstractSelector {
- static final FileDescriptor[] EMPTY_FILE_DESCRIPTORS_ARRAY = new FileDescriptor[0];
+ private static final FileDescriptor[] EMPTY_FILE_DESCRIPTORS_ARRAY = new FileDescriptor[0];
private static final SelectionKeyImpl[] EMPTY_SELECTION_KEY_IMPLS_ARRAY
= new SelectionKeyImpl[0];
- private static final int CONNECT_OR_WRITE = OP_CONNECT | OP_WRITE;
-
- private static final int ACCEPT_OR_READ = OP_ACCEPT | OP_READ;
-
private static final int NA = 0;
private static final int READABLE = 1;
@@ -206,25 +202,24 @@ final class SelectorImpl extends AbstractSelector {
boolean isBlock = (SELECT_NOW != timeout);
int readableKeysCount = 1; // first is always the wakeup channel
int writableKeysCount = 0;
+ boolean success;
synchronized (keysLock) {
for (SelectionKeyImpl key : mutableKeys) {
int ops = key.interestOpsNoCheck();
- if ((ACCEPT_OR_READ & ops) != 0) {
+ if (((OP_ACCEPT | OP_READ) & ops) != 0) {
readableKeysCount++;
}
- if ((CONNECT_OR_WRITE & ops) != 0) {
+ if (((OP_CONNECT | OP_WRITE) & ops) != 0) {
writableKeysCount++;
}
}
prepareChannels(readableKeysCount, writableKeysCount);
}
- boolean success;
try {
if (isBlock) {
begin();
}
- success = Platform.NETWORK.select(readableFDs, writableFDs,
- readableKeysCount, writableKeysCount, timeout, flags);
+ success = (Platform.NETWORK.select(readableFDs, writableFDs, timeout, flags) > 0);
} finally {
if (isBlock) {
end();
@@ -246,15 +241,9 @@ final class SelectorImpl extends AbstractSelector {
}
}
- private int getReadyOps(SelectionKeyImpl key) {
- SelectableChannel channel = key.channel();
- return ((channel instanceof SocketChannel) && !((SocketChannel) channel).isConnectionPending()) ?
- OP_WRITE : CONNECT_OR_WRITE;
- }
-
/**
* Prepare the readableFDs, writableFDs, readyKeys and flags arrays in
- * preparation for a call to {@code INetworkSystem#select()}. After they're
+ * preparation for a call to select(2). After they're
* used, the array elements must be cleared.
*/
private void prepareChannels(int numReadable, int numWritable) {
@@ -281,12 +270,12 @@ final class SelectorImpl extends AbstractSelector {
int w = 0;
for (SelectionKeyImpl key : mutableKeys) {
int interestOps = key.interestOpsNoCheck();
- if ((ACCEPT_OR_READ & interestOps) != 0) {
+ if (((OP_ACCEPT | OP_READ) & interestOps) != 0) {
readableFDs[r] = ((FileDescriptorChannel) key.channel()).getFD();
readyKeys[r] = key;
r++;
}
- if ((getReadyOps(key) & interestOps) != 0) {
+ if (((OP_CONNECT | OP_WRITE) & interestOps) != 0) {
writableFDs[w] = ((FileDescriptorChannel) key.channel()).getFD();
readyKeys[w + numReadable] = key;
w++;
@@ -318,7 +307,7 @@ final class SelectorImpl extends AbstractSelector {
switch (flags[i]) {
case READABLE:
- selectedOp = ACCEPT_OR_READ & ops;
+ selectedOp = (OP_ACCEPT | OP_READ) & ops;
break;
case WRITABLE:
if (key.isConnected()) {
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
index 0f24816..f573dda 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
@@ -28,68 +28,22 @@ import java.net.SocketImpl;
* The interface for network methods.
*/
public interface INetworkSystem {
- public void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd)
- throws IOException;
+ public void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd) throws IOException;
- public int read(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
-
- public int readDirect(FileDescriptor fd, int address, int count) throws IOException;
-
- public int write(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
-
- public int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException;
+ public void close(FileDescriptor fd) throws IOException;
public boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
- public int send(FileDescriptor fd, byte[] data, int offset, int length,
- int port, InetAddress inetAddress) throws IOException;
- public int sendDirect(FileDescriptor fd, int address, int offset, int length,
- int port, InetAddress inetAddress) throws IOException;
+ public int read(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
+ public int readDirect(FileDescriptor fd, int address, int count) throws IOException;
+ public int recv(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset, int length, boolean peek, boolean connected) throws IOException;
+ public int recvDirect(FileDescriptor fd, DatagramPacket packet, int address, int offset, int length, boolean peek, boolean connected) throws IOException;
- public int recv(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset,
- int length, boolean peek, boolean connected) throws IOException;
- public int recvDirect(FileDescriptor fd, DatagramPacket packet, int address, int offset,
- int length, boolean peek, boolean connected) throws IOException;
+ public int select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs, long timeout, int[] flags) throws SocketException;
+ public int send(FileDescriptor fd, byte[] data, int offset, int length, int port, InetAddress inetAddress) throws IOException;
+ public int sendDirect(FileDescriptor fd, int address, int offset, int length, int port, InetAddress inetAddress) throws IOException;
public void sendUrgentData(FileDescriptor fd, byte value);
-
- /**
- * Select the given file descriptors for read and write operations.
- *
- * <p>The first {@code numReadable} file descriptors of {@code readFDs} will
- * be selected for read-ready operations. The first {@code numWritable} file
- * descriptors in {@code writeFDs} will be selected for write-ready
- * operations. A file descriptor can appear in either or both and must not
- * be null. If the file descriptor is closed during the select the behavior
- * depends upon the underlying OS.
- *
- * @param readFDs
- * all sockets interested in read and accept
- * @param writeFDs
- * all sockets interested in write and connect
- * @param numReadable
- * the size of the subset of readFDs to read or accept.
- * @param numWritable
- * the size of the subset of writeFDs to write or connect
- * @param timeout
- * timeout in milliseconds
- * @param flags
- * for output. Length must be at least {@code numReadable
- * + numWritable}. Upon returning, each element describes the
- * state of the descriptor in the corresponding read or write
- * array. See {@code SelectorImpl.READABLE} and {@code
- * SelectorImpl.WRITEABLE}
- * @return true
- * unless selection timed out or was interrupted
- * @throws SocketException
- */
- public boolean select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs,
- int numReadable, int numWritable, long timeout, int[] flags)
- throws SocketException;
-
- /**
- * It is an error to close the same file descriptor from multiple threads
- * concurrently.
- */
- public void close(FileDescriptor fd) throws IOException;
+ public int write(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
+ public int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException;
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 2080054..6e1f288 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -41,55 +41,22 @@ final class OSNetworkSystem implements INetworkSystem {
private OSNetworkSystem() {
}
- public native void accept(FileDescriptor serverFd, SocketImpl newSocket,
- FileDescriptor clientFd) throws IOException;
+ public native void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd) throws IOException;
- public native boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
-
- public native int read(FileDescriptor fd, byte[] data, int offset, int count)
- throws IOException;
+ public native void close(FileDescriptor fd) throws IOException;
+ public native int read(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
public native int readDirect(FileDescriptor fd, int address, int count) throws IOException;
+ public native int recv(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset, int length, boolean peek, boolean connected) throws IOException;
+ public native int recvDirect(FileDescriptor fd, DatagramPacket packet, int address, int offset, int length, boolean peek, boolean connected) throws IOException;
- public native int recv(FileDescriptor fd, DatagramPacket packet,
- byte[] data, int offset, int length,
- boolean peek, boolean connected) throws IOException;
-
- public native int recvDirect(FileDescriptor fd, DatagramPacket packet,
- int address, int offset, int length,
- boolean peek, boolean connected) throws IOException;
-
- public boolean select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs,
- int numReadable, int numWritable, long timeout, int[] flags)
- throws SocketException {
- if (numReadable < 0 || numWritable < 0) {
- throw new IllegalArgumentException();
- }
-
- int total = numReadable + numWritable;
- if (total == 0) {
- return true;
- }
-
- return selectImpl(readFDs, writeFDs, numReadable, numWritable, flags, timeout);
- }
-
- static native boolean selectImpl(FileDescriptor[] readfd,
- FileDescriptor[] writefd, int cread, int cwirte, int[] flags,
- long timeout);
+ public native boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
- public native int send(FileDescriptor fd, byte[] data, int offset, int length,
- int port, InetAddress inetAddress) throws IOException;
- public native int sendDirect(FileDescriptor fd, int address, int offset, int length,
- int port, InetAddress inetAddress) throws IOException;
+ public native int select(FileDescriptor[] readFds, FileDescriptor[] writeFds, long timeout, int[] flags);
+ public native int send(FileDescriptor fd, byte[] data, int offset, int length, int port, InetAddress inetAddress) throws IOException;
+ public native int sendDirect(FileDescriptor fd, int address, int offset, int length, int port, InetAddress inetAddress) throws IOException;
public native void sendUrgentData(FileDescriptor fd, byte value);
-
- public native void close(FileDescriptor fd) throws IOException;
-
- public native int write(FileDescriptor fd, byte[] data, int offset, int count)
- throws IOException;
-
- public native int writeDirect(FileDescriptor fd, int address, int offset, int count)
- throws IOException;
+ public native int write(FileDescriptor fd, byte[] data, int offset, int count) throws IOException;
+ public native int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException;
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 3c3a924..3e4c12c 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -39,7 +39,7 @@
#include <sys/time.h>
#include <unistd.h>
-/* constants for OSNetworkSystem_selectImpl */
+/* constants for OSNetworkSystem_select */
#define SOCKET_OP_NONE 0
#define SOCKET_OP_READ 1
#define SOCKET_OP_WRITE 2
@@ -286,7 +286,7 @@ static jint OSNetworkSystem_readDirect(JNIEnv* env, jobject, jobject fileDescrip
}
}
-static jint OSNetworkSystem_read(JNIEnv* env, jclass, jobject fileDescriptor,
+static jint OSNetworkSystem_read(JNIEnv* env, jobject, jobject fileDescriptor,
jbyteArray byteArray, jint offset, jint count) {
ScopedByteArrayRW bytes(env, byteArray);
if (bytes.get() == NULL) {
@@ -425,16 +425,17 @@ static bool isValidFd(int fd) {
return fd >= 0 && fd < FD_SETSIZE;
}
-static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdSet, int* maxFd) {
- for (int i = 0; i < count; ++i) {
+static size_t initFdSet(JNIEnv* env, jobjectArray fdArray, fd_set* fdSet, int* maxFd) {
+ size_t length = env->GetArrayLength(fdArray);
+ for (size_t i = 0; i < length; ++i) {
jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
if (fileDescriptor == NULL) {
- return false;
+ return i;
}
const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (!isValidFd(fd)) {
- LOGE("selectImpl: ignoring invalid fd %i", fd);
+ LOGE("select: ignoring invalid fd %i", fd);
continue;
}
@@ -444,7 +445,7 @@ static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdS
*maxFd = fd;
}
}
- return true;
+ return length;
}
/*
@@ -453,11 +454,12 @@ static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdS
* side here:
* http://www.opengroup.org/onlinepubs/000095399/functions/select.html
*/
-static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
- for (int i = 0; i < count; ++i) {
+static void translateFdSet(JNIEnv* env, jobjectArray fdArray, fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
+ size_t length = env->GetArrayLength(fdArray);
+ for (size_t i = 0; i < length; ++i) {
jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
if (fileDescriptor == NULL) {
- return false;
+ return;
}
const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -467,12 +469,10 @@ static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set
flagArray[i + offset] = SOCKET_OP_NONE;
}
}
- return true;
}
-static jboolean OSNetworkSystem_selectImpl(JNIEnv* env, jclass,
- jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
- jint countWriteC, jintArray outFlags, jlong timeoutMs) {
+static jint OSNetworkSystem_select(JNIEnv* env, jobject,
+ jobjectArray readFDArray, jobjectArray writeFDArray, jlong timeoutMs, jintArray outFlags) {
// Initialize the fd_sets.
int maxFd = -1;
@@ -480,11 +480,8 @@ static jboolean OSNetworkSystem_selectImpl(JNIEnv* env, jclass,
fd_set writeFds;
FD_ZERO(&readFds);
FD_ZERO(&writeFds);
- bool initialized = initFdSet(env, readFDArray, countReadC, &readFds, &maxFd) &&
- initFdSet(env, writeFDArray, countWriteC, &writeFds, &maxFd);
- if (!initialized) {
- return -1;
- }
+ size_t readFdCount = initFdSet(env, readFDArray, &readFds, &maxFd);
+ initFdSet(env, writeFDArray, &writeFds, &maxFd);
// Initialize the timeout, if any.
timeval tv;
@@ -498,24 +495,23 @@ static jboolean OSNetworkSystem_selectImpl(JNIEnv* env, jclass,
int result = select(maxFd + 1, &readFds, &writeFds, NULL, tvp);
if (result == 0) {
// Timeout.
- return JNI_FALSE;
+ return 0;
} else if (result == -1) {
// Error.
- if (errno == EINTR) {
- return JNI_FALSE;
- } else {
+ if (errno != EINTR) {
jniThrowSocketException(env, errno);
- return JNI_FALSE;
}
+ return -1;
}
// Translate the result into the int[] we're supposed to fill in.
ScopedIntArrayRW flagArray(env, outFlags);
if (flagArray.get() == NULL) {
- return JNI_FALSE;
+ return -1;
}
- return translateFdSet(env, readFDArray, countReadC, readFds, flagArray.get(), 0, SOCKET_OP_READ) &&
- translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray.get(), countReadC, SOCKET_OP_WRITE);
+ translateFdSet(env, readFDArray, readFds, flagArray.get(), 0, SOCKET_OP_READ);
+ translateFdSet(env, writeFDArray, writeFds, flagArray.get(), readFdCount, SOCKET_OP_WRITE);
+ return result;
}
static void OSNetworkSystem_close(JNIEnv* env, jobject, jobject fileDescriptor) {
@@ -540,7 +536,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(OSNetworkSystem, readDirect, "(Ljava/io/FileDescriptor;II)I"),
NATIVE_METHOD(OSNetworkSystem, recv, "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIZZ)I"),
NATIVE_METHOD(OSNetworkSystem, recvDirect, "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIZZ)I"),
- NATIVE_METHOD(OSNetworkSystem, selectImpl, "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)Z"),
+ NATIVE_METHOD(OSNetworkSystem, select, "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;J[I)I"),
NATIVE_METHOD(OSNetworkSystem, send, "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I"),
NATIVE_METHOD(OSNetworkSystem, sendDirect, "(Ljava/io/FileDescriptor;IIIILjava/net/InetAddress;)I"),
NATIVE_METHOD(OSNetworkSystem, sendUrgentData, "(Ljava/io/FileDescriptor;B)V"),
diff --git a/luni/src/test/java/libcore/java/nio/SelectorTest.java b/luni/src/test/java/libcore/java/nio/SelectorTest.java
index ad53825..14177e5 100644
--- a/luni/src/test/java/libcore/java/nio/SelectorTest.java
+++ b/luni/src/test/java/libcore/java/nio/SelectorTest.java
@@ -27,6 +27,7 @@ import java.nio.channels.SocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
+import tests.net.StuckServer;
public class SelectorTest extends TestCase {
@@ -55,52 +56,31 @@ public class SelectorTest extends TestCase {
super.tearDown();
}
- // http://code.google.com/p/android/issues/detail?id=6309
- public void test_connectFinish_fails() throws Exception {
- final SocketChannel channel = SocketChannel.open();
- channel.configureBlocking(false);
- channel.register(selector, SelectionKey.OP_CONNECT);
- final Boolean[] fail = new Boolean[1];
- new Thread() {
- public void run() {
- try {
- while (selector.isOpen()) {
- if (selector.select() != 0) {
- for (SelectionKey key : selector.selectedKeys()) {
- if (key.isValid() && key.isConnectable()) {
- try {
- channel.finishConnect();
- synchronized (fail) {
- fail[0] = Boolean.FALSE;
- fail.notify();
- }
- } catch (NoConnectionPendingException _) {
- synchronized (fail) {
- fail[0] = Boolean.TRUE;
- fail.notify();
- }
- }
- }
- }
- }
- }
- } catch (Exception _) {}
- }
- }.start();
+ public void testNonBlockingConnect_immediate() throws Exception {
+ // Test the case where we [probably] connect immediately.
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
+ sc.connect(ssc.socket().getLocalSocketAddress());
+ SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
+ assertEquals(1, selector.select());
+ assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
+ sc.finishConnect();
+ }
- final int WAIT_TIME_MS = 100;
- Thread.sleep(WAIT_TIME_MS);
- channel.connect(ssc.socket().getLocalSocketAddress());
- long time = System.currentTimeMillis();
- synchronized (fail) {
- while (System.currentTimeMillis() - time < WAIT_TIME_MS || fail[0] == null) {
- fail.wait(WAIT_TIME_MS);
- }
- }
- if (fail[0] == null) {
- fail("test does not work");
- } else if (fail[0].booleanValue()) {
- fail();
+ public void testNonBlockingConnect_slow() throws Exception {
+ // Test the case where we have to wait for the connection.
+ StuckServer ss = new StuckServer();
+ try {
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
+ ss.unblockAfterMs(2000);
+ sc.connect(ss.getLocalSocketAddress());
+ SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
+ assertEquals(1, selector.select());
+ assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
+ sc.finishConnect();
+ } finally {
+ ss.close();
}
}
diff --git a/support/src/test/java/tests/net/StuckServer.java b/support/src/test/java/tests/net/StuckServer.java
index 4230f17..eababce 100644
--- a/support/src/test/java/tests/net/StuckServer.java
+++ b/support/src/test/java/tests/net/StuckServer.java
@@ -40,6 +40,24 @@ public final class StuckServer {
}
}
+ public void unblockAfterMs(final int ms) {
+ Thread t = new Thread(new Runnable() {
+ @Override public void run() {
+ try {
+ Thread.sleep(ms);
+ for (Socket client : clients) {
+ client.close();
+ }
+ clients.clear();
+ clients.add(serverSocket.accept());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ t.start();
+ }
+
public InetSocketAddress getLocalSocketAddress() {
return (InetSocketAddress) serverSocket.getLocalSocketAddress();
}