< prev index next >

src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java

Print this page

        

@@ -40,19 +40,22 @@
 import java.nio.channels.NonReadableChannelException;
 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;
 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;
 
+import jdk.internal.access.foreign.UnmapperProxy;
+
 public class FileChannelImpl
     extends FileChannel
 {
     // Memory allocation size for mapping buffers
     private static final long allocationGranularity;

@@ -861,31 +864,43 @@
 
 
     // -- 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);
             address = 0;
 

@@ -909,13 +924,13 @@
         // 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);
+        public DefaultUnmapper(long address, long size, long cap,
+                               FileDescriptor fd, int pagePosition) {
+            super(address, size, cap, fd, pagePosition);
             incrementStats();
         }
 
         protected void incrementStats() {
             synchronized (DefaultUnmapper.class) {

@@ -938,13 +953,13 @@
         // 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);
+        public SyncUnmapper(long address, long size, long cap,
+                            FileDescriptor fd, int pagePosition) {
+            super(address, size, cap, fd, pagePosition);
             incrementStats();
         }
 
         protected void incrementStats() {
             synchronized (SyncUnmapper.class) {

@@ -966,15 +981,48 @@
         Cleaner cl = ((DirectBuffer)bb).cleaner();
         if (cl != null)
             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();
         if (mode == null)
             throw new NullPointerException("Mode is null");

@@ -982,39 +1030,12 @@
             throw new IllegalArgumentException("Negative position");
         if (size < 0L)
             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 {
             beginBlocking();
             ti = threads.add();

@@ -1043,36 +1064,30 @@
                     if (!isOpen())
                         return null;
                 }
 
                 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);
                 long mapPosition = position - pagePosition;
                 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
                     System.gc();
                     try {
                         Thread.sleep(100);
                     } catch (InterruptedException y) {
                         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);
                     }
                 }

@@ -1088,33 +1103,57 @@
                 throw ioe;
             }
 
             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.
      */
     public static JavaNioAccess.BufferPool getMappedBufferPool() {
< prev index next >