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 }