diff --git a/make/mapfiles/libnet/mapfile-vers b/make/mapfiles/libnet/mapfile-vers index 9e07f44b14aaeaf98f1273fde0deb6c9b892a233..3eb5e6d994a9c22a6d8658fbf81539d16ba1c480 100644 --- a/make/mapfiles/libnet/mapfile-vers +++ b/make/mapfiles/libnet/mapfile-vers @@ -110,6 +110,8 @@ SUNWprivate_1.1 { NET_Bind; NET_MapSocketOption; NET_Wait; + NET_EnableFastTcpLoopback; + NET_ThrowNew; ipv6_available; local: diff --git a/src/share/classes/sun/nio/ch/FileChannelImpl.java b/src/share/classes/sun/nio/ch/FileChannelImpl.java index bb127e8a5f2ce61689289f633c31b5fb1431f76d..88ddab43a57d06f01068647899753a957668c8bd 100644 --- a/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -38,6 +38,7 @@ import java.nio.channels.NonReadableChannelException; import java.nio.channels.NonWritableChannelException; import java.nio.channels.OverlappingFileLockException; import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectableChannel; import java.nio.channels.WritableByteChannel; import java.security.AccessController; import java.util.ArrayList; @@ -407,30 +408,13 @@ public class FileChannelImpl // private static volatile boolean fileSupported = true; - private long transferToDirectly(long position, int icount, - WritableByteChannel target) + private long transferToDirectlyInternal(long position, int icount, + WritableByteChannel target, + FileDescriptor targetFD) throws IOException { - if (!transferSupported) - return IOStatus.UNSUPPORTED; - - FileDescriptor targetFD = null; - if (target instanceof FileChannelImpl) { - if (!fileSupported) - return IOStatus.UNSUPPORTED_CASE; - targetFD = ((FileChannelImpl)target).fd; - } else if (target instanceof SelChImpl) { - // Direct transfer to pipe causes EINVAL on some configurations - if ((target instanceof SinkChannelImpl) && !pipeSupported) - return IOStatus.UNSUPPORTED_CASE; - targetFD = ((SelChImpl)target).getFD(); - } - if (targetFD == null) - return IOStatus.UNSUPPORTED; - int thisFDVal = IOUtil.fdVal(fd); - int targetFDVal = IOUtil.fdVal(targetFD); - if (thisFDVal == targetFDVal) // Not supported on some configurations - return IOStatus.UNSUPPORTED; + assert !nd.transferToDirectlyNeedsPositionLock() || + Thread.holdsLock(positionLock); long n = -1; int ti = -1; @@ -440,7 +424,7 @@ public class FileChannelImpl if (!isOpen()) return -1; do { - n = transferTo0(thisFDVal, position, icount, targetFDVal); + n = transferTo0(fd, position, icount, targetFD); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNSUPPORTED_CASE) { if (target instanceof SinkChannelImpl) @@ -461,6 +445,54 @@ public class FileChannelImpl } } + private long transferToDirectly(long position, int icount, + WritableByteChannel target) + throws IOException + { + if (!transferSupported) + return IOStatus.UNSUPPORTED; + + FileDescriptor targetFD = null; + if (target instanceof FileChannelImpl) { + if (!fileSupported) + return IOStatus.UNSUPPORTED_CASE; + targetFD = ((FileChannelImpl)target).fd; + } else if (target instanceof SelChImpl) { + // Direct transfer to pipe causes EINVAL on some configurations + if ((target instanceof SinkChannelImpl) && !pipeSupported) + return IOStatus.UNSUPPORTED_CASE; + + // Platform-specific restrictions. Now there is only one: + // Direct transfer to non-blocking channel could be forbidden + SelectableChannel sc = (SelectableChannel)target; + if (!nd.canTransferToDirectly(sc)) + return IOStatus.UNSUPPORTED_CASE; + + targetFD = ((SelChImpl)target).getFD(); + } + + if (targetFD == null) + return IOStatus.UNSUPPORTED; + int thisFDVal = IOUtil.fdVal(fd); + int targetFDVal = IOUtil.fdVal(targetFD); + if (thisFDVal == targetFDVal) // Not supported on some configurations + return IOStatus.UNSUPPORTED; + + if (nd.transferToDirectlyNeedsPositionLock()) { + synchronized (positionLock) { + long pos = position(); + try { + return transferToDirectlyInternal(position, icount, + target, targetFD); + } finally { + position(pos); + } + } + } else { + return transferToDirectlyInternal(position, icount, target, targetFD); + } + } + // Maximum size to map when using a mapped buffer private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; @@ -1176,7 +1208,8 @@ public class FileChannelImpl private static native int unmap0(long address, long length); // Transfers from src to dst, or returns -2 if kernel can't do that - private native long transferTo0(int src, long position, long count, int dst); + private native long transferTo0(FileDescriptor src, long position, + long count, FileDescriptor dst); // Sets or reports this file's position // If offset is -1, the current position is returned diff --git a/src/share/classes/sun/nio/ch/FileDispatcher.java b/src/share/classes/sun/nio/ch/FileDispatcher.java index 6e5df2250807d78e9a125cb2e9c2c3b0ce1cae29..5e9f82fc037543f331fb0b99fe928ffca43a03cd 100644 --- a/src/share/classes/sun/nio/ch/FileDispatcher.java +++ b/src/share/classes/sun/nio/ch/FileDispatcher.java @@ -25,7 +25,9 @@ package sun.nio.ch; -import java.io.*; +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.channels.SelectableChannel; abstract class FileDispatcher extends NativeDispatcher { @@ -53,4 +55,8 @@ abstract class FileDispatcher extends NativeDispatcher { */ abstract FileDescriptor duplicateForMapping(FileDescriptor fd) throws IOException; + + abstract boolean canTransferToDirectly(SelectableChannel sc); + + abstract boolean transferToDirectlyNeedsPositionLock(); } diff --git a/src/share/classes/sun/nio/ch/Net.java b/src/share/classes/sun/nio/ch/Net.java index 37823e98c550f6e8ae5a382708d508c634d5eb1f..598b4849e5bef82358ea143f4ca653f980261a84 100644 --- a/src/share/classes/sun/nio/ch/Net.java +++ b/src/share/classes/sun/nio/ch/Net.java @@ -50,30 +50,8 @@ public class Net { // set to true if exclusive binding is on for Windows private static final boolean exclusiveBind; - static { - int availLevel = isExclusiveBindAvailable(); - if (availLevel >= 0) { - String exclBindProp = - java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - return System.getProperty( - "sun.net.useExclusiveBind"); - } - }); - if (exclBindProp != null) { - exclusiveBind = exclBindProp.length() == 0 ? - true : Boolean.parseBoolean(exclBindProp); - } else if (availLevel == 1) { - exclusiveBind = true; - } else { - exclusiveBind = false; - } - } else { - exclusiveBind = false; - } - } + // set to true if the fast tcp loopback should be enabled on Windows + private static final boolean fastLoopback; // -- Miscellaneous utilities -- @@ -391,6 +369,23 @@ public class Net { } } + public static boolean isFastTcpLoopbackRequested() { + String loopbackProp = java.security.AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public String run() { + return System.getProperty("jdk.net.useFastTcpLoopback"); + } + }); + boolean enable; + if ("".equals(loopbackProp)) { + enable = true; + } else { + enable = Boolean.parseBoolean(loopbackProp); + } + return enable; + } + // -- Socket operations -- private static native boolean isIPv6Available0(); @@ -413,15 +408,16 @@ public class Net { throws IOException { boolean preferIPv6 = isIPv6Available() && (family != StandardProtocolFamily.INET); - return IOUtil.newFD(socket0(preferIPv6, stream, false)); + return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback)); } static FileDescriptor serverSocket(boolean stream) { - return IOUtil.newFD(socket0(isIPv6Available(), stream, true)); + return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback)); } // Due to oddities SO_REUSEADDR on windows reuse is ignored - private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse); + private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse, + boolean fastLoopback); public static void bind(FileDescriptor fd, InetAddress addr, int port) throws IOException @@ -634,4 +630,30 @@ public class Net { POLLCONN = pollconnValue(); } + static { + int availLevel = isExclusiveBindAvailable(); + if (availLevel >= 0) { + String exclBindProp = + java.security.AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public String run() { + return System.getProperty( + "sun.net.useExclusiveBind"); + } + }); + if (exclBindProp != null) { + exclusiveBind = exclBindProp.length() == 0 ? + true : Boolean.parseBoolean(exclBindProp); + } else if (availLevel == 1) { + exclusiveBind = true; + } else { + exclusiveBind = false; + } + } else { + exclusiveBind = false; + } + + fastLoopback = isFastTcpLoopbackRequested(); + } } diff --git a/src/share/native/java/net/net_util.h b/src/share/native/java/net/net_util.h index 246c0549e7f0768f1c7c7606320e2094b64c0621..60d63fcb6b70694bd622b6e4520d4917fea54111 100644 --- a/src/share/native/java/net/net_util.h +++ b/src/share/native/java/net/net_util.h @@ -182,9 +182,13 @@ NET_MapSocketOption(jint cmd, int *level, int *optname); JNIEXPORT int JNICALL NET_MapSocketOptionV6(jint cmd, int *level, int *optname); +JNIEXPORT jint JNICALL +NET_EnableFastTcpLoopback(int fd); + int getScopeID (struct sockaddr *); int cmpScopeID (unsigned int, struct sockaddr *); unsigned short in_cksum(unsigned short *addr, int len); + #endif /* NET_UTILS_H */ diff --git a/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java b/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java index 2c7504caa4a11225cdf8474f7c299a5ec2654c39..3b8894825ba32228e9b63b3c06ac56b9dcacc2ff 100644 --- a/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java @@ -25,10 +25,10 @@ package sun.nio.ch; -import java.io.*; +import java.io.FileDescriptor; +import java.io.IOException; -class FileDispatcherImpl extends FileDispatcher -{ +class FileDispatcherImpl extends FileDispatcher { static { IOUtil.load(); @@ -108,6 +108,14 @@ class FileDispatcherImpl extends FileDispatcher return new FileDescriptor(); } + boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) { + return true; + } + + boolean transferToDirectlyNeedsPositionLock() { + return false; + } + // -- Native methods -- static native int read0(FileDescriptor fd, long address, int len) diff --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c index 769e5405024914d5f48e4395aff932949341bc48..67da52316a98918416769a974e3e453e2bf31a9c 100644 --- a/src/solaris/native/java/net/net_util_md.c +++ b/src/solaris/native/java/net/net_util_md.c @@ -777,6 +777,11 @@ void parseExclusiveBindProperty(JNIEnv *env) { #endif } +JNIEXPORT jint JNICALL +NET_EnableFastTcpLoopback(int fd) { + return 0; +} + /* In the case of an IPv4 Inetaddress this method will return an * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE. * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress. diff --git a/src/solaris/native/sun/nio/ch/FileChannelImpl.c b/src/solaris/native/sun/nio/ch/FileChannelImpl.c index 895289067d66ace549573bf3ee586e7cb178a78a..d8face71c37b74ab8613008608ae34404e9f0098 100644 --- a/src/solaris/native/sun/nio/ch/FileChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/FileChannelImpl.c @@ -154,10 +154,13 @@ Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, - jint srcFD, + jobject srcFDO, jlong position, jlong count, - jint dstFD) + jobject dstFDO) { + jint srcFD = fdval(env, srcFDO); + jint dstFD = fdval(env, dstFDO); + #if defined(__linux__) off64_t offset = (off64_t)position; jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count); diff --git a/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c index ae7f5794316527d1c77c5b7ec08bd06c93625ced..73560ad6c62dc6c1c33c7dc54651b9426207cf99 100644 --- a/src/solaris/native/sun/nio/ch/Net.c +++ b/src/solaris/native/sun/nio/ch/Net.c @@ -231,7 +231,7 @@ Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) JNIEXPORT int JNICALL Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, - jboolean stream, jboolean reuse) + jboolean stream, jboolean reuse, jboolean ignored) { int fd; int type = (stream ? SOCK_STREAM : SOCK_DGRAM); diff --git a/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java index ccab64d12a453c04a5285faf9c594d4f33427138..117bcb147f8338710c696b73b3ed47762774426c 100644 --- a/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -25,15 +25,16 @@ package sun.nio.ch; -import java.io.*; +import java.io.FileDescriptor; +import java.io.IOException; +import java.security.PrivilegedAction; import sun.misc.SharedSecrets; import sun.misc.JavaIOFileDescriptorAccess; -class FileDispatcherImpl extends FileDispatcher -{ - static { - IOUtil.load(); - } +class FileDispatcherImpl extends FileDispatcher { + + // set to true if fast file transmission (TransmitFile) is enabled + private static final boolean fastFileTransfer; /** * Indicates if the dispatcher should first advance the file position @@ -120,6 +121,36 @@ class FileDispatcherImpl extends FileDispatcher return result; } + boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) { + return fastFileTransfer && sc.isBlocking(); + } + + boolean transferToDirectlyNeedsPositionLock() { + return true; + } + + static boolean isFastFileTransferRequested() { + String fileTransferProp = java.security.AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public String run() { + return System.getProperty("jdk.net.enableFastFileTransfer"); + } + }); + boolean enable; + if ("".equals(fileTransferProp)) { + enable = true; + } else { + enable = Boolean.parseBoolean(fileTransferProp); + } + return enable; + } + + static { + IOUtil.load(); + fastFileTransfer = isFastFileTransferRequested(); + } + //-- Native methods static native int read0(FileDescriptor fd, long address, int len) diff --git a/src/windows/native/java/net/net_util_md.c b/src/windows/native/java/net/net_util_md.c index 274d90995bac49d7c673ec906a749afdbf2c6ecc..9acffcaab39ffb6953114e523db2dbaa9f56dee1 100644 --- a/src/windows/native/java/net/net_util_md.c +++ b/src/windows/native/java/net/net_util_md.c @@ -29,6 +29,9 @@ #include "net_util.h" #include "jni.h" +// Taken from mstcpip.h in Windows SDK 8.0 or newer. +#define SIO_LOOPBACK_FAST_PATH _WSAIOW(IOC_VENDOR,16) + #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e #endif @@ -844,6 +847,25 @@ jint getDefaultIPv6Interface(JNIEnv *env, struct SOCKADDR_IN6 *target_addr) } } +/** + * Enables SIO_LOOPBACK_FAST_PATH + */ +JNIEXPORT jint JNICALL +NET_EnableFastTcpLoopback(int fd) { + int enabled = 1; + DWORD result_byte_count = -1; + int result = WSAIoctl(fd, + SIO_LOOPBACK_FAST_PATH, + &enabled, + sizeof(enabled), + NULL, + 0, + &result_byte_count, + NULL, + NULL); + return result == SOCKET_ERROR ? WSAGetLastError() : 0; +} + /* If address types is IPv6, then IPv6 must be available. Otherwise * no address can be generated. In the case of an IPv4 Inetaddress this * method will return an IPv4 mapped address where IPv6 is available and diff --git a/src/windows/native/sun/nio/ch/FileChannelImpl.c b/src/windows/native/sun/nio/ch/FileChannelImpl.c index 89215f2b5817e875763f7dac7402b12f6a77e0e8..cb72478e8674aa8ca80a98d0c173ac17cd4c9420 100644 --- a/src/windows/native/sun/nio/ch/FileChannelImpl.c +++ b/src/windows/native/sun/nio/ch/FileChannelImpl.c @@ -31,6 +31,10 @@ #include "nio.h" #include "nio_util.h" #include "sun_nio_ch_FileChannelImpl.h" +#include "java_lang_Integer.h" + +#include +#pragma comment(lib, "Mswsock.lib") static jfieldID chan_fd; /* id for jobject 'fd' in java.io.FileChannel */ @@ -174,9 +178,42 @@ Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo) JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, - jint srcFD, + jobject srcFD, jlong position, jlong count, - jint dstFD) + jobject dstFD) { - return IOS_UNSUPPORTED; + const int PACKET_SIZE = 524288; + + HANDLE src = (HANDLE)(handleval(env, srcFD)); + SOCKET dst = (SOCKET)(fdval(env, dstFD)); + DWORD chunkSize = (count > java_lang_Integer_MAX_VALUE) ? + java_lang_Integer_MAX_VALUE : (DWORD)count; + BOOL result = 0; + + jlong pos = Java_sun_nio_ch_FileChannelImpl_position0(env, this, srcFD, position); + if (pos == IOS_THROWN) { + return IOS_THROWN; + } + + result = TransmitFile( + dst, + src, + chunkSize, + PACKET_SIZE, + NULL, + NULL, + TF_USE_KERNEL_APC + ); + if (!result) { + int error = WSAGetLastError(); + if (WSAEINVAL == error && count >= 0) { + return IOS_UNSUPPORTED_CASE; + } + if (WSAENOTSOCK == error) { + return IOS_UNSUPPORTED_CASE; + } + JNU_ThrowIOExceptionWithLastError(env, "transfer failed"); + return IOS_THROWN; + } + return chunkSize; } diff --git a/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c index fb0faa87b84fa90a34826eb0aa01cc9b182e6c63..e68951b839061522d28903f7dfa41a43edf69411 100644 --- a/src/windows/native/sun/nio/ch/Net.c +++ b/src/windows/native/sun/nio/ch/Net.c @@ -127,7 +127,7 @@ Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, - jboolean stream, jboolean reuse) + jboolean stream, jboolean reuse, jboolean fastLoopback) { SOCKET s; int domain = (preferIPv6) ? AF_INET6 : AF_INET; @@ -152,6 +152,20 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, NET_ThrowNew(env, WSAGetLastError(), "socket"); } + if (stream && fastLoopback) { + static int loopback_available = 1; + if (loopback_available) { + int rv = NET_EnableFastTcpLoopback((jint)s); + if (rv) { + if (rv == WSAEOPNOTSUPP) { + loopback_available = 0; + } else { + NET_ThrowNew(env, rv, "fastLoopback"); + } + } + } + } + return (jint)s; } diff --git a/test/com/sun/corba/5036554/TestCorbaBug.sh b/test/com/sun/corba/5036554/TestCorbaBug.sh index 7e057e72c387d9eb270ccc2797cd7f8c13a9425b..09cbed3cd5bd834f44c050623d6066cd80548482 100644 --- a/test/com/sun/corba/5036554/TestCorbaBug.sh +++ b/test/com/sun/corba/5036554/TestCorbaBug.sh @@ -75,13 +75,13 @@ ${TESTJAVA}${FS}bin${FS}java -version mkdir bug cp ${TESTSRC}${FS}bug.idl . -${TESTJAVA}${FS}bin${FS}idlj bug.idl +${COMPILEJAVA}${FS}bin${FS}idlj bug.idl cp ${TESTSRC}${FS}JavaBug.java bug chmod -fR 777 bug -${TESTJAVA}${FS}bin${FS}javac -d . bug${FS}*.java +${COMPILEJAVA}${FS}bin${FS}javac -d . bug${FS}*.java ${TESTJAVA}${FS}bin${FS}java -cp . bug/JavaBug > test.out 2>&1 diff --git a/test/com/sun/corba/cachedSocket/7056731.sh b/test/com/sun/corba/cachedSocket/7056731.sh index 3b58ad6e632e2fbfc677827320b1cc4d4930e0ec..0d7c036a702fb8a4094774d7e8f1564754959993 100644 --- a/test/com/sun/corba/cachedSocket/7056731.sh +++ b/test/com/sun/corba/cachedSocket/7056731.sh @@ -55,8 +55,8 @@ PORT=1052 cp -r ${TESTSRC}${FS}*.java ${TESTSRC}${FS}Hello.idl . echo "Testing...please wait" -${TESTJAVA}${FS}bin${FS}idlj -fall Hello.idl -${TESTJAVA}${FS}bin${FS}javac *.java HelloApp/*.java +${COMPILEJAVA}${FS}bin${FS}idlj -fall Hello.idl +${COMPILEJAVA}${FS}bin${FS}javac *.java HelloApp/*.java echo "starting orbd" ${TESTJAVA}${FS}bin${FS}orbd -ORBInitialPort $PORT -ORBInitialHost localhost & diff --git a/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java index 46b326bde06a8af702d8c8224f565134c8bf09de..4627aaa2a5a5401a05224dd39e2226c636ef8cff 100644 --- a/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java +++ b/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java @@ -24,6 +24,8 @@ /* @test * @bug 6834246 6842687 * @summary Stress test connections through the loopback interface + * @run main StressLoopback + * @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback */ import java.nio.ByteBuffer; diff --git a/test/java/nio/channels/FileChannel/TransferToChannel.java b/test/java/nio/channels/FileChannel/TransferToChannel.java index 05069d296dc88f05215f265c4e8a879bc82ed9cb..2aa1b4bd2cced27aa95293d4d3afc993ef56ece5 100644 --- a/test/java/nio/channels/FileChannel/TransferToChannel.java +++ b/test/java/nio/channels/FileChannel/TransferToChannel.java @@ -24,6 +24,8 @@ /* @test * @bug 4652496 * @summary Test transferTo with different target channels + * @run main TransferToChannel + * @run main/othervm -Djdk.net.enableFastFileTransfer TransferToChannel */ import java.nio.channels.FileChannel;