src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
changeset 57804 9b7b9f16dfd9
parent 54532 e9c62d960d64
--- 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