--- old/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c 2016-09-29 14:26:28.724927343 -0700 +++ new/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c 2016-09-29 14:26:28.524927341 -0700 @@ -34,6 +34,8 @@ #include #include #include +#include +#include #if defined(__linux__) #include #include @@ -58,7 +60,7 @@ static int preCloseFD = -1; /* File descriptor to which we dup other fd's before closing them for real */ - +static int pageSize = -1; JNIEXPORT void JNICALL Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) @@ -70,6 +72,75 @@ } preCloseFD = sp[0]; close(sp[1]); + + pageSize = getpagesize(); +} + +jint readDirect(JNIEnv *env, jclass clazz, jint fd, jlong offset, jint len, void *buf, jint pageSize) +{ + int gap = 0; + int newLen = -1; + long newStartLocation = -1; + void *bytes = NULL; + int nread = -1; + + newStartLocation = offset; + if ((newStartLocation % pageSize) != 0) { + newStartLocation = offset / pageSize * pageSize; + gap = offset - newStartLocation; + } + + lseek(fd, newStartLocation, SEEK_SET); + + newLen = len; + if ((newLen % pageSize) != 0) { + newLen = (len / pageSize + 1) * pageSize; + } + + if ((newLen - gap) < len) { + newLen = newLen + pageSize; + } + + posix_memalign(&bytes, pageSize, newLen); + + nread = read(fd, bytes, newLen); + + if (nread > gap) { + if ((nread - gap) >= len) { + memcpy(buf, bytes+gap, len); + nread = len; + } else { + memcpy(buf, bytes+gap, (nread-gap)); + nread = nread - gap; + } + } else if (nread == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Read error"); + } else { /*EOF*/ + nread = 0; + } + + free(bytes); + + return nread; +} + +jint writeDirect(JNIEnv *env, jclass clazz, jint fd, jlong offset, jint len, void *buf, jint pageSize) +{ + void *bytes = NULL; + int nwrite = -1; + posix_memalign(&bytes, pageSize, len); + memcpy(bytes, buf, len); + + lseek(fd, offset, SEEK_SET); + + nwrite = write(fd, bytes, len); + if (nwrite == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Write error"); + } + + free(bytes); + + return nwrite; } JNIEXPORT jint JNICALL @@ -83,6 +154,23 @@ } JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_readDirect0(JNIEnv *env, jclass clazz, + jobject fdo, jlong address, jint len) +{ + jint fd = fdval(env, fdo); + void *buf = (void *)jlong_to_ptr(address); + long currentLocation = lseek(fd, 0, SEEK_CUR); + + if (currentLocation % pageSize == 0 && len % pageSize == 0 && address % pageSize == 0) { + return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); + } + + int nread = readDirect(env, clazz, fd, currentLocation, len, buf, pageSize); + lseek(fd, (currentLocation + nread), SEEK_SET); + return convertReturnVal(env, nread, JNI_TRUE); +} + +JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { @@ -92,15 +180,111 @@ return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_preadDirect0(JNIEnv *env, jclass clazz, jobject fdo, + jlong address, jint len, jlong offset) +{ + jint fd = fdval(env, fdo); + void *buf = (void *)jlong_to_ptr(address); + + long currentLocation = lseek(fd, 0, SEEK_CUR); + + if (offset % pageSize == 0 && len % pageSize == 0 && address % pageSize == 0) { + return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE); + } + + int nread = readDirect(env, clazz, fd, offset, len, buf, pageSize); + lseek(fd, currentLocation, SEEK_SET); + return convertReturnVal(env, nread, JNI_TRUE); +} + JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); struct iovec *iov = (struct iovec *)jlong_to_ptr(address); + return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_readvDirect0(JNIEnv *env, jclass clazz, + jobject fdo, jlong address, jint len) +{ + int i; + int totalLen = 0; + int newLen = 0; + int gap = 0; + int nread = 0; + int result = 0; + void *bytes = NULL; + long currentLocation = -1; + long newStartLocation = -1; + + jint fd = fdval(env, fdo); + struct iovec *iov = (struct iovec *)jlong_to_ptr(address); + + currentLocation = lseek(fd, 0, SEEK_CUR); + newStartLocation = currentLocation; + if ((newStartLocation % pageSize) != 0) { + newStartLocation = currentLocation / pageSize * pageSize; + gap = currentLocation - newStartLocation; + } + + lseek(fd, newStartLocation, SEEK_SET); + + for (i = 0; i < len; i++) { + totalLen += iov[i].iov_len; + } + + newLen = totalLen; + if ((newLen % pageSize) != 0) { + newLen = (totalLen / pageSize + 1) * pageSize; + } + + if ((newLen - gap) < totalLen) { + newLen += pageSize; + } + + posix_memalign(&bytes, pageSize, newLen); + nread = read(fd, bytes, newLen); + + if (nread > gap) { + if ((nread - gap) >= totalLen) { + nread = totalLen; + } else { + nread -= gap; + } + } else if (nread == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Read error"); + } else { /*EOF*/ + nread = 0; + } + + i = 0; + int tempLen; + while (nread > 0) { + tempLen = iov[i].iov_len; + if (nread >= tempLen) { + memcpy(iov[i].iov_base, (bytes + gap + result), tempLen); + result += tempLen; + nread -= tempLen; + } else { + memcpy(iov[i].iov_base, (bytes + gap + result), nread); + result += nread; + nread = 0; + } + i++; + } + + free(bytes); + + lseek(fd, (currentLocation + result), SEEK_SET); + + return convertLongReturnVal(env, result, JNI_TRUE); +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) @@ -112,6 +296,31 @@ } JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_writeDirect0(JNIEnv *env, jclass clazz, + jobject fdo, jlong address, jint len) +{ + jint fd = fdval(env, fdo); + void *buf = (void *)jlong_to_ptr(address); + + long currentLocation = lseek(fd, 0, SEEK_CUR); + + if ((len % pageSize != 0) || (currentLocation % pageSize != 0)) { + JNU_ThrowByNameWithMessageAndLastError(env, "java/io/IOException", + "In DirectIO mode, the IO size and currentLocation must be aligned with kernel page size"); + } + + if (address % pageSize == 0) { + return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); + } + + int nwrite = writeDirect(env, clazz, fd, currentLocation, len, buf, pageSize); + + lseek(fd, (currentLocation + nwrite), SEEK_SET); + + return convertReturnVal(env, nwrite, JNI_FALSE); +} + +JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { @@ -121,15 +330,85 @@ return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_FileDispatcherImpl_pwriteDirect0(JNIEnv *env, jclass clazz, jobject fdo, + jlong address, jint len, jlong offset) +{ + jint fd = fdval(env, fdo); + void *buf = (void *)jlong_to_ptr(address); + + if ((len % pageSize != 0) || (offset % pageSize != 0)) { + JNU_ThrowByNameWithMessageAndLastError(env, "java/io/IOException", + "In DirectIO mode, the IO size and offset must be aligned with kernel page size"); + } + + if (address % pageSize == 0) { + return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE); + } + + long currentLocation = lseek(fd, 0, SEEK_CUR); + + int nwrite = writeDirect(env, clazz, fd, offset, len, buf, pageSize); + + lseek(fd, currentLocation, SEEK_SET); + + return convertReturnVal(env, nwrite, JNI_FALSE); +} + JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len) { jint fd = fdval(env, fdo); struct iovec *iov = (struct iovec *)jlong_to_ptr(address); + return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_writevDirect0(JNIEnv *env, jclass clazz, + jobject fdo, jlong address, jint len) +{ + int i; + int totalLen = 0; + int currentLocation = -1; + int nwrite = 0; + int result = 0; + void *bytes = NULL; + + jint fd = fdval(env, fdo); + struct iovec *iov = (struct iovec *)jlong_to_ptr(address); + + for (i = 0; i < len; i++) { + totalLen += iov[i].iov_len; + } + + currentLocation = lseek(fd, 0, SEEK_CUR); + + if ((totalLen % pageSize != 0) || (currentLocation % pageSize != 0)) { + JNU_ThrowByNameWithMessageAndLastError(env, "java/io/IOException", + "In DirectIO mode, the IO size and offset must be aligned with kernel page size"); + } + + posix_memalign(&bytes, pageSize, totalLen); + + int tempLen; + for (i = 0; i < len; i++) { + tempLen = iov[i].iov_len; + memcpy((bytes + result), iov[i].iov_base, tempLen); + result += tempLen; + } + nwrite = write(fd, bytes, totalLen); + if (nwrite == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Write error"); + } + + free(bytes); + + return convertLongReturnVal(env, nwrite, JNI_FALSE); + +} + static jlong handle(JNIEnv *env, jlong rv, char *msg) {