--- old/make/mapfiles/libjava/mapfile-vers 2016-08-25 17:51:52.242564682 -0700 +++ new/make/mapfiles/libjava/mapfile-vers 2016-08-25 17:51:52.137564681 -0700 @@ -83,12 +83,17 @@ Java_java_io_FileInputStream_open0; Java_java_io_FileInputStream_read0; Java_java_io_FileInputStream_readBytes; + Java_java_io_FileInputStream_getPageSize0; + Java_java_io_FileInputStream_readBytesD; Java_java_io_FileInputStream_skip; Java_java_io_FileOutputStream_close0; Java_java_io_FileOutputStream_initIDs; + Java_java_io_FileOutputStream_getPageSize0; Java_java_io_FileOutputStream_open0; Java_java_io_FileOutputStream_write; Java_java_io_FileOutputStream_writeBytes; + Java_java_io_FileOutputStream_writeBytesD; + Java_java_io_FileOutputStream_getCurrentLocation0; Java_java_io_ObjectInputStream_bytesToDoubles; Java_java_io_ObjectInputStream_bytesToFloats; Java_java_io_ObjectOutputStream_doublesToBytes; @@ -102,10 +107,14 @@ Java_java_io_RandomAccessFile_open0; Java_java_io_RandomAccessFile_read0; Java_java_io_RandomAccessFile_readBytes; + Java_java_io_RandomAccessFile_getPageSize0; + Java_java_io_RandomAccessFile_readBytesD; Java_java_io_RandomAccessFile_seek0; + Java_java_io_RandomAccessFile_getCurrentLocation0; Java_java_io_RandomAccessFile_setLength; Java_java_io_RandomAccessFile_write0; Java_java_io_RandomAccessFile_writeBytes; + Java_java_io_RandomAccessFile_writeBytesD; Java_java_io_UnixFileSystem_canonicalize0; Java_java_io_UnixFileSystem_checkAccess; Java_java_io_UnixFileSystem_createDirectory; --- old/src/java.base/share/classes/java/io/FileInputStream.java 2016-08-25 17:51:52.487564684 -0700 +++ new/src/java.base/share/classes/java/io/FileInputStream.java 2016-08-25 17:51:52.384564683 -0700 @@ -62,6 +62,9 @@ private final AtomicBoolean closed = new AtomicBoolean(false); + private boolean direct = false; + + private int pageSize = -1; /** * Creates a FileInputStream by * opening a connection to an actual file, @@ -94,6 +97,41 @@ } /** + * Creates a FileInputStream by + * opening a connection to an actual file, + * the file named by the path name name + * in the file system. If the second parameter is + * true, bytes are directly read from + * storage media. A new FileDescriptor + * object is created to represent this file connection. + *

+ * First, if there is a security + * manager, its checkRead method + * is called with the name argument + * as its argument. + *

+ * If the named file does not exist, is a directory rather than a regular + * file, or for some other reason cannot be opened for reading then a + * FileNotFoundException is thrown. + * + * @param name the system-dependent file name. + * @param direct if true, then bytes will be read + * directly to storage media + * @exception FileNotFoundException if the file does not exist, + * is a directory rather than a regular file, + * or for some other reason cannot be opened for + * reading. + * @exception SecurityException if a security manager exists and its + * checkRead method denies read access + * to the file. + * @see java.lang.SecurityManager#checkRead(java.lang.String) + * @since 1.9 + */ + public FileInputStream(String name, boolean direct) throws FileNotFoundException { + this(name != null ? new File(name): null, direct); + } + + /** * Creates a FileInputStream by * opening a connection to an actual file, * the file named by the File @@ -121,21 +159,7 @@ * @see java.lang.SecurityManager#checkRead(java.lang.String) */ public FileInputStream(File file) throws FileNotFoundException { - String name = (file != null ? file.getPath() : null); - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkRead(name); - } - if (name == null) { - throw new NullPointerException(); - } - if (file.isInvalid()) { - throw new FileNotFoundException("Invalid file path"); - } - fd = new FileDescriptor(); - fd.attach(this); - path = name; - open(name); + this(file, false); } /** @@ -180,11 +204,54 @@ fd.attach(this); } + /** + * Creates a FileInputStream by opening a connection to an + * actual file with O_DIRECT option, the file named by the + * File object file in the file system. A new + * FileDescriptor object is created to represent this file connection. + *

+ * First, if there is a security manager, its checkRead + * method is called with the path represented by the file + * argument as its argument. + *

+ * If the named file does not exist, is a directory rather than a regular + * file, or for some other reason cannot be opened for reading then a + * FileNotFoundException is thrown. + * @param file the file to be opened for reading. + * @param direct if true, then bytes will be read + * directly to storage media + * @exception FileNotFoundException if the file does not exist, is a + * directory rather than a regular file, or for some + * other reason cannot be opened for reading. + * @exception SecurityException if a security manager exists + */ + public FileInputStream(File file, boolean direct) throws FileNotFoundException { + this.direct = direct; + if (direct) { + getPageSize(); + } + String name = (file != null ? file.getPath() : null); + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkRead(name); + } + if (name == null) { + throw new NullPointerException(); + } + if (file.isInvalid()) { + throw new FileNotFoundException("Invalid file path"); + } + fd = new FileDescriptor(); + fd.attach(this); + path = name; + open(name); + } + /** * Opens the specified file for reading. * @param name the name of the file */ - private native void open0(String name) throws FileNotFoundException; + private native void open0(String name, boolean direct) throws FileNotFoundException; // wrap native call to allow instrumentation /** @@ -192,7 +259,16 @@ * @param name the name of the file */ private void open(String name) throws FileNotFoundException { - open0(name); + open0(name, direct); + } + + private native int getPageSize0(); + + private int getPageSize() { + if (pageSize == -1) { + pageSize = getPageSize0(); + } + return this.pageSize; } /** @@ -219,6 +295,15 @@ private native int readBytes(byte b[], int off, int len) throws IOException; /** + * Reads a subarray as a sequence of bytes with DirectIO. + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @exception IOException If an I/O error has occurred. + */ + private native int readBytesD(byte b[], int off, int len) throws IOException; + + /** * Reads up to b.length bytes of data from this input * stream into an array of bytes. This method blocks until some input * is available. @@ -230,6 +315,8 @@ * @exception IOException if an I/O error occurs. */ public int read(byte b[]) throws IOException { + if (direct) + return readBytesD(b, 0, b.length); return readBytes(b, 0, b.length); } @@ -252,6 +339,8 @@ * @exception IOException if an I/O error occurs. */ public int read(byte b[], int off, int len) throws IOException { + if (direct) + return readBytesD(b, off, len); return readBytes(b, off, len); } --- old/src/java.base/share/classes/java/io/FileOutputStream.java 2016-08-25 17:51:52.726564686 -0700 +++ new/src/java.base/share/classes/java/io/FileOutputStream.java 2016-08-25 17:51:52.624564685 -0700 @@ -79,6 +79,10 @@ private final AtomicBoolean closed = new AtomicBoolean(false); + private boolean direct = false; + + private int pageSize = -1; + /** * Creates a file output stream to write to the file with the * specified name. A new FileDescriptor object is @@ -101,7 +105,7 @@ * @see java.lang.SecurityManager#checkWrite(java.lang.String) */ public FileOutputStream(String name) throws FileNotFoundException { - this(name != null ? new File(name) : null, false); + this(name != null ? new File(name) : null, false, false); } /** @@ -133,7 +137,42 @@ public FileOutputStream(String name, boolean append) throws FileNotFoundException { - this(name != null ? new File(name) : null, append); + this(name != null ? new File(name) : null, append, false); + } + + /** + * Creates a file output stream to write to the file with the specified + * name. If the second argument is true, then bytes will + * be written to the end of the file rather than the beginning. If the + * third parameter is true, then bytes will be directly + * written to storage media. A new FileDescriptor object + * is created to represent this file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with name as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param name the system-dependent file name + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @param direct if true, then bytes will be written + * directly to storage media + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason. + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since 1.9 + */ + public FileOutputStream(String name, boolean append, boolean direct) + throws FileNotFoundException + { + this(name != null ? new File(name) : null, append, direct); } /** @@ -162,7 +201,7 @@ * @see java.lang.SecurityManager#checkWrite(java.lang.String) */ public FileOutputStream(File file) throws FileNotFoundException { - this(file, false); + this(file, false, false); } /** @@ -197,6 +236,49 @@ public FileOutputStream(File file, boolean append) throws FileNotFoundException { + this(file, append, false); + } + + /** + * Creates a file output stream to write to the file represented by + * the specified File object. If the second argument is + * true, then bytes will be written to the end of the file + * rather than the beginning. If the third argument is true, + * then bytes will be directly written to storage media. A new + * FileDescriptor object is created to represent this file + * connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with the path represented by the file + * argument as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param file the file to be opened for writing. + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @param direct if true, then bytes will be written + * directly to storage media + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.io.File#getPath() + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since 1.9 + */ + public FileOutputStream(File file, boolean append, boolean direct) + throws FileNotFoundException + { + this.direct = direct; + if (direct) { + getPageSize(); + } String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -256,8 +338,9 @@ * Opens a file, with the specified name, for overwriting or appending. * @param name name of file to be opened * @param append whether the file is to be opened in append mode + * @param direct whether the file s to be opened in the direct mode */ - private native void open0(String name, boolean append) + private native void open0(String name, boolean append, boolean direct) throws FileNotFoundException; // wrap native call to allow instrumentation @@ -268,7 +351,16 @@ */ private void open(String name, boolean append) throws FileNotFoundException { - open0(name, append); + open0(name, append, direct); + } + + private native int getPageSize0(); + + private int getPageSize() { + if (pageSize == -1) { + pageSize = getPageSize0(); + } + return this.pageSize; } /** @@ -304,6 +396,17 @@ throws IOException; /** + * Writes a sub array as a sequence of bytes with DirectIO. + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param append {@code true} to first advance the position to the + * end of file + * @exception IOException If an I/O error has occurred.*/ + private native void writeBytesD(byte b[], int off, int len, boolean append) + throws IOException; + + /** * Writes b.length bytes from the specified byte array * to this file output stream. * @@ -311,7 +414,15 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[]) throws IOException { - writeBytes(b, 0, b.length, fdAccess.getAppend(fd)); + if (direct) { + if((b.length % pageSize != 0) ||(getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size must be aligned " + + "with kernel page size " + pageSize + " bytes!"); + } + writeBytesD(b, 0, b.length, fdAccess.getAppend(fd)); + } else { + writeBytes(b, 0, b.length, fdAccess.getAppend(fd)); + } } /** @@ -324,9 +435,23 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { - writeBytes(b, off, len, fdAccess.getAppend(fd)); + if (direct) { + if((len % pageSize != 0) || (getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size and the start " + + "point must be aligned with kernel page size " + pageSize + " bytes!"); + } + writeBytesD(b, off, len, fdAccess.getAppend(fd)); + } else { + writeBytes(b, off, len, fdAccess.getAppend(fd)); + } + } + + private long getCurrentLocation() throws IOException { + return getCurrentLocation0(); } + private native long getCurrentLocation0() throws IOException; + /** * Closes this file output stream and releases any system resources * associated with this stream. This file output stream may no longer --- old/src/java.base/share/classes/java/io/RandomAccessFile.java 2016-08-25 17:51:52.967564689 -0700 +++ new/src/java.base/share/classes/java/io/RandomAccessFile.java 2016-08-25 17:51:52.863564688 -0700 @@ -64,6 +64,8 @@ private FileDescriptor fd; private volatile FileChannel channel; private boolean rw; + private boolean direct = false; + private int pageSize = -1; /** * The path of the referenced file @@ -78,6 +80,7 @@ private static final int O_SYNC = 4; private static final int O_DSYNC = 8; private static final int O_TEMPORARY = 16; + private static final int O_DIRECT = 32; /** * Creates a random access file stream to read from, and optionally @@ -216,6 +219,11 @@ int imode = -1; if (mode.equals("r")) imode = O_RDONLY; + else if (mode.equals("ro")) { + imode = O_RDONLY | O_DIRECT; + direct = true; + getPageSize(); + } else if (mode.startsWith("rw")) { imode = O_RDWR; rw = true; @@ -224,6 +232,11 @@ imode |= O_SYNC; else if (mode.equals("rwd")) imode |= O_DSYNC; + else if (mode.equals("rwo")) { + imode |= O_DIRECT; + direct = true; + getPageSize(); + } else imode = -1; } @@ -233,8 +246,8 @@ if (imode < 0) throw new IllegalArgumentException("Illegal mode \"" + mode + "\" must be one of " - + "\"r\", \"rw\", \"rws\"," - + " or \"rwd\""); + + "\"r\", \"ro\", \"rw\", \"rws\", \"rwd\"" + + " or \"rwo\""); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); @@ -338,6 +351,15 @@ open0(name, mode); } + private native int getPageSize0(); + + private int getPageSize() { + if (pageSize == -1) { + pageSize = getPageSize0(); + } + return this.pageSize; + } + // 'Read' primitives /** @@ -371,6 +393,15 @@ private native int readBytes(byte b[], int off, int len) throws IOException; /** + * Reads a sub array as a sequence of bytes with DirectIO. + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the number of bytes to read. + * @exception IOException If an I/O error has occurred. + */ + private native int readBytesD(byte b[], int off, int len) throws IOException; + + /** * Reads up to {@code len} bytes of data from this file into an * array of bytes. This method blocks until at least one byte of input * is available. @@ -396,6 +427,9 @@ * {@code b.length - off} */ public int read(byte b[], int off, int len) throws IOException { + if (direct) { + return readBytesD(b, off, len); + } return readBytes(b, off, len); } @@ -419,6 +453,9 @@ * @exception NullPointerException If {@code b} is {@code null}. */ public int read(byte b[]) throws IOException { + if (direct) { + return readBytesD(b, 0, b.length); + } return readBytes(b, 0, b.length); } @@ -529,6 +566,15 @@ private native void writeBytes(byte b[], int off, int len) throws IOException; /** + * Writes a sub array as a sequence of bytes with DirectIO. + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @exception IOException If an I/O error has occurred. + */ + private native void writeBytesD(byte b[], int off, int len) throws IOException; + + /** * Writes {@code b.length} bytes from the specified byte array * to this file, starting at the current file pointer. * @@ -536,7 +582,16 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[]) throws IOException { - writeBytes(b, 0, b.length); + if (direct) { + if((b.length % pageSize != 0) && (getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size and start point " + + "must be aligned with kernel page size " + pageSize + " bytes!"); + } else { + writeBytesD(b, 0, b.length); + } + } else { + writeBytes(b, 0, b.length); + } } /** @@ -549,7 +604,16 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { - writeBytes(b, off, len); + if (direct) { + if ((len % pageSize != 0) || (getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size and start point " + + "must be aligned with kernel page size " + pageSize + " bytes!"); + } else { + writeBytesD(b, off, len); + } + } else { + writeBytes(b, off, len); + } } // 'Random access' stuff @@ -587,6 +651,12 @@ private native void seek0(long pos) throws IOException; + private long getCurrentLocation() throws IOException { + return getCurrentLocation0(); + } + + private native long getCurrentLocation0() throws IOException; + /** * Returns the length of this file. * --- old/src/java.base/share/native/libjava/FileInputStream.c 2016-08-25 17:51:53.215564691 -0700 +++ new/src/java.base/share/native/libjava/FileInputStream.c 2016-08-25 17:51:53.111564690 -0700 @@ -42,6 +42,7 @@ /*******************************************************************/ jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */ +jfieldID fis_pgsz; /* id for jobject 'pageSize' in java.io.FileInputStream */ /************************************************************** * static methods to store field ID's in initializers @@ -50,17 +51,13 @@ JNIEXPORT void JNICALL Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) { fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;"); + fis_pgsz = (*env)->GetFieldID(env, fdClass, "pageSize", "I"); } /************************************************************** * Input stream */ -JNIEXPORT void JNICALL -Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) { - fileOpen(env, this, path, fis_fd, O_RDONLY); -} - JNIEXPORT jint JNICALL Java_java_io_FileInputStream_read0(JNIEnv *env, jobject this) { return readSingle(env, this, fis_fd); --- old/src/java.base/share/native/libjava/RandomAccessFile.c 2016-08-25 17:51:53.454564693 -0700 +++ new/src/java.base/share/native/libjava/RandomAccessFile.c 2016-08-25 17:51:53.350564692 -0700 @@ -39,32 +39,12 @@ */ jfieldID raf_fd; /* id for jobject 'fd' in java.io.RandomAccessFile */ +jfieldID raf_pgsz; /* id for jobject 'pageSize' in java.io.RandomAccessFile */ JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_initIDs(JNIEnv *env, jclass fdClass) { raf_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;"); -} - - -JNIEXPORT void JNICALL -Java_java_io_RandomAccessFile_open0(JNIEnv *env, - jobject this, jstring path, jint mode) -{ - int flags = 0; - if (mode & java_io_RandomAccessFile_O_RDONLY) - flags = O_RDONLY; - else if (mode & java_io_RandomAccessFile_O_RDWR) { - flags = O_RDWR | O_CREAT; - if (mode & java_io_RandomAccessFile_O_SYNC) - flags |= O_SYNC; - else if (mode & java_io_RandomAccessFile_O_DSYNC) - flags |= O_DSYNC; - } -#ifdef WIN32 - if (mode & java_io_RandomAccessFile_O_TEMPORARY) - flags |= O_TEMPORARY; -#endif - fileOpen(env, this, path, raf_fd, flags); + raf_pgsz = (*env)->GetFieldID(env, fdClass, "pageSize", "I"); } JNIEXPORT jint JNICALL --- old/src/java.base/share/native/libjava/io_util.c 2016-08-25 17:51:53.692564695 -0700 +++ new/src/java.base/share/native/libjava/io_util.c 2016-08-25 17:51:53.587564694 -0700 @@ -122,6 +122,103 @@ return nread; } +jint +readBytesD(JNIEnv *env, jobject this, jbyteArray bytes, + jint off, jint len, jfieldID fid, jfieldID pgsz_id) +{ +#ifdef _WIN32 + JNU_ThrowIOException(env, "DirectIO is not supported on Windows platform!"); +#else + jint nread; + void *buf = NULL; + int delta = 0; + int gap = 0; + int newLen = 0; + long currentLocation; + long newStartLocation; + FD fd; + int pageSize; + if (IS_NULL(bytes)) { + JNU_ThrowNullPointerException(env, NULL); + return -1; + } + + if (outOfBounds(env, off, len, bytes)) { + JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); + return -1; + } + + if (len == 0) { + return 0; + } + + fd = GET_FD(this, fid); + pageSize = GET_PG_SIZE(this, pgsz_id); + + if (fd == -1) { + JNU_ThrowIOException(env, "Stream Closed"); + return -1; + } else if (pageSize == -1) { + JNU_ThrowIOException(env, "Error getting kernel pageSize for DirectIO alligment"); + return -1; + } else { + currentLocation = IO_Lseek(fd, 0, SEEK_CUR); + + if ((currentLocation % pageSize) != 0) { + newStartLocation = currentLocation / pageSize * pageSize; + gap = currentLocation - newStartLocation; + } else { + newStartLocation = currentLocation; + gap = 0; + } + IO_Lseek(fd, newStartLocation, SEEK_SET); + if ((len % pageSize) != 0) { + newLen = (len / pageSize + 1) * pageSize; + } else { + newLen = len; + } + if ((newLen - gap) < len) { + newLen = newLen + pageSize; + } + + delta = newLen - len; + if (newLen == 0) { + return 0; + } else { + posix_memalign(&buf, pageSize, newLen); + if (buf == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return 0; + } + } + nread = IO_Read(fd, buf, newLen); + if (nread > 0) { + if (nread >= len) { + (*env)->SetByteArrayRegion(env, bytes, off, len, ((jbyte *)(buf) + gap)); //read in the middle of a file + } else { + (*env)->SetByteArrayRegion(env, bytes, off, (nread-gap), ((jbyte *)(buf) + gap)); //reached the end of the file + } + } else if (nread == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Read error"); + } else { /*EOF*/ + nread = -1; + } + IO_Lseek(fd, (currentLocation + len), SEEK_SET); + + free(buf); + if (nread != -1) { + if (nread >= len) { + return len; + } else { + return (nread - gap); + } + } else { + return -1; + } + } +#endif +} + void writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid) { // Discard the 24 high-order bits of byte. See OutputStream#write(int) @@ -202,6 +299,78 @@ } void +writeBytesD(JNIEnv *env, jobject this, jbyteArray bytes, + jint off, jint len, jboolean append, jfieldID fid, jfieldID pgsz_id) +{ +#ifdef _WIN32 + JNU_ThrowIOException(env, "DirectIO is not supported on Windows platform!"); +#else + jint n; + void *buf = NULL; + FD fd; + int pageSize; + long currentLocation; + + fd = GET_FD(this, fid); + if (fd == -1) { + JNU_ThrowIOException(env, "Stream Closed"); + } + + pageSize = GET_PG_SIZE(this, pgsz_id); + if (pageSize == -1) { + JNU_ThrowIOException(env, "Error getting kernel pageSize for DirectIO alligment"); + } + + currentLocation = IO_Lseek(fd, 0, SEEK_CUR); + + if ((len % pageSize != 0) || (currentLocation % pageSize != 0)) { + JNU_ThrowIOException(env, + "In DirectIO mode, the IO size and currentLocation must be aligned with kernel page size!"); + } + + if (IS_NULL(bytes)) { + JNU_ThrowNullPointerException(env, NULL); + return; + } + + if (outOfBounds(env, off, len, bytes)) { + JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); + return; + } + + if (len == 0) { + return; + } else { + posix_memalign(&buf, pageSize, len); + if (buf == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return; + } + } + + (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); + + if (!(*env)->ExceptionOccurred(env)) { + off = 0; + while (len > 0) { + if (append == JNI_TRUE) { + n = IO_Append(fd, buf+off, len); + } else { + n = IO_Write(fd, buf+off, len); + } + if (n == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Write error"); + break; + } + off += n; + len -= n; + } + } + free(buf); +#endif +} + +void throwFileNotFoundException(JNIEnv *env, jstring path) { char buf[256]; --- old/src/java.base/share/native/libjava/io_util.h 2016-08-25 17:51:53.933564698 -0700 +++ new/src/java.base/share/native/libjava/io_util.h 2016-08-25 17:51:53.828564697 -0700 @@ -29,6 +29,7 @@ extern jfieldID IO_fd_fdID; extern jfieldID IO_handle_fdID; extern jfieldID IO_append_fdID; +extern jfieldID IO_pgsz_fdID; #ifdef _ALLBSD_SOURCE #include @@ -50,9 +51,13 @@ jint readSingle(JNIEnv *env, jobject this, jfieldID fid); jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid); +jint readBytesD(JNIEnv *env, jobject this, jbyteArray bytes, jint off, + jint len, jfieldID fid, jfieldID pgsz_id); void writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid); void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jboolean append, jfieldID fid); +void writeBytesD(JNIEnv *env, jobject this, jbyteArray bytes, jint off, + jint len, jboolean append, jfieldID fid, jfieldID pgsz_id); void fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags); void throwFileNotFoundException(JNIEnv *env, jstring path); @@ -127,3 +132,6 @@ (*(env))->ReleaseStringChars(env, _##var##str, var); \ _##var##end: ; \ } else ((void)NULL) + +#define GET_PG_SIZE(this, IO_pgsz_fdID) \ + (*env)->GetIntField(env, (this), (IO_pgsz_fdID)) --- old/src/java.base/unix/native/libjava/FileInputStream_md.c 2016-08-25 17:51:54.174564700 -0700 +++ new/src/java.base/unix/native/libjava/FileInputStream_md.c 2016-08-25 17:51:54.070564699 -0700 @@ -37,12 +37,33 @@ #include "java_io_FileInputStream.h" extern jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */ +extern jfieldID fis_pgsz; /* id for jobject 'pageSize' in java.io.FileInputStream */ /********************************************************************* * Platform specific implementation of input stream native methods */ JNIEXPORT void JNICALL +Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path, jboolean direct) { + if (direct) { + fileOpen(env, this, path, fis_fd, O_RDONLY | O_DIRECT); + } else { + fileOpen(env, this, path, fis_fd, O_RDONLY); + } +} + +JNIEXPORT void JNICALL Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) { fileClose(env, this, fis_fd); } + +JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_readBytesD(JNIEnv *env, jobject this, + jbyteArray bytes, jint off, jint len) { + return readBytesD(env, this, bytes, off, len, fis_fd, fis_pgsz); +} + +JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_getPageSize0(JNIEnv *env, jobject this) { + return getpagesize(); +} --- old/src/java.base/unix/native/libjava/FileOutputStream_md.c 2016-08-25 17:51:54.417564702 -0700 +++ new/src/java.base/unix/native/libjava/FileOutputStream_md.c 2016-08-25 17:51:54.313564701 -0700 @@ -38,6 +38,7 @@ /*******************************************************************/ jfieldID fos_fd; /* id for jobject 'fd' in java.io.FileOutputStream */ +jfieldID fos_pgsz; /* id for jobject 'pageSize' in java.io.FileOutputStream */ /************************************************************** * static methods to store field ID's in initializers @@ -46,6 +47,7 @@ JNIEXPORT void JNICALL Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass fdClass) { fos_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;"); + fos_pgsz = (*env)->GetFieldID(env, fdClass, "pageSize", "I"); } /************************************************************** @@ -54,9 +56,14 @@ JNIEXPORT void JNICALL Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this, - jstring path, jboolean append) { - fileOpen(env, this, path, fos_fd, + jstring path, jboolean append, jboolean direct) { + if (direct) { + fileOpen(env, this, path, fos_fd, + O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC) | O_DIRECT); + } else { + fileOpen(env, this, path, fos_fd, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC)); + } } JNIEXPORT void JNICALL @@ -71,6 +78,34 @@ } JNIEXPORT void JNICALL +Java_java_io_FileOutputStream_writeBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len, jboolean append) { + writeBytesD(env, this, bytes, off, len, append, fos_fd, fos_pgsz); +} + +JNIEXPORT jint JNICALL +Java_java_io_FileOutputStream_getPageSize0(JNIEnv *env, jobject this) { + return getpagesize(); +} + +JNIEXPORT void JNICALL Java_java_io_FileOutputStream_close0(JNIEnv *env, jobject this) { fileClose(env, this, fos_fd); } + +JNIEXPORT jlong JNICALL +Java_java_io_FileOutputStream_getCurrentLocation0(JNIEnv *env, jobject this) { + FD fd; + + fd = GET_FD(this, fos_fd); + if (fd == -1) { + JNU_ThrowIOException(env, "Stream Closed"); + return -1; + } + jlong currentLocation = IO_Lseek(fd, 0, SEEK_CUR); + if (currentLocation == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); + } + return currentLocation; +} + --- old/src/java.base/unix/native/libjava/RandomAccessFile_md.c 2016-08-25 17:51:54.659564705 -0700 +++ new/src/java.base/unix/native/libjava/RandomAccessFile_md.c 2016-08-25 17:51:54.554564704 -0700 @@ -37,6 +37,7 @@ #include "java_io_RandomAccessFile.h" extern jfieldID raf_fd; /* id for jobject 'fd' in java.io.RandomAccessFile */ +extern jfieldID raf_pgsz; /* id for jobject 'fd' in java.io.RandomAccessFile */ /********************************************************************* * Platform specific implementation of input stream native methods @@ -46,3 +47,59 @@ Java_java_io_RandomAccessFile_close0(JNIEnv *env, jobject this) { fileClose(env, this, raf_fd); } + +JNIEXPORT void JNICALL +Java_java_io_RandomAccessFile_open0(JNIEnv *env, + jobject this, jstring path, jint mode) +{ + int flags = 0; + if (mode & java_io_RandomAccessFile_O_RDONLY) { + flags = O_RDONLY; + if (mode & java_io_RandomAccessFile_O_DIRECT) + flags |= O_DIRECT; + } + else if (mode & java_io_RandomAccessFile_O_RDWR) { + flags = O_RDWR | O_CREAT; + if (mode & java_io_RandomAccessFile_O_SYNC) + flags |= O_SYNC; + else if (mode & java_io_RandomAccessFile_O_DSYNC) + flags |= O_DSYNC; + else if (mode & java_io_RandomAccessFile_O_DIRECT) + flags |= O_DIRECT; + } + fileOpen(env, this, path, raf_fd, flags); +} + +JNIEXPORT jlong JNICALL +Java_java_io_RandomAccessFile_getCurrentLocation0(JNIEnv *env, jobject this) { + + FD fd; + + fd = GET_FD(this, raf_fd); + if (fd == -1) { + JNU_ThrowIOException(env, "Stream Closed"); + return -1; + } + jlong currentLocation = IO_Lseek(fd, 0, SEEK_CUR); + if (currentLocation == -1) { + JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); + } + return currentLocation; +} + +JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_getPageSize0(JNIEnv *env, jobject this) { + return getpagesize(); +} + +JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_readBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len) { + return readBytesD(env, this, bytes, off, len, raf_fd, raf_pgsz); +} + +JNIEXPORT void JNICALL +Java_java_io_RandomAccessFile_writeBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len) { + writeBytesD(env, this, bytes, off, len, JNI_FALSE, raf_fd, raf_pgsz); +} --- old/src/java.base/windows/native/libjava/FileInputStream_md.c 2016-08-25 17:51:54.902564707 -0700 +++ new/src/java.base/windows/native/libjava/FileInputStream_md.c 2016-08-25 17:51:54.799564706 -0700 @@ -39,6 +39,27 @@ */ JNIEXPORT void JNICALL +Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path, jboolean direct) { + if (direct) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + } + fileOpen(env, this, path, fis_fd, O_RDONLY); +} + +JNIEXPORT void JNICALL Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) { handleClose(env, this, fis_fd); } + +JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_readBytesD(JNIEnv *env, jobject this, + jbyteArray bytes, jint off, jint len) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + return 0; +} + +JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_getPageSize0(JNIEnv *env, jobject this) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + return 0; +} --- old/src/java.base/windows/native/libjava/FileOutputStream_md.c 2016-08-25 17:51:55.247564710 -0700 +++ new/src/java.base/windows/native/libjava/FileOutputStream_md.c 2016-08-25 17:51:55.142564709 -0700 @@ -55,7 +55,10 @@ JNIEXPORT void JNICALL Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this, - jstring path, jboolean append) { + jstring path, jboolean append, jboolean direct) { + if (direct) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + } fileOpen(env, this, path, fos_fd, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC)); } @@ -73,6 +76,18 @@ } JNIEXPORT void JNICALL +Java_java_io_FileOutputStream_writeBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len, jboolean append) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); +} + +JNIEXPORT jint JNICALL +Java_java_io_FileOutputStream_getPageSize0(JNIEnv *env, jobject this) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + return 0; +} + +JNIEXPORT void JNICALL Java_java_io_FileOutputStream_close0(JNIEnv *env, jobject this) { handleClose(env, this, fos_fd); } --- old/src/java.base/windows/native/libjava/RandomAccessFile_md.c 2016-08-25 17:51:55.485564712 -0700 +++ new/src/java.base/windows/native/libjava/RandomAccessFile_md.c 2016-08-25 17:51:55.382564711 -0700 @@ -39,6 +39,48 @@ */ JNIEXPORT void JNICALL +Java_java_io_RandomAccessFile_open0(JNIEnv *env, + jobject this, jstring path, jint mode) +{ + int flags = 0; + if (mode & java_io_RandomAccessFile_O_DIRECT) + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + + if (mode & java_io_RandomAccessFile_O_RDONLY) { + flags = O_RDONLY; + } + else if (mode & java_io_RandomAccessFile_O_RDWR) { + flags = O_RDWR | O_CREAT; + if (mode & java_io_RandomAccessFile_O_SYNC) + flags |= O_SYNC; + else if (mode & java_io_RandomAccessFile_O_DSYNC) + flags |= O_DSYNC; + } + else if (mode & java_io_RandomAccessFile_O_TEMPORARY) + flags |= O_TEMPORARY; + fileOpen(env, this, path, raf_fd, flags); +} + +JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_close0(JNIEnv *env, jobject this) { handleClose(env, this, raf_fd); } + +JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_getPageSize0(JNIEnv *env, jobject this) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + return 0; +} + +JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_readBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); + return 0; +} + +JNIEXPORT void JNICALL +Java_java_io_RandomAccessFile_writeBytesD(JNIEnv *env, + jobject this, jbyteArray bytes, jint off, jint len) { + JNU_ThrowIOException (env, "DirectIO is not available on Windows platform!"); +}