1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.foreign;
  27 
  28 import jdk.incubator.foreign.MappedMemorySegment;
  29 import jdk.internal.access.JavaNioAccess;
  30 import jdk.internal.access.SharedSecrets;
  31 import jdk.internal.access.foreign.UnmapperProxy;
  32 import sun.nio.ch.FileChannelImpl;
  33 
  34 import java.io.IOException;
  35 import java.nio.ByteBuffer;
  36 import java.nio.channels.FileChannel;
  37 import java.nio.file.OpenOption;
  38 import java.nio.file.Path;
  39 import java.nio.file.StandardOpenOption;
  40 
  41 /**
  42  * Implementation for a mapped memory segments. A mapped memory segment is a native memory segment, which
  43  * additionally features an {@link UnmapperProxy} object. This object provides detailed information about the
  44  * memory mapped segment, such as the file descriptor associated with the mapping. This information is crucial
  45  * in order to correctly reconstruct a byte buffer object from the segment (see {@link #makeByteBuffer()}).
  46  */
  47 public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl implements MappedMemorySegment {
  48 
  49     private final UnmapperProxy unmapper;
  50 
  51     MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, int mask, Thread owner, MemoryScope scope) {
  52         super(min, length, mask, owner, scope);
  53         this.unmapper = unmapper;
  54     }
  55 
  56     @Override
  57     ByteBuffer makeByteBuffer() {
  58         JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
  59         return nioAccess.newMappedByteBuffer(unmapper, min, (int)length, null, this);
  60     }
  61 
  62     @Override
  63     MappedMemorySegmentImpl dup(long offset, long size, int mask, Thread owner, MemoryScope scope) {
  64         return new MappedMemorySegmentImpl(min + offset, unmapper, size, mask, owner, scope);
  65     }
  66 
  67     // mapped segment methods
  68 
  69 
  70     @Override
  71     public MappedMemorySegmentImpl asSlice(long offset, long newSize) {
  72         return (MappedMemorySegmentImpl)super.asSlice(offset, newSize);
  73     }
  74 
  75     @Override
  76     public MappedMemorySegmentImpl withAccessModes(int accessModes) {
  77         return (MappedMemorySegmentImpl)super.withAccessModes(accessModes);
  78     }
  79 
  80     @Override
  81     public void load() {
  82         nioAccess.load(min, unmapper.isSync(), length);
  83     }
  84 
  85     @Override
  86     public void unload() {
  87         nioAccess.unload(min, unmapper.isSync(), length);
  88     }
  89 
  90     @Override
  91     public boolean isLoaded() {
  92         return nioAccess.isLoaded(min, unmapper.isSync(), length);
  93     }
  94 
  95     @Override
  96     public void force() {
  97         nioAccess.force(unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length);
  98     }
  99 
 100     // factories
 101 
 102     public static MappedMemorySegment makeMappedSegment(Path path, long bytesSize, FileChannel.MapMode mapMode) throws IOException {
 103         if (bytesSize <= 0) throw new IllegalArgumentException("Requested bytes size must be > 0.");
 104         try (FileChannelImpl channelImpl = (FileChannelImpl)FileChannel.open(path, openOptions(mapMode))) {
 105             UnmapperProxy unmapperProxy = channelImpl.mapInternal(mapMode, 0L, bytesSize);
 106             MemoryScope scope = new MemoryScope(null, unmapperProxy::unmap);
 107             int modes = defaultAccessModes(bytesSize);
 108             if (mapMode == FileChannel.MapMode.READ_ONLY) {
 109                 modes &= ~WRITE;
 110             }
 111             return new MappedMemorySegmentImpl(unmapperProxy.address(), unmapperProxy, bytesSize,
 112                     modes, Thread.currentThread(), scope);
 113         }
 114     }
 115 
 116     private static OpenOption[] openOptions(FileChannel.MapMode mapMode) {
 117         if (mapMode == FileChannel.MapMode.READ_ONLY) {
 118             return new OpenOption[] { StandardOpenOption.READ };
 119         } else if (mapMode == FileChannel.MapMode.READ_WRITE || mapMode == FileChannel.MapMode.PRIVATE) {
 120             return new OpenOption[] { StandardOpenOption.READ, StandardOpenOption.WRITE };
 121         } else {
 122             throw new UnsupportedOperationException("Unsupported map mode: " + mapMode);
 123         }
 124     }
 125 }