8075484: SocketInputStream.socketRead0 can hang even with soTimeout set
authorvtewari
Tue, 13 Sep 2016 17:00:06 +0530
changeset 40937 f72e61ec734b
parent 40936 386b5a3986f1
child 40938 5b0977acc842
8075484: SocketInputStream.socketRead0 can hang even with soTimeout set Reviewed-by: chegar, dsamersoff, msheppar, clanger
jdk/src/java.base/aix/native/libnet/aix_close.c
jdk/src/java.base/linux/native/libnet/linux_close.c
jdk/src/java.base/macosx/native/libnet/bsd_close.c
jdk/src/java.base/solaris/native/libnet/solaris_close.c
jdk/src/java.base/unix/native/libnet/SocketInputStream.c
jdk/src/java.base/unix/native/libnet/net_util_md.c
jdk/src/java.base/unix/native/libnet/net_util_md.h
--- a/jdk/src/java.base/aix/native/libnet/aix_close.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/aix/native/libnet/aix_close.c	Tue Sep 13 17:00:06 2016 +0530
@@ -410,6 +410,10 @@
     BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
 }
 
+int NET_NonBlockingRead(int s, void* buf, size_t len) {
+    BLOCKING_IO_RETURN_INT(s, recv(s, buf, len, MSG_NONBLOCK));
+}
+
 int NET_ReadV(int s, const struct iovec * vector, int count) {
     BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
 }
@@ -503,8 +507,8 @@
  * Auto restarts with adjusted timeout if interrupted by
  * signal other than our wakeup signal.
  */
-int NET_Timeout(int s, long timeout) {
-    long prevtime = 0, newtime;
+int NET_Timeout0(int s, long timeout, long currentTime) {
+    long prevtime = currentTime, newtime;
     struct timeval t;
     fdEntry_t *fdEntry = getFdEntry(s);
 
@@ -516,14 +520,6 @@
         return -1;
     }
 
-    /*
-     * Pick up current time as may need to adjust timeout
-     */
-    if (timeout > 0) {
-        gettimeofday(&t, NULL);
-        prevtime = t.tv_sec * 1000  +  t.tv_usec / 1000;
-    }
-
     for(;;) {
         struct pollfd pfd;
         int rv;
--- a/jdk/src/java.base/linux/native/libnet/linux_close.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/linux/native/libnet/linux_close.c	Tue Sep 13 17:00:06 2016 +0530
@@ -367,6 +367,10 @@
     BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
 }
 
+int NET_NonBlockingRead(int s, void* buf, size_t len) {
+    BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT) );
+}
+
 int NET_ReadV(int s, const struct iovec * vector, int count) {
     BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
 }
@@ -406,8 +410,8 @@
  * Auto restarts with adjusted timeout if interrupted by
  * signal other than our wakeup signal.
  */
-int NET_Timeout(int s, long timeout) {
-    long prevtime = 0, newtime;
+int NET_Timeout0(int s, long timeout, long currentTime) {
+    long prevtime = currentTime, newtime;
     struct timeval t;
     fdEntry_t *fdEntry = getFdEntry(s);
 
@@ -419,14 +423,6 @@
         return -1;
     }
 
-    /*
-     * Pick up current time as may need to adjust timeout
-     */
-    if (timeout > 0) {
-        gettimeofday(&t, NULL);
-        prevtime = t.tv_sec * 1000  +  t.tv_usec / 1000;
-    }
-
     for(;;) {
         struct pollfd pfd;
         int rv;
--- a/jdk/src/java.base/macosx/native/libnet/bsd_close.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/macosx/native/libnet/bsd_close.c	Tue Sep 13 17:00:06 2016 +0530
@@ -371,6 +371,10 @@
     BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
 }
 
+int NET_NonBlockingRead(int s, void* buf, size_t len) {
+    BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT));
+}
+
 int NET_ReadV(int s, const struct iovec * vector, int count) {
     BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
 }
@@ -410,8 +414,8 @@
  * Auto restarts with adjusted timeout if interrupted by
  * signal other than our wakeup signal.
  */
-int NET_Timeout(int s, long timeout) {
-    long prevtime = 0, newtime;
+int NET_Timeout0(int s, long timeout, long currentTime) {
+    long prevtime = currentTime, newtime;
     struct timeval t, *tp = &t;
     fd_set fds;
     fd_set* fdsp = NULL;
@@ -432,9 +436,6 @@
      */
     if (timeout > 0) {
         /* Timed */
-        struct timeval now;
-        gettimeofday(&now, NULL);
-        prevtime = now.tv_sec * 1000  +  now.tv_usec / 1000;
         t.tv_sec = timeout / 1000;
         t.tv_usec = (timeout % 1000) * 1000;
     } else if (timeout < 0) {
--- a/jdk/src/java.base/solaris/native/libnet/solaris_close.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/solaris/native/libnet/solaris_close.c	Tue Sep 13 17:00:06 2016 +0530
@@ -35,7 +35,7 @@
     if (1) {                                          \
         do {                                          \
             _result = _cmd;                           \
-        } while((_result == -1) && (errno == EINTR)); \
+        } while((_result == -1) && (errno == EINTR));      \
         return _result;                               \
     }                                                 \
 } while(0)
@@ -44,6 +44,10 @@
     RESTARTABLE_RETURN_INT(recv(s, buf, len, 0));
 }
 
+int NET_NonBlockingRead(int s, void* buf, size_t len) {
+    RESTARTABLE_RETURN_INT(recv(s, buf, len, MSG_DONTWAIT));
+}
+
 int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
                  struct sockaddr *from, socklen_t *fromlen) {
     RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen));
@@ -86,19 +90,14 @@
     RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout));
 }
 
-int NET_Timeout(int s, long timeout) {
+int NET_Timeout0(int s, long timeout, long currentTime) {
     int result;
     struct timeval t;
-    long prevtime, newtime;
+    long prevtime = currentTime, newtime;
     struct pollfd pfd;
     pfd.fd = s;
     pfd.events = POLLIN;
 
-    if (timeout > 0) {
-        gettimeofday(&t, NULL);
-        prevtime = (t.tv_sec * 1000)  +  t.tv_usec / 1000;
-    }
-
     for(;;) {
         result = poll(&pfd, 1, timeout);
         if (result < 0 && errno == EINTR) {
--- a/jdk/src/java.base/unix/native/libnet/SocketInputStream.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/unix/native/libnet/SocketInputStream.c	Tue Sep 13 17:00:06 2016 +0530
@@ -35,7 +35,6 @@
 
 #include "java_net_SocketInputStream.h"
 
-
 /************************************************************************
  * SocketInputStream
  */
@@ -52,6 +51,40 @@
     IO_fd_fdID = NET_GetFileDescriptorID(env);
 }
 
+static int NET_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len, long timeout) {
+    int result = 0;
+    long prevtime = NET_GetCurrentTime(), newtime;
+    while (timeout > 0) {
+        result = NET_TimeoutWithCurrentTime(fd, timeout, prevtime);
+        if (result <= 0) {
+            if (result == 0) {
+                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Read timed out");
+            } else if (result == -1) {
+                if (errno == EBADF) {
+                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
+                } else if (errno == ENOMEM) {
+                    JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
+                } else {
+                    JNU_ThrowByNameWithMessageAndLastError
+                            (env, JNU_JAVANETPKG "SocketException", "select/poll failed");
+                }
+            }
+            return -1;
+        }
+        result = NET_NonBlockingRead(fd, bufP, len);
+        if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
+            newtime = NET_GetCurrentTime();
+            timeout -= newtime - prevtime;
+            if (timeout > 0) {
+                prevtime = newtime;
+            }
+        } else {
+            break;
+        }
+    }
+    return result;
+}
+
 /*
  * Class:     java_net_SocketInputStream
  * Method:    socketRead0
@@ -98,32 +131,18 @@
     } else {
         bufP = BUF;
     }
-
     if (timeout) {
-        nread = NET_Timeout(fd, timeout);
-        if (nread <= 0) {
-            if (nread == 0) {
-                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
-                            "Read timed out");
-            } else if (nread == -1) {
-                if (errno == EBADF) {
-                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
-                } else if (errno == ENOMEM) {
-                    JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
-                } else {
-                    JNU_ThrowByNameWithMessageAndLastError
-                        (env, JNU_JAVANETPKG "SocketException", "select/poll failed");
-                }
-            }
+        nread = NET_ReadWithTimeout(env, fd, bufP, len, timeout);
+        if ((*env)->ExceptionCheck(env)) {
             if (bufP != BUF) {
                 free(bufP);
             }
-            return -1;
+            return nread;
         }
+    } else {
+        nread = NET_Read(fd, bufP, len);
     }
 
-    nread = NET_Read(fd, bufP, len);
-
     if (nread <= 0) {
         if (nread < 0) {
 
@@ -143,7 +162,6 @@
                      JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
                            "Operation interrupted");
                      break;
-
                 default:
                     JNU_ThrowByNameWithMessageAndLastError
                         (env, JNU_JAVANETPKG "SocketException", "Read failed");
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Tue Sep 13 17:00:06 2016 +0530
@@ -33,6 +33,7 @@
 #include <netdb.h>
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <sys/time.h>
 
 #ifndef _ALLBSD_SOURCE
 #include <values.h>
@@ -1669,3 +1670,18 @@
 
     return timeout;
 }
+
+long NET_GetCurrentTime() {
+    struct timeval time;
+    gettimeofday(&time, NULL);
+    return (time.tv_sec * 1000 + time.tv_usec / 1000);
+}
+
+int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime) {
+    return NET_Timeout0(s, timeout, currentTime);
+}
+
+int NET_Timeout(int s, long timeout) {
+    long currentTime = (timeout > 0) ? NET_GetCurrentTime() : 0;
+    return NET_Timeout0(s, timeout, currentTime);
+}
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.h	Tue Sep 13 14:55:20 2016 +0800
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h	Tue Sep 13 17:00:06 2016 +0530
@@ -35,7 +35,11 @@
 #include <sys/poll.h>
 
 int NET_Timeout(int s, long timeout);
+int NET_Timeout0(int s, long timeout, long currentTime);
 int NET_Read(int s, void* buf, size_t len);
+int NET_NonBlockingRead(int s, void* buf, size_t len);
+int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime);
+long NET_GetCurrentTime();
 int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
                  struct sockaddr *from, socklen_t *fromlen);
 int NET_ReadV(int s, const struct iovec * vector, int count);