diff -r 23e3ab980622 -r 9b7b9f16dfd9 src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java Tue Aug 20 10:46:23 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java Tue Aug 20 10:11:53 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -46,6 +46,8 @@ import jdk.internal.access.JavaIOFileDescriptorAccess; import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.ExtendedMapMode; +import jdk.internal.misc.Unsafe; import jdk.internal.ref.Cleaner; import jdk.internal.ref.CleanerFactory; @@ -860,20 +862,15 @@ // -- Memory-mapped buffers -- - private static class Unmapper + private static abstract class Unmapper implements Runnable { // may be required to close file private static final NativeDispatcher nd = new FileDispatcherImpl(); - // keep track of mapped buffer usage - static volatile int count; - static volatile long totalSize; - static volatile long totalCapacity; - private volatile long address; - private final long size; - private final int cap; + protected final long size; + protected final int cap; private final FileDescriptor fd; private Unmapper(long address, long size, int cap, @@ -884,12 +881,6 @@ this.size = size; this.cap = cap; this.fd = fd; - - synchronized (Unmapper.class) { - count++; - totalSize += size; - totalCapacity += cap; - } } public void run() { @@ -907,7 +898,63 @@ } } - synchronized (Unmapper.class) { + decrementStats(); + } + protected abstract void incrementStats(); + protected abstract void decrementStats(); + } + + private static class DefaultUnmapper extends Unmapper { + + // keep track of non-sync mapped buffer usage + static volatile int count; + static volatile long totalSize; + static volatile long totalCapacity; + + public DefaultUnmapper(long address, long size, int cap, + FileDescriptor fd) { + super(address, size, cap, fd); + incrementStats(); + } + + protected void incrementStats() { + synchronized (DefaultUnmapper.class) { + count++; + totalSize += size; + totalCapacity += cap; + } + } + protected void decrementStats() { + synchronized (DefaultUnmapper.class) { + count--; + totalSize -= size; + totalCapacity -= cap; + } + } + } + + private static class SyncUnmapper extends Unmapper { + + // keep track of mapped buffer usage + static volatile int count; + static volatile long totalSize; + static volatile long totalCapacity; + + public SyncUnmapper(long address, long size, int cap, + FileDescriptor fd) { + super(address, size, cap, fd); + incrementStats(); + } + + protected void incrementStats() { + synchronized (SyncUnmapper.class) { + count++; + totalSize += size; + totalCapacity += cap; + } + } + protected void decrementStats() { + synchronized (SyncUnmapper.class) { count--; totalSize -= size; totalCapacity -= cap; @@ -941,18 +988,30 @@ 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 + 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) && !writable) + } + 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(); + } long addr = -1; int ti = -1; @@ -990,9 +1049,9 @@ // a valid file descriptor is not required FileDescriptor dummy = new FileDescriptor(); if ((!writable) || (imode == MAP_RO)) - return Util.newMappedByteBufferR(0, 0, dummy, null); + return Util.newMappedByteBufferR(0, 0, dummy, null, isSync); else - return Util.newMappedByteBuffer(0, 0, dummy, null); + return Util.newMappedByteBuffer(0, 0, dummy, null, isSync); } pagePosition = (int)(position % allocationGranularity); @@ -1000,7 +1059,7 @@ mapSize = size + pagePosition; try { // If map0 did not throw an exception, the address is valid - addr = map0(imode, mapPosition, mapSize); + addr = map0(imode, mapPosition, mapSize, isSync); } catch (OutOfMemoryError x) { // An OutOfMemoryError may indicate that we've exhausted // memory so force gc and re-attempt map @@ -1011,7 +1070,7 @@ Thread.currentThread().interrupt(); } try { - addr = map0(imode, mapPosition, mapSize); + addr = map0(imode, mapPosition, mapSize, isSync); } catch (OutOfMemoryError y) { // After a second OOME, fail throw new IOException("Map failed", y); @@ -1032,17 +1091,21 @@ assert (IOStatus.checkAll(addr)); assert (addr % allocationGranularity == 0); int isize = (int)size; - Unmapper um = new Unmapper(addr, mapSize, isize, mfd); + 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); + um, + isSync); } else { return Util.newMappedByteBuffer(isize, addr + pagePosition, mfd, - um); + um, + isSync); } } finally { threads.remove(ti); @@ -1062,15 +1125,40 @@ } @Override public long getCount() { - return Unmapper.count; + return DefaultUnmapper.count; } @Override public long getTotalCapacity() { - return Unmapper.totalCapacity; + return DefaultUnmapper.totalCapacity; } @Override public long getMemoryUsed() { - return Unmapper.totalSize; + return DefaultUnmapper.totalSize; + } + }; + } + + /** + * Invoked by sun.management.ManagementFactoryHelper to create the management + * interface for sync mapped buffers. + */ + public static JavaNioAccess.BufferPool getSyncMappedBufferPool() { + return new JavaNioAccess.BufferPool() { + @Override + public String getName() { + return "mapped - 'non-volatile memory'"; + } + @Override + public long getCount() { + return SyncUnmapper.count; + } + @Override + public long getTotalCapacity() { + return SyncUnmapper.totalCapacity; + } + @Override + public long getMemoryUsed() { + return SyncUnmapper.totalSize; } }; } @@ -1196,7 +1284,7 @@ // -- Native methods -- // Creates a new mapping - private native long map0(int prot, long position, long length) + private native long map0(int prot, long position, long length, boolean isSync) throws IOException; // Removes an existing mapping