8075484: SocketInputStream.socketRead0 can hang even with soTimeout set
Reviewed-by: chegar, dsamersoff, msheppar, clanger
--- 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);