6395224: (so) SocketChannel writer blocked on large buffer is not preempted by close method (vista)
authoralanb
Thu, 17 Jun 2010 17:49:59 +0100
changeset 5804 faf9bd47d6ce
parent 5803 c3ddaebe216b
child 5805 87c7dd70572a
6395224: (so) SocketChannel writer blocked on large buffer is not preempted by close method (vista) Reviewed-by: chegar
jdk/src/windows/native/sun/nio/ch/SocketDispatcher.c
jdk/src/windows/native/sun/nio/ch/nio_util.h
jdk/test/ProblemList.txt
jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java
--- a/jdk/src/windows/native/sun/nio/ch/SocketDispatcher.c	Wed Jun 16 23:27:41 2010 -0700
+++ b/jdk/src/windows/native/sun/nio/ch/SocketDispatcher.c	Thu Jun 17 17:49:59 2010 +0100
@@ -50,6 +50,10 @@
     jint fd = fdval(env, fdo);
     WSABUF buf;
 
+    /* limit size */
+    if (len > MAX_BUFFER_SIZE)
+        len = MAX_BUFFER_SIZE;
+
     /* destination buffer and size */
     buf.buf = (char *)address;
     buf.len = (u_long)len;
@@ -86,6 +90,7 @@
     jint fd = fdval(env, fdo);
     struct iovec *iovp = (struct iovec *)address;
     WSABUF *bufs = malloc(len * sizeof(WSABUF));
+    jint rem = MAX_BUFFER_SIZE;
 
     if (bufs == 0) {
         JNU_ThrowOutOfMemoryError(env, 0);
@@ -98,8 +103,16 @@
 
     /* copy iovec into WSABUF */
     for(i=0; i<len; i++) {
+        jint iov_len = iovp[i].iov_len;
+        if (iov_len > rem)
+            iov_len = rem;
         bufs[i].buf = (char *)iovp[i].iov_base;
-        bufs[i].len = (u_long)iovp[i].iov_len;
+        bufs[i].len = (u_long)iov_len;
+        rem -= iov_len;
+        if (rem == 0) {
+            len = i+1;
+            break;
+        }
     }
 
     /* read into the buffers */
@@ -136,6 +149,10 @@
     jint fd = fdval(env, fdo);
     WSABUF buf;
 
+    /* limit size */
+    if (len > MAX_BUFFER_SIZE)
+        len = MAX_BUFFER_SIZE;
+
     /* copy iovec into WSABUF */
     buf.buf = (char *)address;
     buf.len = (u_long)len;
@@ -171,6 +188,7 @@
     jint fd = fdval(env, fdo);
     struct iovec *iovp = (struct iovec *)address;
     WSABUF *bufs = malloc(len * sizeof(WSABUF));
+    jint rem = MAX_BUFFER_SIZE;
 
     if (bufs == 0) {
         JNU_ThrowOutOfMemoryError(env, 0);
@@ -183,8 +201,16 @@
 
     /* copy iovec into WSABUF */
     for(i=0; i<len; i++) {
+        jint iov_len = iovp[i].iov_len;
+        if (iov_len > rem)
+            iov_len = rem;
         bufs[i].buf = (char *)iovp[i].iov_base;
-        bufs[i].len = (u_long)iovp[i].iov_len;
+        bufs[i].len = (u_long)iov_len;
+        rem -= iov_len;
+        if (rem == 0) {
+            len = i+1;
+            break;
+        }
     }
 
     /* read into the buffers */
--- a/jdk/src/windows/native/sun/nio/ch/nio_util.h	Wed Jun 16 23:27:41 2010 -0700
+++ b/jdk/src/windows/native/sun/nio/ch/nio_util.h	Thu Jun 17 17:49:59 2010 +0100
@@ -25,6 +25,14 @@
 
 #include "jni.h"
 
+/**
+ * The maximum buffer size for WSASend/WSARecv. Microsoft recommendation for
+ * blocking operations is to use buffers no larger than 64k. We need the
+ * maximum to be less than 128k to support asynchronous close on Windows
+ * Server 2003 and newer editions of Windows.
+ */
+#define MAX_BUFFER_SIZE             ((128*1024)-1)
+
 jint fdval(JNIEnv *env, jobject fdo);
 jlong handleval(JNIEnv *env, jobject fdo);
 jboolean isNT();
--- a/jdk/test/ProblemList.txt	Wed Jun 16 23:27:41 2010 -0700
+++ b/jdk/test/ProblemList.txt	Thu Jun 17 17:49:59 2010 +0100
@@ -772,9 +772,6 @@
 # Linux 64bit failures. too many files open
 java/nio/channels/Selector/HelperSlowToDie.java			generic-all
 
-# Timeouts etc. on Window
-java/nio/channels/AsyncCloseAndInterrupt.java		 	windows-all
-
 # Gets java.lang.ExceptionInInitializerError on Windows 2000 (need XP or newer)
 java/nio/channels/AsynchronousChannelGroup/Basic.java	 	windows-5.0
 java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java 	windows-5.0
--- a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java	Wed Jun 16 23:27:41 2010 -0700
+++ b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java	Thu Jun 17 17:49:59 2010 +0100
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135
+ * @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135 6395224
  * @summary Comprehensive test of asynchronous closing and interruption
  * @author Mark Reinhold
  */
@@ -88,6 +88,9 @@
     }
 
     private static void pumpRefuser(String msg) throws IOException {
+        // Can't reliably saturate connection backlog on Windows Server editions
+        assert !TestUtil.onWindows();
+
         log.print(msg);
         int n = refuserClients.size();
 
@@ -203,9 +206,9 @@
         = new ChannelFactory("DatagramChannel") {
                 InterruptibleChannel create() throws IOException {
                     DatagramChannel dc = DatagramChannel.open();
-                    dc.socket().bind(wildcardAddress);
-                    InetAddress ia = InetAddress.getByName("127.0.0.1");
-                    dc.connect(new InetSocketAddress(ia, 80));
+                    InetAddress lb = InetAddress.getByName("127.0.0.1");
+                    dc.bind(new InetSocketAddress(lb, 0));
+                    dc.connect(new InetSocketAddress(lb, 80));
                     return dc;
                 }
             };
@@ -636,7 +639,8 @@
 
         wildcardAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
         initAcceptor();
-        initRefuser();
+        if (!TestUtil.onWindows())
+            initRefuser();
         initPipes();
         initFile();
 
@@ -658,8 +662,15 @@
         // unclear under what conditions mmap(2) will actually block.
 
         test(connectedSocketChannelFactory);
-        test(socketChannelFactory, CONNECT);
-        test(socketChannelFactory, FINISH_CONNECT);
+
+        if (TestUtil.onWindows()) {
+            log.println("WARNING Cannot reliably test connect/finishConnect"
+                + " operations on Windows");
+        } else {
+            test(socketChannelFactory, CONNECT);
+            test(socketChannelFactory, FINISH_CONNECT);
+        }
+
         test(serverSocketChannelFactory, ACCEPT);
         test(datagramChannelFactory);
         test(pipeSourceChannelFactory);