8293331: Refactor FileDispatcherImpl into operating system-specific components

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2022-09-22 15:59:05 +00:00
parent f751e6087d
commit 48cc15602b
14 changed files with 959 additions and 704 deletions

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
public class FileDispatcherImpl extends UnixFileDispatcherImpl {
FileDispatcherImpl() {
super();
}
int force(FileDescriptor fd, boolean metaData) throws IOException {
return force0(fd, metaData);
}
protected long transferTo(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append)
{
return transferTo0(src, position, count, dst, append);
}
// --- native methods ---
static native int force0(FileDescriptor fd, boolean metaData)
throws IOException;
private static native long transferTo0(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append);
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include "jni.h"
#include "jni_util.h"
#include "jlong.h"
#include "nio.h"
#include "nio_util.h"
#include "java_lang_Integer.h"
#include <assert.h>
static jlong
handle(JNIEnv *env, jlong rv, char *msg)
{
if (rv >= 0)
return rv;
if (errno == EINTR)
return IOS_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, msg);
return IOS_THROWN;
}
// AIX
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
jobject fdo, jboolean md)
{
jint fd = fdval(env, fdo);
int result = 0;
if (md == JNI_FALSE) {
result = fdatasync(fd);
} else {
/* Calling fsync on a file descriptor that is opened only for
* reading results in an error ("EBADF: The FileDescriptor parameter is
* not a valid file descriptor open for writing.").
* However, at this point it is not possibly anymore to read the
* 'writable' attribute of the corresponding file channel so we have to
* use 'fcntl'.
*/
int getfl = fcntl(fd, F_GETFL);
if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) {
return 0;
}
result = fsync(fd);
}
return handle(env, result, "Force failed");
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this,
jobject srcFDO,
jlong position, jlong count,
jobject dstFDO, jboolean append)
{
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
jlong max = (jlong)java_lang_Integer_MAX_VALUE;
struct sf_parms sf_iobuf;
jlong result;
if (position > max)
return IOS_UNSUPPORTED_CASE;
if (count > max)
count = max;
memset(&sf_iobuf, 0, sizeof(sf_iobuf));
sf_iobuf.file_descriptor = srcFD;
sf_iobuf.file_offset = (off_t)position;
sf_iobuf.file_bytes = count;
result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE);
/* AIX send_file() will return 0 when this operation complete successfully,
* return 1 when partial bytes transferred and return -1 when an error has
* occurred.
*/
if (result == -1) {
if (errno == EWOULDBLOCK)
return IOS_UNAVAILABLE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR)
return IOS_INTERRUPTED;
if (errno == ENOTSOCK)
return IOS_UNSUPPORTED;
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
if (sf_iobuf.bytes_sent > 0)
return (jlong)sf_iobuf.bytes_sent;
return IOS_UNSUPPORTED_CASE;
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
class FileDispatcherImpl extends UnixFileDispatcherImpl {
FileDispatcherImpl() {
super();
}
int maxDirectTransferSize() {
return 0x7ffff000; // 2,147,479,552 maximum for sendfile()
}
long transferTo(FileDescriptor src, long position, long count,
FileDescriptor dst, boolean append) {
return transferTo0(src, position, count, dst, append);
}
long transferFrom(FileDescriptor src, FileDescriptor dst,
long position, long count, boolean append) {
return transferFrom0(src, dst, position, count, append);
}
// -- Native methods --
static native long transferTo0(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append);
static native long transferFrom0(FileDescriptor src, FileDescriptor dst,
long position, long count, boolean append);
static native void init0();
static {
init0();
}
}

View file

@ -0,0 +1,130 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include <sys/sendfile.h>
#include <dlfcn.h>
#include "jni.h"
#include "nio.h"
#include "nio_util.h"
#include "sun_nio_ch_FileDispatcherImpl.h"
typedef ssize_t copy_file_range_func(int, loff_t*, int, loff_t*, size_t,
unsigned int);
static copy_file_range_func* my_copy_file_range_func = NULL;
JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_init0(JNIEnv *env, jclass klass)
{
my_copy_file_range_func =
(copy_file_range_func*) dlsym(RTLD_DEFAULT, "copy_file_range");
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_transferFrom0(JNIEnv *env, jobject this,
jobject srcFDO, jobject dstFDO,
jlong position, jlong count,
jboolean append)
{
if (my_copy_file_range_func == NULL)
return IOS_UNSUPPORTED;
// copy_file_range fails with EBADF when appending
if (append == JNI_TRUE)
return IOS_UNSUPPORTED_CASE;
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
off64_t offset = (off64_t)position;
size_t len = (size_t)count;
jlong n = my_copy_file_range_func(srcFD, NULL, dstFD, &offset, len, 0);
if (n < 0) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if (errno == ENOSYS)
return IOS_UNSUPPORTED_CASE;
if ((errno == EBADF || errno == EINVAL || errno == EXDEV) &&
((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR) {
return IOS_INTERRUPTED;
}
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return n;
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this,
jobject srcFDO,
jlong position, jlong count,
jobject dstFDO, jboolean append)
{
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
// copy_file_range fails with EBADF when appending, and sendfile
// fails with EINVAL
if (append == JNI_TRUE)
return IOS_UNSUPPORTED_CASE;
off64_t offset = (off64_t)position;
jlong n;
if (my_copy_file_range_func != NULL) {
size_t len = (size_t)count;
n = my_copy_file_range_func(srcFD, &offset, dstFD, NULL, len, 0);
if (n < 0) {
switch (errno) {
case EINTR:
return IOS_INTERRUPTED;
case EINVAL:
case ENOSYS:
case EXDEV:
// ignore and try sendfile()
break;
default:
JNU_ThrowIOExceptionWithLastError(env, "Copy failed");
return IOS_THROWN;
}
}
if (n >= 0)
return n;
}
n = sendfile64(dstFD, srcFD, &offset, (size_t)count);
if (n < 0) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR) {
return IOS_INTERRUPTED;
}
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return n;
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
class FileDispatcherImpl extends UnixFileDispatcherImpl {
FileDispatcherImpl() {
super();
}
int force(FileDescriptor fd, boolean metaData) throws IOException {
return force0(fd, metaData);
}
boolean canTransferToFromOverlappedMap() {
return false;
}
long transferTo(FileDescriptor src, long position, long count,
FileDescriptor dst, boolean append) {
return transferTo0(src, position, count, dst, append);
}
// -- Native methods --
static native int force0(FileDescriptor fd, boolean metaData)
throws IOException;
static native long transferTo0(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append);
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include <sys/mount.h>
#include "jni.h"
#include "nio.h"
#include "nio_util.h"
#include "sun_nio_ch_FileDispatcherImpl.h"
static jlong
handle(JNIEnv *env, jlong rv, char *msg)
{
if (rv >= 0)
return rv;
if (errno == EINTR)
return IOS_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, msg);
return IOS_THROWN;
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
jobject fdo, jboolean md)
{
jint fd = fdval(env, fdo);
int result = 0;
result = fcntl(fd, F_FULLFSYNC);
if (result == -1) {
struct statfs fbuf;
int errno_fcntl = errno;
if (fstatfs(fd, &fbuf) == 0) {
if ((fbuf.f_flags & MNT_LOCAL) == 0) {
/* Try fsync() in case file is not local. */
result = fsync(fd);
}
} else {
/* fstatfs() failed so restore errno from fcntl(). */
errno = errno_fcntl;
}
}
return handle(env, result, "Force failed");
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this,
jobject srcFDO,
jlong position, jlong count,
jobject dstFDO, jboolean append)
{
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
off_t numBytes;
int result;
numBytes = count;
result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0);
if (numBytes > 0)
return numBytes;
if (result == -1) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN)
return IOS_UNSUPPORTED_CASE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR)
return IOS_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return result;
}

View file

@ -64,18 +64,12 @@ import jdk.internal.access.foreign.UnmapperProxy;
public class FileChannelImpl public class FileChannelImpl
extends FileChannel extends FileChannel
{ {
// Memory allocation size for mapping buffers
private static final long allocationGranularity;
// Access to FileDescriptor internals // Access to FileDescriptor internals
private static final JavaIOFileDescriptorAccess fdAccess = private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess(); SharedSecrets.getJavaIOFileDescriptorAccess();
// Maximum direct transfer size
private static final int MAX_DIRECT_TRANSFER_SIZE;
// Used to make native read and write calls // Used to make native read and write calls
private final FileDispatcher nd; private static final FileDispatcher nd = new FileDispatcherImpl();
// File descriptor // File descriptor
private final FileDescriptor fd; private final FileDescriptor fd;
@ -130,12 +124,11 @@ public class FileChannelImpl
boolean writable, boolean direct, Object parent) boolean writable, boolean direct, Object parent)
{ {
this.fd = fd; this.fd = fd;
this.path = path;
this.readable = readable; this.readable = readable;
this.writable = writable; this.writable = writable;
this.parent = parent;
this.path = path;
this.direct = direct; this.direct = direct;
this.nd = new FileDispatcherImpl(); this.parent = parent;
if (direct) { if (direct) {
assert path != null; assert path != null;
this.alignment = nd.setDirectIO(fd, path); this.alignment = nd.setDirectIO(fd, path);
@ -151,8 +144,9 @@ public class FileChannelImpl
CleanerFactory.cleaner().register(this, new Closer(fd)); CleanerFactory.cleaner().register(this, new Closer(fd));
} }
// Used by FileInputStream.getChannel(), FileOutputStream.getChannel
// and RandomAccessFile.getChannel() // Used by FileInputStream::getChannel, FileOutputStream::getChannel,
// and RandomAccessFile::getChannel
public static FileChannel open(FileDescriptor fd, String path, public static FileChannel open(FileDescriptor fd, String path,
boolean readable, boolean writable, boolean readable, boolean writable,
boolean direct, Object parent) boolean direct, Object parent)
@ -574,7 +568,7 @@ public class FileChannelImpl
do { do {
long comp = Blocker.begin(); long comp = Blocker.begin();
try { try {
n = transferTo0(fd, position, icount, targetFD, append); n = nd.transferTo(fd, position, icount, targetFD, append);
} finally { } finally {
Blocker.end(comp); Blocker.end(comp);
} }
@ -779,7 +773,7 @@ public class FileChannelImpl
if (sz > 0) { if (sz > 0) {
// Attempt a direct transfer, if the kernel supports it, limiting // Attempt a direct transfer, if the kernel supports it, limiting
// the number of bytes according to which platform // the number of bytes according to which platform
int icount = (int)Math.min(count, MAX_DIRECT_TRANSFER_SIZE); int icount = (int)Math.min(count, nd.maxDirectTransferSize());
long n; long n;
if ((n = transferToDirectly(position, icount, target)) >= 0) if ((n = transferToDirectly(position, icount, target)) >= 0)
return n; return n;
@ -813,7 +807,7 @@ public class FileChannelImpl
long comp = Blocker.begin(); long comp = Blocker.begin();
try { try {
boolean append = fdAccess.getAppend(fd); boolean append = fdAccess.getAppend(fd);
n = transferFrom0(srcFD, fd, position, count, append); n = nd.transferFrom(srcFD, fd, position, count, append);
} finally { } finally {
Blocker.end(comp); Blocker.end(comp);
} }
@ -1052,9 +1046,6 @@ public class FileChannelImpl
private abstract static class Unmapper private abstract static class Unmapper
implements Runnable, UnmapperProxy implements Runnable, UnmapperProxy
{ {
// may be required to close file
private static final NativeDispatcher nd = new FileDispatcherImpl();
private volatile long address; private volatile long address;
protected final long size; protected final long size;
protected final long cap; protected final long cap;
@ -1094,7 +1085,7 @@ public class FileChannelImpl
public void unmap() { public void unmap() {
if (address == 0) if (address == 0)
return; return;
unmap0(address, size); nd.unmap(address, size);
address = 0; address = 0;
// if this mapping has a valid file descriptor then we close it // if this mapping has a valid file descriptor then we close it
@ -1313,12 +1304,12 @@ public class FileChannelImpl
return null; return null;
} }
pagePosition = (int)(position % allocationGranularity); pagePosition = (int)(position % nd.allocationGranularity());
long mapPosition = position - pagePosition; long mapPosition = position - pagePosition;
mapSize = size + pagePosition; mapSize = size + pagePosition;
try { try {
// If map0 did not throw an exception, the address is valid // If map did not throw an exception, the address is valid
addr = map0(fd, prot, mapPosition, mapSize, isSync); addr = nd.map(fd, prot, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError x) { } catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted // An OutOfMemoryError may indicate that we've exhausted
// memory so force gc and re-attempt map // memory so force gc and re-attempt map
@ -1329,7 +1320,7 @@ public class FileChannelImpl
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
try { try {
addr = map0(fd, prot, mapPosition, mapSize, isSync); addr = nd.map(fd, prot, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError y) { } catch (OutOfMemoryError y) {
// After a second OOME, fail // After a second OOME, fail
throw new IOException("Map failed", y); throw new IOException("Map failed", y);
@ -1343,15 +1334,15 @@ public class FileChannelImpl
try { try {
mfd = nd.duplicateForMapping(fd); mfd = nd.duplicateForMapping(fd);
} catch (IOException ioe) { } catch (IOException ioe) {
unmap0(addr, mapSize); nd.unmap(addr, mapSize);
throw ioe; throw ioe;
} }
assert (IOStatus.checkAll(addr)); assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0); assert (addr % nd.allocationGranularity() == 0);
Unmapper um = (isSync Unmapper um = (isSync
? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition) ? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition)
: new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition)); : new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition));
return um; return um;
} finally { } finally {
threads.remove(ti); threads.remove(ti);
@ -1575,37 +1566,4 @@ public class FileChannelImpl
assert fileLockTable != null; assert fileLockTable != null;
fileLockTable.remove(fli); fileLockTable.remove(fli);
} }
// -- Native methods --
// Creates a new mapping
private native long map0(FileDescriptor fd, int prot, long position,
long length, boolean isSync)
throws IOException;
// Removes an existing mapping
private static native int unmap0(long address, long length);
// Transfers from src to dst, or returns IOStatus.UNSUPPORTED (-4) or
// IOStatus.UNSUPPORTED_CASE (-6) if the kernel does not support it
private static native long transferTo0(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append);
private static native long transferFrom0(FileDescriptor src,
FileDescriptor dst,
long position, long count,
boolean append);
// Retrieves the maximum size of a transfer
private static native int maxDirectTransferSize0();
// Retrieves allocation granularity
private static native long allocationGranularity0();
static {
IOUtil.load();
allocationGranularity = allocationGranularity0();
MAX_DIRECT_TRANSFER_SIZE = maxDirectTransferSize0();
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -69,5 +69,21 @@ abstract class FileDispatcher extends NativeDispatcher {
abstract boolean canTransferToFromOverlappedMap(); abstract boolean canTransferToFromOverlappedMap();
abstract long allocationGranularity();
abstract long map(FileDescriptor fd, int prot, long position, long length,
boolean isSync)
throws IOException;
abstract int unmap(long address, long length);
abstract int maxDirectTransferSize();
abstract long transferTo(FileDescriptor src, long position, long count,
FileDescriptor dst, boolean append);
abstract long transferFrom(FileDescriptor src, FileDescriptor dst,
long position, long count, boolean append);
abstract int setDirectIO(FileDescriptor fd, String path); abstract int setDirectIO(FileDescriptor fd, String path);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,11 @@ import java.io.IOException;
import jdk.internal.access.JavaIOFileDescriptorAccess; import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
class FileDispatcherImpl extends FileDispatcher { class UnixFileDispatcherImpl extends FileDispatcher {
private static final int MAP_INVALID = -1;
private static final int MAP_RO = 0;
private static final int MAP_RW = 1;
private static final int MAP_PV = 2;
static { static {
IOUtil.load(); IOUtil.load();
@ -41,7 +45,7 @@ class FileDispatcherImpl extends FileDispatcher {
private static final JavaIOFileDescriptorAccess fdAccess = private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess(); SharedSecrets.getJavaIOFileDescriptorAccess();
FileDispatcherImpl() { UnixFileDispatcherImpl() {
} }
int read(FileDescriptor fd, long address, int len) throws IOException { int read(FileDescriptor fd, long address, int len) throws IOException {
@ -127,7 +131,36 @@ class FileDispatcherImpl extends FileDispatcher {
} }
boolean canTransferToFromOverlappedMap() { boolean canTransferToFromOverlappedMap() {
return canTransferToFromOverlappedMap0(); return true;
}
long allocationGranularity() {
return allocationGranularity0();
}
long map(FileDescriptor fd, int prot, long position, long length,
boolean isSync)
throws IOException
{
return map0(fd, prot, position, length, isSync);
}
int unmap(long address, long length) {
return unmap0(address, length);
}
int maxDirectTransferSize() {
return Integer.MAX_VALUE;
}
long transferTo(FileDescriptor src, long position, long count,
FileDescriptor dst, boolean append) {
return IOStatus.UNSUPPORTED;
}
long transferFrom(FileDescriptor src, FileDescriptor dst,
long position, long count, boolean append) {
return IOStatus.UNSUPPORTED;
} }
int setDirectIO(FileDescriptor fd, String path) { int setDirectIO(FileDescriptor fd, String path) {
@ -188,10 +221,15 @@ class FileDispatcherImpl extends FileDispatcher {
static native void closeIntFD(int fd) throws IOException; static native void closeIntFD(int fd) throws IOException;
static native boolean canTransferToFromOverlappedMap0(); static native long allocationGranularity0();
static native long map0(FileDescriptor fd, int prot, long position,
long length, boolean isSync)
throws IOException;
static native int unmap0(long address, long length);
static native int setDirect0(FileDescriptor fd) throws IOException; static native int setDirect0(FileDescriptor fd) throws IOException;
static native void init(); static native void init();
} }

View file

@ -1,336 +0,0 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#if defined(__linux__)
#include <sys/sendfile.h>
#include <dlfcn.h>
#elif defined(_AIX)
#include <string.h>
#include <sys/socket.h>
#elif defined(_ALLBSD_SOURCE)
#include <sys/socket.h>
#include <sys/uio.h>
#define lseek64 lseek
#define mmap64 mmap
#endif
#include "jni.h"
#include "jni_util.h"
#include "jlong.h"
#include "nio.h"
#include "nio_util.h"
#include "sun_nio_ch_FileChannelImpl.h"
#include "java_lang_Integer.h"
#include <assert.h>
#if defined(__linux__)
typedef ssize_t copy_file_range_func(int, loff_t*, int, loff_t*, size_t,
unsigned int);
static copy_file_range_func* my_copy_file_range_func = NULL;
#endif
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_allocationGranularity0(JNIEnv *env, jclass clazz)
{
jlong pageSize = sysconf(_SC_PAGESIZE);
#if defined(__linux__)
my_copy_file_range_func =
(copy_file_range_func*) dlsym(RTLD_DEFAULT, "copy_file_range");
#endif
return pageSize;
}
static jlong
handle(JNIEnv *env, jlong rv, char *msg)
{
if (rv >= 0)
return rv;
if (errno == EINTR)
return IOS_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, msg);
return IOS_THROWN;
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, jobject fdo,
jint prot, jlong off, jlong len, jboolean map_sync)
{
void *mapAddress = 0;
jint fd = fdval(env, fdo);
int protections = 0;
int flags = 0;
// should never be called with map_sync and prot == PRIVATE
assert((prot != sun_nio_ch_FileChannelImpl_MAP_PV) || !map_sync);
if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) {
protections = PROT_READ;
flags = MAP_SHARED;
} else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) {
protections = PROT_WRITE | PROT_READ;
flags = MAP_SHARED;
} else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) {
protections = PROT_WRITE | PROT_READ;
flags = MAP_PRIVATE;
}
// if MAP_SYNC and MAP_SHARED_VALIDATE are not defined then it is
// best to define them here. This ensures the code compiles on old
// OS releases which do not provide the relevant headers. If run
// on the same machine then it will work if the kernel contains
// the necessary support otherwise mmap should fail with an
// invalid argument error
#ifndef MAP_SYNC
#define MAP_SYNC 0x80000
#endif
#ifndef MAP_SHARED_VALIDATE
#define MAP_SHARED_VALIDATE 0x03
#endif
if (map_sync) {
// ensure
// 1) this is Linux on AArch64, x86_64, or PPC64 LE
// 2) the mmap APIs are available at compile time
#if !defined(LINUX) || ! (defined(aarch64) || (defined(amd64) && defined(_LP64)) || defined(ppc64le))
// TODO - implement for solaris/AIX/BSD/WINDOWS and for 32 bit
JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");
return IOS_THROWN;
#else
flags |= MAP_SYNC | MAP_SHARED_VALIDATE;
#endif
}
mapAddress = mmap64(
0, /* Let OS decide location */
len, /* Number of bytes to map */
protections, /* File permissions */
flags, /* Changes are shared */
fd, /* File descriptor of mapped file */
off); /* Offset into file */
if (mapAddress == MAP_FAILED) {
if (map_sync && errno == ENOTSUP) {
JNU_ThrowIOExceptionWithLastError(env, "map with mode MAP_SYNC unsupported");
return IOS_THROWN;
}
if (errno == ENOMEM) {
JNU_ThrowOutOfMemoryError(env, "Map failed");
return IOS_THROWN;
}
return handle(env, -1, "Map failed");
}
return ((jlong) (unsigned long) mapAddress);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this,
jlong address, jlong len)
{
void *a = (void *)jlong_to_ptr(address);
return handle(env,
munmap(a, (size_t)len),
"Unmap failed");
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
jobject srcFDO,
jlong position, jlong count,
jobject dstFDO, jboolean append)
{
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
#if defined(__linux__)
// copy_file_range fails with EBADF when appending, and sendfile
// fails with EINVAL
if (append == JNI_TRUE)
return IOS_UNSUPPORTED_CASE;
off64_t offset = (off64_t)position;
jlong n;
if (my_copy_file_range_func != NULL) {
size_t len = (size_t)count;
n = my_copy_file_range_func(srcFD, &offset, dstFD, NULL, len, 0);
if (n < 0) {
switch (errno) {
case EINTR:
return IOS_INTERRUPTED;
case EINVAL:
case ENOSYS:
case EXDEV:
// ignore and try sendfile()
break;
default:
JNU_ThrowIOExceptionWithLastError(env, "Copy failed");
return IOS_THROWN;
}
}
if (n >= 0)
return n;
}
n = sendfile64(dstFD, srcFD, &offset, (size_t)count);
if (n < 0) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR) {
return IOS_INTERRUPTED;
}
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return n;
#elif defined(__APPLE__)
off_t numBytes;
int result;
numBytes = count;
result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0);
if (numBytes > 0)
return numBytes;
if (result == -1) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN)
return IOS_UNSUPPORTED_CASE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR)
return IOS_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return result;
#elif defined(_AIX)
jlong max = (jlong)java_lang_Integer_MAX_VALUE;
struct sf_parms sf_iobuf;
jlong result;
if (position > max)
return IOS_UNSUPPORTED_CASE;
if (count > max)
count = max;
memset(&sf_iobuf, 0, sizeof(sf_iobuf));
sf_iobuf.file_descriptor = srcFD;
sf_iobuf.file_offset = (off_t)position;
sf_iobuf.file_bytes = count;
result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE);
/* AIX send_file() will return 0 when this operation complete successfully,
* return 1 when partial bytes transferred and return -1 when an error has
* occurred.
*/
if (result == -1) {
if (errno == EWOULDBLOCK)
return IOS_UNAVAILABLE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR)
return IOS_INTERRUPTED;
if (errno == ENOTSOCK)
return IOS_UNSUPPORTED;
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
if (sf_iobuf.bytes_sent > 0)
return (jlong)sf_iobuf.bytes_sent;
return IOS_UNSUPPORTED_CASE;
#else
return IOS_UNSUPPORTED;
#endif
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferFrom0(JNIEnv *env, jobject this,
jobject srcFDO, jobject dstFDO,
jlong position, jlong count,
jboolean append)
{
#if defined(__linux__)
if (my_copy_file_range_func == NULL)
return IOS_UNSUPPORTED;
// copy_file_range fails with EBADF when appending
if (append == JNI_TRUE)
return IOS_UNSUPPORTED_CASE;
jint srcFD = fdval(env, srcFDO);
jint dstFD = fdval(env, dstFDO);
off64_t offset = (off64_t)position;
size_t len = (size_t)count;
jlong n = my_copy_file_range_func(srcFD, NULL, dstFD, &offset, len, 0);
if (n < 0) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
if (errno == ENOSYS)
return IOS_UNSUPPORTED_CASE;
if ((errno == EBADF || errno == EINVAL || errno == EXDEV) &&
((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR) {
return IOS_INTERRUPTED;
}
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
return IOS_THROWN;
}
return n;
#else
return IOS_UNSUPPORTED;
#endif
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileChannelImpl_maxDirectTransferSize0(JNIEnv* env, jobject this)
{
#if defined(LINUX)
return 0x7ffff000; // 2,147,479,552 maximum for sendfile()
#else
return java_lang_Integer_MAX_VALUE;
#endif
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,23 +23,11 @@
* questions. * questions.
*/ */
#include <sys/types.h> #include <sys/mman.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h>
#ifdef MACOSX
#include <sys/mount.h>
#include <sys/param.h>
#endif
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#if defined(__linux__)
#include <linux/fs.h>
#include <sys/ioctl.h>
#endif
#if defined(_ALLBSD_SOURCE) #if defined(_ALLBSD_SOURCE)
#define lseek64 lseek #define lseek64 lseek
#define stat64 stat #define stat64 stat
@ -52,23 +40,23 @@
#define ftruncate64 ftruncate #define ftruncate64 ftruncate
#define fstat64 fstat #define fstat64 fstat
#define fdatasync fsync #define fdatasync fsync
#define mmap64 mmap
#define statvfs64 statvfs
#define fstatvfs64 fstatvfs
#endif #endif
#include "jni.h" #include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "nio.h" #include "nio.h"
#include "nio_util.h" #include "nio_util.h"
#include "sun_nio_ch_FileDispatcherImpl.h" #include "sun_nio_ch_UnixFileDispatcherImpl.h"
#include "java_lang_Long.h" #include "java_lang_Long.h"
#include <assert.h>
static int preCloseFD = -1; /* File descriptor to which we dup other fd's static int preCloseFD = -1; /* File descriptor to which we dup other fd's
before closing them for real */ before closing them for real */
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) Java_sun_nio_ch_UnixFileDispatcherImpl_init(JNIEnv *env, jclass cl)
{ {
int sp[2]; int sp[2];
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
@ -80,7 +68,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_read0(JNIEnv *env, jclass clazz,
jobject fdo, jlong address, jint len) jobject fdo, jlong address, jint len)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -90,7 +78,7 @@ Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz,
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo, Java_sun_nio_ch_UnixFileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
jlong address, jint len, jlong offset) jlong address, jint len, jlong offset)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -100,7 +88,7 @@ Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_readv0(JNIEnv *env, jclass clazz,
jobject fdo, jlong address, jint len) jobject fdo, jlong address, jint len)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -109,7 +97,7 @@ Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz,
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_write0(JNIEnv *env, jclass clazz,
jobject fdo, jlong address, jint len) jobject fdo, jlong address, jint len)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -119,7 +107,7 @@ Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz,
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo, Java_sun_nio_ch_UnixFileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
jlong address, jint len, jlong offset) jlong address, jint len, jlong offset)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -129,7 +117,7 @@ Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fd
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_writev0(JNIEnv *env, jclass clazz,
jobject fdo, jlong address, jint len) jobject fdo, jlong address, jint len)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -149,7 +137,7 @@ handle(JNIEnv *env, jlong rv, char *msg)
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_seek0(JNIEnv *env, jclass clazz,
jobject fdo, jlong offset) jobject fdo, jlong offset)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -163,52 +151,23 @@ Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz,
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, Java_sun_nio_ch_UnixFileDispatcherImpl_force0(JNIEnv *env, jobject this,
jobject fdo, jboolean md) jobject fdo, jboolean md)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
int result = 0; int result = 0;
#ifdef MACOSX
result = fcntl(fd, F_FULLFSYNC);
if (result == -1) {
struct statfs fbuf;
int errno_fcntl = errno;
if (fstatfs(fd, &fbuf) == 0) {
if ((fbuf.f_flags & MNT_LOCAL) == 0) {
/* Try fsync() in case file is not local. */
result = fsync(fd);
}
} else {
/* fstatfs() failed so restore errno from fcntl(). */
errno = errno_fcntl;
}
}
#else /* end MACOSX, begin not-MACOSX */
if (md == JNI_FALSE) { if (md == JNI_FALSE) {
result = fdatasync(fd); result = fdatasync(fd);
} else { } else {
#ifdef _AIX
/* On AIX, calling fsync on a file descriptor that is opened only for
* reading results in an error ("EBADF: The FileDescriptor parameter is
* not a valid file descriptor open for writing.").
* However, at this point it is not possibly anymore to read the
* 'writable' attribute of the corresponding file channel so we have to
* use 'fcntl'.
*/
int getfl = fcntl(fd, F_GETFL);
if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) {
return 0;
}
#endif /* _AIX */
result = fsync(fd); result = fsync(fd);
} }
#endif /* not-MACOSX */
return handle(env, result, "Force failed"); return handle(env, result, "Force failed");
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, Java_sun_nio_ch_UnixFileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
jobject fdo, jlong size) jobject fdo, jlong size)
{ {
return handle(env, return handle(env,
@ -217,7 +176,7 @@ Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) Java_sun_nio_ch_UnixFileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
struct stat64 fbuf; struct stat64 fbuf;
@ -238,7 +197,7 @@ Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo, Java_sun_nio_ch_UnixFileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
jboolean block, jlong pos, jlong size, jboolean block, jlong pos, jlong size,
jboolean shared) jboolean shared)
{ {
@ -267,16 +226,16 @@ Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
lockResult = fcntl(fd, cmd, &fl); lockResult = fcntl(fd, cmd, &fl);
if (lockResult < 0) { if (lockResult < 0) {
if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES))
return sun_nio_ch_FileDispatcherImpl_NO_LOCK; return sun_nio_ch_UnixFileDispatcherImpl_NO_LOCK;
if (errno == EINTR) if (errno == EINTR)
return sun_nio_ch_FileDispatcherImpl_INTERRUPTED; return sun_nio_ch_UnixFileDispatcherImpl_INTERRUPTED;
JNU_ThrowIOExceptionWithLastError(env, "Lock failed"); JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
} }
return 0; return 0;
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, Java_sun_nio_ch_UnixFileDispatcherImpl_release0(JNIEnv *env, jobject this,
jobject fdo, jlong pos, jlong size) jobject fdo, jlong pos, jlong size)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
@ -308,14 +267,14 @@ static void closeFileDescriptor(JNIEnv *env, int fd) {
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) Java_sun_nio_ch_UnixFileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
closeFileDescriptor(env, fd); closeFileDescriptor(env, fd);
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) Java_sun_nio_ch_UnixFileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
if (preCloseFD >= 0) { if (preCloseFD >= 0) {
@ -325,7 +284,7 @@ Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_dup0(JNIEnv *env, jobject this, jobject fdo1, jobject fdo2) Java_sun_nio_ch_UnixFileDispatcherImpl_dup0(JNIEnv *env, jobject this, jobject fdo1, jobject fdo2)
{ {
if (dup2(fdval(env, fdo1), fdval(env, fdo2)) < 0) { if (dup2(fdval(env, fdo1), fdval(env, fdo2)) < 0) {
JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
@ -333,32 +292,110 @@ Java_sun_nio_ch_FileDispatcherImpl_dup0(JNIEnv *env, jobject this, jobject fdo1,
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd) Java_sun_nio_ch_UnixFileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd)
{ {
closeFileDescriptor(env, fd); closeFileDescriptor(env, fd);
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_canTransferToFromOverlappedMap0(JNIEnv *env, jclass clazz) Java_sun_nio_ch_UnixFileDispatcherImpl_allocationGranularity0(JNIEnv *env, jclass klass)
{ {
#ifdef MACOSX jlong pageSize = sysconf(_SC_PAGESIZE);
return JNI_FALSE; return pageSize;
#else }
return JNI_TRUE;
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_UnixFileDispatcherImpl_map0(JNIEnv *env, jclass klass, jobject fdo,
jint prot, jlong off, jlong len,
jboolean map_sync)
{
void *mapAddress = 0;
jint fd = fdval(env, fdo);
int protections = 0;
int flags = 0;
// should never be called with map_sync and prot == PRIVATE
assert((prot != sun_nio_ch_UnixFileDispatcherImpl_MAP_PV) || !map_sync);
if (prot == sun_nio_ch_UnixFileDispatcherImpl_MAP_RO) {
protections = PROT_READ;
flags = MAP_SHARED;
} else if (prot == sun_nio_ch_UnixFileDispatcherImpl_MAP_RW) {
protections = PROT_WRITE | PROT_READ;
flags = MAP_SHARED;
} else if (prot == sun_nio_ch_UnixFileDispatcherImpl_MAP_PV) {
protections = PROT_WRITE | PROT_READ;
flags = MAP_PRIVATE;
}
// if MAP_SYNC and MAP_SHARED_VALIDATE are not defined then it is
// best to define them here. This ensures the code compiles on old
// OS releases which do not provide the relevant headers. If run
// on the same machine then it will work if the kernel contains
// the necessary support otherwise mmap should fail with an
// invalid argument error
#ifndef MAP_SYNC
#define MAP_SYNC 0x80000
#endif #endif
#ifndef MAP_SHARED_VALIDATE
#define MAP_SHARED_VALIDATE 0x03
#endif
if (map_sync) {
// ensure
// 1) this is Linux on AArch64, x86_64, or PPC64 LE
// 2) the mmap APIs are available at compile time
#if !defined(LINUX) || ! (defined(aarch64) || (defined(amd64) && defined(_LP64)) || defined(ppc64le))
// TODO - implement for solaris/AIX/BSD/WINDOWS and for 32 bit
JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");
return IOS_THROWN;
#else
flags |= MAP_SYNC | MAP_SHARED_VALIDATE;
#endif
}
mapAddress = mmap64(
0, /* Let OS decide location */
len, /* Number of bytes to map */
protections, /* File permissions */
flags, /* Changes are shared */
fd, /* File descriptor of mapped file */
off); /* Offset into file */
if (mapAddress == MAP_FAILED) {
if (map_sync && errno == ENOTSUP) {
JNU_ThrowIOExceptionWithLastError(env, "map with mode MAP_SYNC unsupported");
return IOS_THROWN;
}
if (errno == ENOMEM) {
JNU_ThrowOutOfMemoryError(env, "Map failed");
return IOS_THROWN;
}
return handle(env, -1, "Map failed");
}
return ((jlong) (unsigned long) mapAddress);
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz, Java_sun_nio_ch_UnixFileDispatcherImpl_unmap0(JNIEnv *env, jclass klass,
jobject fdo) jlong address, jlong len)
{
void *a = (void *)jlong_to_ptr(address);
return handle(env,
munmap(a, (size_t)len),
"Unmap failed");
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_UnixFileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz,
jobject fdo)
{ {
jint fd = fdval(env, fdo); jint fd = fdval(env, fdo);
jint result; jint result;
#ifdef MACOSX
struct statvfs file_stat;
#else
struct statvfs64 file_stat; struct statvfs64 file_stat;
#endif
#if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON) #if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON)
#ifdef O_DIRECT #ifdef O_DIRECT
@ -386,11 +423,7 @@ Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz,
return result; return result;
} }
#endif #endif
#ifdef MACOSX
result = fstatvfs(fd, &file_stat);
#else
result = fstatvfs64(fd, &file_stat); result = fstatvfs64(fd, &file_stat);
#endif
if(result == -1) { if(result == -1) {
JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed"); JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
return result; return result;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,22 +25,29 @@
package sun.nio.ch; package sun.nio.ch;
import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import sun.security.action.GetPropertyAction;
import java.io.File;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.access.SharedSecrets;
import sun.security.action.GetPropertyAction;
class FileDispatcherImpl extends FileDispatcher { class FileDispatcherImpl extends FileDispatcher {
private static final int MAP_INVALID = -1;
private static final int MAP_RO = 0;
private static final int MAP_RW = 1;
private static final int MAP_PV = 2;
private static final long ALLOCATION_GRANULARITY;
private static final int MAX_DIRECT_TRANSFER_SIZE;
// set to true if fast file transmission (TransmitFile) is enabled
private static final boolean FAST_FILE_TRANSFER;
private static final JavaIOFileDescriptorAccess fdAccess = private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess(); SharedSecrets.getJavaIOFileDescriptorAccess();
// set to true if fast file transmission (TransmitFile) is enabled
private static final boolean fastFileTransfer;
FileDispatcherImpl() { } FileDispatcherImpl() { }
@Override @Override
@ -118,7 +125,7 @@ class FileDispatcherImpl extends FileDispatcher {
} }
boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) { boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) {
return fastFileTransfer && sc.isBlocking(); return FAST_FILE_TRANSFER && sc.isBlocking();
} }
boolean transferToDirectlyNeedsPositionLock() { boolean transferToDirectlyNeedsPositionLock() {
@ -129,6 +136,36 @@ class FileDispatcherImpl extends FileDispatcher {
return true; return true;
} }
long allocationGranularity() {
return ALLOCATION_GRANULARITY;
}
long map(FileDescriptor fd, int prot, long position, long length,
boolean isSync)
throws IOException
{
return map0(fd, prot, position, length, isSync);
}
int unmap(long address, long length) {
return unmap0(address, length);
}
int maxDirectTransferSize() {
return MAX_DIRECT_TRANSFER_SIZE;
}
long transferTo(FileDescriptor src, long position, long count,
FileDescriptor dst, boolean append) {
return transferTo0(src, position, count, dst, append);
}
long transferFrom(FileDescriptor src, FileDescriptor dst,
long position, long count, boolean append) {
return IOStatus.UNSUPPORTED;
}
int setDirectIO(FileDescriptor fd, String path) { int setDirectIO(FileDescriptor fd, String path) {
int result = -1; int result = -1;
String filePath = path.substring(0, path.lastIndexOf(File.separator)); String filePath = path.substring(0, path.lastIndexOf(File.separator));
@ -151,7 +188,9 @@ class FileDispatcherImpl extends FileDispatcher {
static { static {
IOUtil.load(); IOUtil.load();
fastFileTransfer = isFastFileTransferRequested(); FAST_FILE_TRANSFER = isFastFileTransferRequested();
ALLOCATION_GRANULARITY = allocationGranularity0();
MAX_DIRECT_TRANSFER_SIZE = maxDirectTransferSize0();
} }
//-- Native methods //-- Native methods
@ -194,5 +233,19 @@ class FileDispatcherImpl extends FileDispatcher {
static native long duplicateHandle(long fd) throws IOException; static native long duplicateHandle(long fd) throws IOException;
static native long allocationGranularity0();
static native long map0(FileDescriptor fd, int prot, long position,
long length, boolean isSync)
throws IOException;
static native int unmap0(long address, long length);
static native int maxDirectTransferSize0();
static native long transferTo0(FileDescriptor src, long position,
long count, FileDescriptor dst,
boolean append);
static native int setDirect0(FileDescriptor fd, CharBuffer buffer) throws IOException; static native int setDirect0(FileDescriptor fd, CharBuffer buffer) throws IOException;
} }

View file

@ -1,204 +0,0 @@
/*
* Copyright (c) 2000, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include <io.h>
#include "nio.h"
#include "nio_util.h"
#include "sun_nio_ch_FileChannelImpl.h"
#include "java_lang_Integer.h"
#include <Mswsock.h>
#pragma comment(lib, "Mswsock.lib")
/**************************************************************
* static method to retrieve the allocation granularity
*/
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_allocationGranularity0(JNIEnv *env, jclass clazz)
{
SYSTEM_INFO si;
jint align;
GetSystemInfo(&si);
align = si.dwAllocationGranularity;
return align;
}
/**************************************************************
* Channel
*/
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_map0(JNIEnv *env, jobject this, jobject fdo,
jint prot, jlong off, jlong len, jboolean map_sync)
{
void *mapAddress = 0;
jint lowOffset = (jint)off;
jint highOffset = (jint)(off >> 32);
jlong maxSize = off + len;
jint lowLen = (jint)(maxSize);
jint highLen = (jint)(maxSize >> 32);
HANDLE fileHandle = (HANDLE)(handleval(env, fdo));
HANDLE mapping;
DWORD mapAccess = FILE_MAP_READ;
DWORD fileProtect = PAGE_READONLY;
DWORD mapError;
BOOL result;
if (prot == sun_nio_ch_FileChannelImpl_MAP_RO) {
fileProtect = PAGE_READONLY;
mapAccess = FILE_MAP_READ;
} else if (prot == sun_nio_ch_FileChannelImpl_MAP_RW) {
fileProtect = PAGE_READWRITE;
mapAccess = FILE_MAP_WRITE;
} else if (prot == sun_nio_ch_FileChannelImpl_MAP_PV) {
fileProtect = PAGE_WRITECOPY;
mapAccess = FILE_MAP_COPY;
}
if (map_sync) {
JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");
return IOS_THROWN;
}
mapping = CreateFileMapping(
fileHandle, /* Handle of file */
NULL, /* Not inheritable */
fileProtect, /* Read and write */
highLen, /* High word of max size */
lowLen, /* Low word of max size */
NULL); /* No name for object */
if (mapping == NULL) {
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
mapAddress = MapViewOfFile(
mapping, /* Handle of file mapping object */
mapAccess, /* Read and write access */
highOffset, /* High word of offset */
lowOffset, /* Low word of offset */
(SIZE_T)len); /* Number of bytes to map */
mapError = GetLastError();
result = CloseHandle(mapping);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
if (mapAddress == NULL) {
if (mapError == ERROR_NOT_ENOUGH_MEMORY)
JNU_ThrowOutOfMemoryError(env, "Map failed");
else
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
return ptr_to_jlong(mapAddress);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this,
jlong address, jlong len)
{
BOOL result;
void *a = (void *) jlong_to_ptr(address);
result = UnmapViewOfFile(a);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Unmap failed");
return IOS_THROWN;
}
return 0;
}
// Integer.MAX_VALUE - 1 is the maximum transfer size for TransmitFile()
#define MAX_TRANSMIT_SIZE (java_lang_Integer_MAX_VALUE - 1)
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
jobject srcFD,
jlong position, jlong count,
jobject dstFD, jboolean append)
{
const int PACKET_SIZE = 524288;
LARGE_INTEGER where;
HANDLE src = (HANDLE)(handleval(env, srcFD));
SOCKET dst = (SOCKET)(fdval(env, dstFD));
DWORD chunkSize = (count > MAX_TRANSMIT_SIZE) ?
MAX_TRANSMIT_SIZE : (DWORD)count;
BOOL result;
where.QuadPart = position;
result = SetFilePointerEx(src, where, &where, FILE_BEGIN);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed");
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;
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferFrom0(JNIEnv *env, jobject this,
jobject srcFDO, jobject dstFDO,
jlong position, jlong count,
jboolean append)
{
return IOS_UNSUPPORTED;
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileChannelImpl_maxDirectTransferSize0(JNIEnv* env, jobject this)
{
return MAX_TRANSMIT_SIZE;
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,12 +28,14 @@
#include "jni_util.h" #include "jni_util.h"
#include "jvm.h" #include "jvm.h"
#include "jlong.h" #include "jlong.h"
#include "sun_nio_ch_FileDispatcherImpl.h"
#include <io.h> #include <io.h>
#include "nio.h" #include "nio.h"
#include "nio_util.h" #include "nio_util.h"
#include "jlong.h" #include "java_lang_Integer.h"
#include "sun_nio_ch_FileDispatcherImpl.h"
#include <Mswsock.h>
#pragma comment(lib, "Mswsock.lib")
/************************************************************** /**************************************************************
* FileDispatcherImpl.c * FileDispatcherImpl.c
@ -482,6 +484,165 @@ Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlo
return ptr_to_jlong(hResult); return ptr_to_jlong(hResult);
} }
/**************************************************************
* static method to retrieve the allocation granularity
*/
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_allocationGranularity0(JNIEnv *env, jclass klass)
{
SYSTEM_INFO si;
jint align;
GetSystemInfo(&si);
align = si.dwAllocationGranularity;
return align;
}
/**************************************************************
* Channel
*/
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_map0(JNIEnv *env, jclass klass, jobject fdo,
jint prot, jlong off, jlong len,
jboolean map_sync)
{
void *mapAddress = 0;
jint lowOffset = (jint)off;
jint highOffset = (jint)(off >> 32);
jlong maxSize = off + len;
jint lowLen = (jint)(maxSize);
jint highLen = (jint)(maxSize >> 32);
HANDLE fileHandle = (HANDLE)(handleval(env, fdo));
HANDLE mapping;
DWORD mapAccess = FILE_MAP_READ;
DWORD fileProtect = PAGE_READONLY;
DWORD mapError;
BOOL result;
if (prot == sun_nio_ch_FileDispatcherImpl_MAP_RO) {
fileProtect = PAGE_READONLY;
mapAccess = FILE_MAP_READ;
} else if (prot == sun_nio_ch_FileDispatcherImpl_MAP_RW) {
fileProtect = PAGE_READWRITE;
mapAccess = FILE_MAP_WRITE;
} else if (prot == sun_nio_ch_FileDispatcherImpl_MAP_PV) {
fileProtect = PAGE_WRITECOPY;
mapAccess = FILE_MAP_COPY;
}
if (map_sync) {
JNU_ThrowInternalError(env, "should never call map on platform where MAP_SYNC is unimplemented");
return IOS_THROWN;
}
mapping = CreateFileMapping(
fileHandle, /* Handle of file */
NULL, /* Not inheritable */
fileProtect, /* Read and write */
highLen, /* High word of max size */
lowLen, /* Low word of max size */
NULL); /* No name for object */
if (mapping == NULL) {
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
mapAddress = MapViewOfFile(
mapping, /* Handle of file mapping object */
mapAccess, /* Read and write access */
highOffset, /* High word of offset */
lowOffset, /* Low word of offset */
(SIZE_T)len); /* Number of bytes to map */
mapError = GetLastError();
result = CloseHandle(mapping);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
if (mapAddress == NULL) {
if (mapError == ERROR_NOT_ENOUGH_MEMORY)
JNU_ThrowOutOfMemoryError(env, "Map failed");
else
JNU_ThrowIOExceptionWithLastError(env, "Map failed");
return IOS_THROWN;
}
return ptr_to_jlong(mapAddress);
}
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_unmap0(JNIEnv *env, jclass klass,
jlong address, jlong len)
{
BOOL result;
void *a = (void *) jlong_to_ptr(address);
result = UnmapViewOfFile(a);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Unmap failed");
return IOS_THROWN;
}
return 0;
}
// Integer.MAX_VALUE - 1 is the maximum transfer size for TransmitFile()
#define MAX_TRANSMIT_SIZE (java_lang_Integer_MAX_VALUE - 1)
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_maxDirectTransferSize0(JNIEnv* env, jclass klass)
{
return MAX_TRANSMIT_SIZE;
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jclass klass,
jobject srcFD,
jlong position, jlong count,
jobject dstFD, jboolean append)
{
const int PACKET_SIZE = 524288;
LARGE_INTEGER where;
HANDLE src = (HANDLE)(handleval(env, srcFD));
SOCKET dst = (SOCKET)(fdval(env, dstFD));
DWORD chunkSize = (count > MAX_TRANSMIT_SIZE) ?
MAX_TRANSMIT_SIZE : (DWORD)count;
BOOL result;
where.QuadPart = position;
result = SetFilePointerEx(src, where, &where, FILE_BEGIN);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed");
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;
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this, Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this,
jobject fdObj, jobject buffer) jobject fdObj, jobject buffer)