1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl.h" 27 #include "nio.h" 28 #include "nio_util.h" 29 #include <Rsocket.h> 30 31 static jfieldID fd_fdID; 32 33 jint 34 convertReturnVal(JNIEnv *env, jint n, jboolean reading) { 35 if (n > 0) 36 return n; 37 else if (n == 0) { 38 if (reading) { 39 return IOS_EOF; 40 } else { 41 return 0; 42 } 43 } 44 else if (errno == EAGAIN) 45 return IOS_UNAVAILABLE; 46 else if (errno == EINTR) 47 return IOS_INTERRUPTED; 48 else { 49 const char *msg = reading ? "Read failed" : "Write failed"; 50 JNU_ThrowIOExceptionWithLastError(env, msg); 51 return IOS_THROWN; 52 } 53 } 54 55 jlong 56 convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) { 57 if (n > 0) 58 return n; 59 else if (n == 0) { 60 if (reading) { 61 return IOS_EOF; 62 } else { 63 return 0; 64 } 65 } 66 else if (errno == EAGAIN) 67 return IOS_UNAVAILABLE; 68 else if (errno == EINTR) 69 return IOS_INTERRUPTED; 70 else { 71 const char *msg = reading ? "Read failed" : "Write failed"; 72 JNU_ThrowIOExceptionWithLastError(env, msg); 73 return IOS_THROWN; 74 } 75 } 76 77 JNIEXPORT void JNICALL 78 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_init(JNIEnv *env, 79 jclass cl) { 80 loadRdmaFuncs(env); 81 CHECK_NULL(cl = (*env)->FindClass(env, "java/io/FileDescriptor")); 82 CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, cl, "fd", "I")); 83 } 84 85 JNIEXPORT jint JNICALL 86 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_read0(JNIEnv *env, 87 jclass clazz, jobject fdo, jlong address, jint len) { 88 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 89 void *buf = (void *)jlong_to_ptr(address); 90 jint result = convertReturnVal(env, rs_read(fd, buf, len), JNI_TRUE); 91 if (result == IOS_UNAVAILABLE 92 && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking 93 struct pollfd pfd[1]; 94 pfd[0].fd = fd; 95 pfd[0].events = POLLIN; 96 rs_poll(pfd, 1, -1); 97 if (pfd[0].revents & POLLIN) 98 result = convertReturnVal(env, rs_read(fd, buf, len), JNI_TRUE); 99 else { 100 JNU_ThrowIOExceptionWithLastError(env, "Read failed"); 101 return IOS_THROWN; 102 } 103 } 104 return result; 105 } 106 107 JNIEXPORT jlong JNICALL 108 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_readv0(JNIEnv *env, 109 jclass clazz, jobject fdo, jlong address, jint len) { 110 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 111 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 112 jlong result = convertLongReturnVal(env, rs_readv(fd, iov, len), JNI_TRUE); 113 if (result == IOS_UNAVAILABLE 114 && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking 115 struct pollfd pfd[1]; 116 pfd[0].fd = fd; 117 pfd[0].events = POLLIN; 118 rs_poll(pfd, 1, -1); 119 if (pfd[0].revents & POLLIN) 120 result = convertLongReturnVal(env, rs_readv(fd, iov, len), JNI_TRUE); 121 else { 122 JNU_ThrowIOExceptionWithLastError(env, "Read failed"); 123 return IOS_THROWN; 124 } 125 } 126 return result; 127 } 128 129 JNIEXPORT jint JNICALL 130 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_write0(JNIEnv *env, 131 jclass clazz, jobject fdo, jlong address, jint len) { 132 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 133 void *buf = (void *)jlong_to_ptr(address); 134 jint result = convertReturnVal(env, rs_write(fd, buf, len), JNI_FALSE); 135 if (result == IOS_UNAVAILABLE 136 && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking 137 struct pollfd pfd[1]; 138 pfd[0].fd = fd; 139 pfd[0].events = POLLOUT; 140 rs_poll(pfd, 1, -1); 141 if (pfd[0].revents & POLLOUT) 142 result = convertReturnVal(env, rs_write(fd, buf, len), JNI_FALSE); 143 else { 144 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 145 return IOS_THROWN; 146 } 147 } 148 return result; 149 } 150 151 JNIEXPORT jlong JNICALL 152 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_writev0(JNIEnv *env, 153 jclass clazz, jobject fdo, jlong address, jint len) { 154 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 155 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 156 jlong result = convertLongReturnVal(env, rs_writev(fd, iov, len), 157 JNI_FALSE); 158 if (result == IOS_UNAVAILABLE 159 && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking 160 struct pollfd pfd[1]; 161 pfd[0].fd = fd; 162 pfd[0].events = POLLOUT; 163 rs_poll(pfd, 1, -1); 164 if (pfd[0].revents & POLLOUT) 165 result = convertLongReturnVal(env, rs_writev(fd, iov, len), JNI_FALSE); 166 else { 167 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 168 return IOS_THROWN; 169 } 170 } 171 return result; 172 } 173 174 static void closeFileDescriptor(JNIEnv *env, int fd) { 175 if (fd != -1) { 176 int result = rs_close(fd); 177 if (result < 0) 178 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 179 } 180 } 181 182 JNIEXPORT void JNICALL 183 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_close0(JNIEnv *env, 184 jclass clazz, jobject fdo) { 185 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 186 closeFileDescriptor(env, fd); 187 }