From fba82c7c533710979ee38eb5dc1b2ffb0f9ffd27 Mon Sep 17 00:00:00 2001 From: chegar Date: Sun, 2 Mar 2014 19:27:43 +0000 Subject: [PATCH] 8035897: Better memory allocation for file descriptors greater than 1024 on macosx Reviewed-by: michaelm, alanb --- .../native/java/net/PlainDatagramSocketImpl.c | 12 ++- src/solaris/native/java/net/PlainSocketImpl.c | 6 +- .../native/java/net/SocketInputStream.c | 6 +- src/solaris/native/java/net/bsd_close.c | 34 ++++++-- src/solaris/native/java/net/linux_close.c | 5 +- .../ServerSocket/AnotherSelectFdsLimit.java | 78 +++++++++++++++++++ 6 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 test/java/net/ServerSocket/AnotherSelectFdsLimit.java diff --git a/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/src/solaris/native/java/net/PlainDatagramSocketImpl.c index 356875600..9da9104aa 100644 --- a/src/solaris/native/java/net/PlainDatagramSocketImpl.c +++ b/src/solaris/native/java/net/PlainDatagramSocketImpl.c @@ -509,7 +509,8 @@ Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "Null address in peek()"); } if (timeout) { - int ret = NET_Timeout(fd, timeout); + int ret = NET_Timeout(env, fd, timeout); + JNU_CHECK_EXCEPTION_RETURN(env, -1); if (ret == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Peek timed out"); @@ -611,7 +612,8 @@ Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this, packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID); if (timeout) { - int ret = NET_Timeout(fd, timeout); + int ret = NET_Timeout(env, fd, timeout); + JNU_CHECK_EXCEPTION_RETURN(env, -1); if (ret == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Receive timed out"); @@ -829,9 +831,11 @@ Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this, retry = JNI_FALSE; if (timeout) { - int ret = NET_Timeout(fd, timeout); + int ret = NET_Timeout(env, fd, timeout); if (ret <= 0) { - if (ret == 0) { + if ((*env)->ExceptionCheck(env)) { + // fall-through, to potentially free, then return + } else if (ret == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Receive timed out"); } else if (ret == JVM_IO_ERR) { diff --git a/src/solaris/native/java/net/PlainSocketImpl.c b/src/solaris/native/java/net/PlainSocketImpl.c index b6f78b9c1..812c4b991 100644 --- a/src/solaris/native/java/net/PlainSocketImpl.c +++ b/src/solaris/native/java/net/PlainSocketImpl.c @@ -704,11 +704,11 @@ Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this, /* passing a timeout of 0 to poll will return immediately, but in the case of ServerSocket 0 means infinite. */ if (timeout <= 0) { - ret = NET_Timeout(fd, -1); + ret = NET_Timeout(env, fd, -1); } else { - ret = NET_Timeout(fd, timeout); + ret = NET_Timeout(env, fd, timeout); } - + JNU_CHECK_EXCEPTION(env); if (ret == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Accept timed out"); diff --git a/src/solaris/native/java/net/SocketInputStream.c b/src/solaris/native/java/net/SocketInputStream.c index ccee03c9e..66ff3e2cf 100644 --- a/src/solaris/native/java/net/SocketInputStream.c +++ b/src/solaris/native/java/net/SocketInputStream.c @@ -100,9 +100,11 @@ Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this, } if (timeout) { - nread = NET_Timeout(fd, timeout); + nread = NET_Timeout(env, fd, timeout); if (nread <= 0) { - if (nread == 0) { + if ((*env)->ExceptionCheck(env)) { + // fall-through, to potentially free, then return + } else if (nread == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Read timed out"); } else if (nread == JVM_IO_ERR) { diff --git a/src/solaris/native/java/net/bsd_close.c b/src/solaris/native/java/net/bsd_close.c index f314357e8..c8bb25639 100644 --- a/src/solaris/native/java/net/bsd_close.c +++ b/src/solaris/native/java/net/bsd_close.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -35,9 +36,10 @@ #include #include #include - #include +#include "jni_util.h" + /* * Stack allocated by thread when doing blocking operation */ @@ -344,9 +346,13 @@ int NET_Select(int s, fd_set *readfds, fd_set *writefds, * Auto restarts with adjusted timeout if interrupted by * signal other than our wakeup signal. */ -int NET_Timeout(int s, long timeout) { +int NET_Timeout(JNIEnv *env, int s, long timeout) { long prevtime = 0, newtime; struct timeval t, *tp = &t; + fd_set fds; + fd_set* fdsp = NULL; + int allocated = 0; + threadEntry_t self; fdEntry_t *fdEntry = getFdEntry(s); /* @@ -376,20 +382,30 @@ int NET_Timeout(int s, long timeout) { t.tv_usec = 0; } + if (s < FD_SETSIZE) { + fdsp = &fds; + FD_ZERO(fdsp); + } else { + int length = (howmany(s+1, NFDBITS)) * sizeof(int); + fdsp = (fd_set *) calloc(1, length); + if (fdsp == NULL) { + JNU_ThrowOutOfMemoryError(env, "NET_Select native heap allocation failed"); + return 0; + } + allocated = 1; + } + FD_SET(s, fdsp); + for(;;) { - fd_set rfds; int rv; - threadEntry_t self; /* * call select on the fd. If interrupted by our wakeup signal * errno will be set to EBADF. */ - FD_ZERO(&rfds); - FD_SET(s, &rfds); startOp(fdEntry, &self); - rv = select(s+1, &rfds, 0, 0, tp); + rv = select(s+1, fdsp, 0, 0, tp); endOp(fdEntry, &self); /* @@ -403,6 +419,8 @@ int NET_Timeout(int s, long timeout) { newtime = now.tv_sec * 1000 + now.tv_usec / 1000; timeout -= newtime - prevtime; if (timeout <= 0) { + if (allocated != 0) + free(fdsp); return 0; } prevtime = newtime; @@ -410,6 +428,8 @@ int NET_Timeout(int s, long timeout) { t.tv_usec = (timeout % 1000) * 1000; } } else { + if (allocated != 0) + free(fdsp); return rv; } diff --git a/src/solaris/native/java/net/linux_close.c b/src/solaris/native/java/net/linux_close.c index 38d998658..1198e0f82 100644 --- a/src/solaris/native/java/net/linux_close.c +++ b/src/solaris/native/java/net/linux_close.c @@ -34,9 +34,10 @@ #include #include #include - #include +#include "jni.h" + /* * Stack allocated by thread when doing blocking operation */ @@ -325,7 +326,7 @@ int NET_Select(int s, fd_set *readfds, fd_set *writefds, * Auto restarts with adjusted timeout if interrupted by * signal other than our wakeup signal. */ -int NET_Timeout(int s, long timeout) { +int NET_Timeout(JNIEnv *unused, int s, long timeout) { long prevtime = 0, newtime; struct timeval t; fdEntry_t *fdEntry = getFdEntry(s); diff --git a/test/java/net/ServerSocket/AnotherSelectFdsLimit.java b/test/java/net/ServerSocket/AnotherSelectFdsLimit.java new file mode 100644 index 000000000..391c5fb00 --- /dev/null +++ b/test/java/net/ServerSocket/AnotherSelectFdsLimit.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8035897 + * @summary FD_SETSIZE should be set on macosx + * @run main/othervm AnotherSelectFdsLimit 1023 + * @run main/othervm AnotherSelectFdsLimit 1024 + * @run main/othervm AnotherSelectFdsLimit 1025 + * @run main/othervm AnotherSelectFdsLimit 1600 + */ + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.List; + +public class AnotherSelectFdsLimit { + static final int DEFAULT_FDS_TO_USE = 1600; + + public static void main(String [] args) throws Exception { + if (!System.getProperty("os.name").contains("OS X")) { + System.out.println("Test only run on MAC. Exiting."); + return; + } + + int fdsToUse = DEFAULT_FDS_TO_USE; + if (args.length == 1) + fdsToUse = Integer.parseInt(args[0]); + + System.out.println("Using " + fdsToUse + " fds."); + + List threads = new ArrayList<>(); + for (int i=0; i