8234049: Implementation of Memory Access API (Incubator)

Co-authored-by: Vlaidmir Ivanov <vladimir.x.ivanov@oracle.com>
Reviewed-by: alanb, psandoz, chegar, rriggs, plevart, briangoetz, jrose, adinn, vlivanov
This commit is contained in:
Jorn Vernee 2019-12-12 22:59:57 +00:00 committed by Maurizio Cimadamore
parent 7cdecd8981
commit 8f4f088a12
59 changed files with 7849 additions and 147 deletions

View file

@ -42,6 +42,7 @@ import java.nio.channels.NonWritableChannelException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Objects;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.access.JavaNioAccess;
@ -51,6 +52,8 @@ import jdk.internal.misc.Unsafe;
import jdk.internal.ref.Cleaner;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.access.foreign.UnmapperProxy;
public class FileChannelImpl
extends FileChannel
{
@ -863,27 +866,39 @@ public class FileChannelImpl
// -- Memory-mapped buffers --
private static abstract class Unmapper
implements Runnable
implements Runnable, UnmapperProxy
{
// may be required to close file
private static final NativeDispatcher nd = new FileDispatcherImpl();
private volatile long address;
protected final long size;
protected final int cap;
protected final long cap;
private final FileDescriptor fd;
private final int pagePosition;
private Unmapper(long address, long size, int cap,
FileDescriptor fd)
private Unmapper(long address, long size, long cap,
FileDescriptor fd, int pagePosition)
{
assert (address != 0);
this.address = address;
this.size = size;
this.cap = cap;
this.fd = fd;
this.pagePosition = pagePosition;
}
@Override
public long address() {
return address;
}
@Override
public void run() {
unmap();
}
public void unmap() {
if (address == 0)
return;
unmap0(address, size);
@ -911,9 +926,9 @@ public class FileChannelImpl
static volatile long totalSize;
static volatile long totalCapacity;
public DefaultUnmapper(long address, long size, int cap,
FileDescriptor fd) {
super(address, size, cap, fd);
public DefaultUnmapper(long address, long size, long cap,
FileDescriptor fd, int pagePosition) {
super(address, size, cap, fd, pagePosition);
incrementStats();
}
@ -940,9 +955,9 @@ public class FileChannelImpl
static volatile long totalSize;
static volatile long totalCapacity;
public SyncUnmapper(long address, long size, int cap,
FileDescriptor fd) {
super(address, size, cap, fd);
public SyncUnmapper(long address, long size, long cap,
FileDescriptor fd, int pagePosition) {
super(address, size, cap, fd, pagePosition);
incrementStats();
}
@ -968,11 +983,44 @@ public class FileChannelImpl
cl.clean();
}
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;
public MappedByteBuffer map(MapMode mode, long position, long size)
public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
if (size > Integer.MAX_VALUE)
throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));
int prot = toProt(mode);
Unmapper unmapper = mapInternal(mode, position, size, prot, isSync);
if (unmapper == null) {
// a valid file descriptor is not required
FileDescriptor dummy = new FileDescriptor();
if ((!writable) || (prot == MAP_RO))
return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);
else
return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);
} else if ((!writable) || (prot == MAP_RO)) {
return Util.newMappedByteBufferR((int)unmapper.cap,
unmapper.address + unmapper.pagePosition,
unmapper.fd,
unmapper, isSync);
} else {
return Util.newMappedByteBuffer((int)unmapper.cap,
unmapper.address + unmapper.pagePosition,
unmapper.fd,
unmapper, isSync);
}
}
public Unmapper mapInternal(MapMode mode, long position, long size) throws IOException {
boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));
int prot = toProt(mode);
return mapInternal(mode, position, size, prot, isSync);
}
private Unmapper mapInternal(MapMode mode, long position, long size, int prot, boolean isSync)
throws IOException
{
ensureOpen();
@ -984,35 +1032,8 @@ public class FileChannelImpl
throw new IllegalArgumentException("Negative size");
if (position + size < 0)
throw new IllegalArgumentException("Position + size overflow");
if (size > Integer.MAX_VALUE)
throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
int imode;
boolean isSync = false;
if (mode == MapMode.READ_ONLY)
imode = MAP_RO;
else if (mode == MapMode.READ_WRITE)
imode = MAP_RW;
else if (mode == MapMode.PRIVATE)
imode = MAP_PV;
else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {
imode = MAP_RO;
isSync = true;
} else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {
imode = MAP_RW;
isSync = true;
} else {
throw new UnsupportedOperationException();
}
if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)
throw new NonWritableChannelException();
if (!readable)
throw new NonReadableChannelException();
// reject SYNC request if writeback is not enabled for this platform
if (isSync && !Unsafe.isWritebackEnabled()) {
throw new UnsupportedOperationException();
}
checkMode(mode, prot, isSync);
long addr = -1;
int ti = -1;
try {
@ -1045,13 +1066,7 @@ public class FileChannelImpl
}
if (size == 0) {
addr = 0;
// a valid file descriptor is not required
FileDescriptor dummy = new FileDescriptor();
if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);
else
return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);
return null;
}
pagePosition = (int)(position % allocationGranularity);
@ -1059,7 +1074,7 @@ public class FileChannelImpl
mapSize = size + pagePosition;
try {
// If map0 did not throw an exception, the address is valid
addr = map0(imode, mapPosition, mapSize, isSync);
addr = map0(prot, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted
// memory so force gc and re-attempt map
@ -1070,7 +1085,7 @@ public class FileChannelImpl
Thread.currentThread().interrupt();
}
try {
addr = map0(imode, mapPosition, mapSize, isSync);
addr = map0(prot, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
@ -1090,29 +1105,53 @@ public class FileChannelImpl
assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0);
int isize = (int)size;
Unmapper um = (isSync
? new SyncUnmapper(addr, mapSize, isize, mfd)
: new DefaultUnmapper(addr, mapSize, isize, mfd));
if ((!writable) || (imode == MAP_RO)) {
return Util.newMappedByteBufferR(isize,
addr + pagePosition,
mfd,
um,
isSync);
} else {
return Util.newMappedByteBuffer(isize,
addr + pagePosition,
mfd,
um,
isSync);
}
? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition)
: new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition));
return um;
} finally {
threads.remove(ti);
endBlocking(IOStatus.checkAll(addr));
}
}
private boolean isSync(MapMode mode) {
return mode == ExtendedMapMode.READ_ONLY_SYNC ||
mode == ExtendedMapMode.READ_WRITE_SYNC;
}
private int toProt(MapMode mode) {
int prot;
if (mode == MapMode.READ_ONLY) {
prot = MAP_RO;
} else if (mode == MapMode.READ_WRITE) {
prot = MAP_RW;
} else if (mode == MapMode.PRIVATE) {
prot = MAP_PV;
} else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {
prot = MAP_RO;
} else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {
prot = MAP_RW;
} else {
prot = MAP_INVALID;
}
return prot;
}
private void checkMode(MapMode mode, int prot, boolean isSync) {
if (prot == MAP_INVALID) {
throw new UnsupportedOperationException();
}
if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)
throw new NonWritableChannelException();
if (!readable)
throw new NonReadableChannelException();
// reject SYNC request if writeback is not enabled for this platform
if (isSync && !Unsafe.isWritebackEnabled()) {
throw new UnsupportedOperationException();
}
}
/**
* Invoked by sun.management.ManagementFactoryHelper to create the management
* interface for mapped buffers.

View file

@ -37,6 +37,7 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
@ -416,7 +417,7 @@ public class Util {
long.class,
FileDescriptor.class,
Runnable.class,
boolean.class });
boolean.class, MemorySegmentProxy.class});
ctor.setAccessible(true);
directByteBufferConstructor = ctor;
} catch (ClassNotFoundException |
@ -443,7 +444,7 @@ public class Util {
addr,
fd,
unmapper,
isSync});
isSync, null});
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {
@ -464,7 +465,7 @@ public class Util {
long.class,
FileDescriptor.class,
Runnable.class,
boolean.class });
boolean.class, MemorySegmentProxy.class });
ctor.setAccessible(true);
directByteBufferRConstructor = ctor;
} catch (ClassNotFoundException |
@ -491,7 +492,7 @@ public class Util {
addr,
fd,
unmapper,
isSync});
isSync, null});
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {