1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.nio; 28 29 import java.io.FileDescriptor; 30 import sun.misc.Unsafe; 31 32 33 /** 34 * A direct byte buffer whose content is a memory-mapped region of a file. 35 * 36 * <p> Mapped byte buffers are created via the {@link 37 * java.nio.channels.FileChannel#map FileChannel.map} method. This class 38 * extends the {@link ByteBuffer} class with operations that are specific to 39 * memory-mapped file regions. 40 * 41 * <p> A mapped byte buffer and the file mapping that it represents remain 42 * valid until the buffer itself is garbage-collected. 43 * 44 * <p> The content of a mapped byte buffer can change at any time, for example 45 * if the content of the corresponding region of the mapped file is changed by 46 * this program or another. Whether or not such changes occur, and when they 47 * occur, is operating-system dependent and therefore unspecified. 48 * 49 * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become 50 * inaccessible at any time, for example if the mapped file is truncated. An 51 * attempt to access an inaccessible region of a mapped byte buffer will not 52 * change the buffer's content and will cause an unspecified exception to be 53 * thrown either at the time of the access or at some later time. It is 54 * therefore strongly recommended that appropriate precautions be taken to 55 * avoid the manipulation of a mapped file by this program, or by a 56 * concurrently running program, except to read or write the file's content. 57 * 58 * <p> Mapped byte buffers otherwise behave no differently than ordinary direct 59 * byte buffers. </p> 60 * 61 * 62 * @author Mark Reinhold 63 * @author JSR-51 Expert Group 64 * @since 1.4 65 */ 66 67 public abstract class MappedByteBuffer 68 extends ByteBuffer 69 { 70 71 // This is a little bit backwards: By rights MappedByteBuffer should be a 72 // subclass of DirectByteBuffer, but to keep the spec clear and simple, and 73 // for optimization purposes, it's easier to do it the other way around. 74 // This works because DirectByteBuffer is a package-private class. 75 76 // For mapped buffers, a FileDescriptor that may be used for mapping 77 // operations if valid; null if the buffer is not mapped. 78 private final FileDescriptor fd; 79 80 // This should only be invoked by the DirectByteBuffer constructors 81 // MappedByteBuffer(int mark, int pos, int lim, int cap, FileDescriptor fd)82 MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private 83 FileDescriptor fd) 84 { 85 super(mark, pos, lim, cap); 86 this.fd = fd; 87 } 88 89 // Android-added: Additional constructor for use by Android's DirectByteBuffer. MappedByteBuffer(int mark, int pos, int lim, int cap, byte[] buf, int offset)90 MappedByteBuffer(int mark, int pos, int lim, int cap, byte[] buf, int offset) { 91 super(mark, pos, lim, cap, buf, offset); 92 this.fd = null; 93 } 94 MappedByteBuffer(int mark, int pos, int lim, int cap)95 MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private 96 super(mark, pos, lim, cap); 97 this.fd = null; 98 } 99 checkMapped()100 private void checkMapped() { 101 if (fd == null) 102 // Can only happen if a luser explicitly casts a direct byte buffer 103 throw new UnsupportedOperationException(); 104 } 105 106 // Returns the distance (in bytes) of the buffer from the page aligned address 107 // of the mapping. Computed each time to avoid storing in every direct buffer. mappingOffset()108 private long mappingOffset() { 109 int ps = Bits.pageSize(); 110 long offset = address % ps; 111 return (offset >= 0) ? offset : (ps + offset); 112 } 113 mappingAddress(long mappingOffset)114 private long mappingAddress(long mappingOffset) { 115 return address - mappingOffset; 116 } 117 mappingLength(long mappingOffset)118 private long mappingLength(long mappingOffset) { 119 return (long)capacity() + mappingOffset; 120 } 121 122 /** 123 * Tells whether or not this buffer's content is resident in physical 124 * memory. 125 * 126 * <p> A return value of <tt>true</tt> implies that it is highly likely 127 * that all of the data in this buffer is resident in physical memory and 128 * may therefore be accessed without incurring any virtual-memory page 129 * faults or I/O operations. A return value of <tt>false</tt> does not 130 * necessarily imply that the buffer's content is not resident in physical 131 * memory. 132 * 133 * <p> The returned value is a hint, rather than a guarantee, because the 134 * underlying operating system may have paged out some of the buffer's data 135 * by the time that an invocation of this method returns. </p> 136 * 137 * @return <tt>true</tt> if it is likely that this buffer's content 138 * is resident in physical memory 139 */ isLoaded()140 public final boolean isLoaded() { 141 checkMapped(); 142 if ((address == 0) || (capacity() == 0)) 143 return true; 144 long offset = mappingOffset(); 145 long length = mappingLength(offset); 146 return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length)); 147 } 148 149 // not used, but a potential target for a store, see load() for details. 150 private static byte unused; 151 152 /** 153 * Loads this buffer's content into physical memory. 154 * 155 * <p> This method makes a best effort to ensure that, when it returns, 156 * this buffer's content is resident in physical memory. Invoking this 157 * method may cause some number of page faults and I/O operations to 158 * occur. </p> 159 * 160 * @return This buffer 161 */ load()162 public final MappedByteBuffer load() { 163 checkMapped(); 164 if ((address == 0) || (capacity() == 0)) 165 return this; 166 long offset = mappingOffset(); 167 long length = mappingLength(offset); 168 load0(mappingAddress(offset), length); 169 170 // Read a byte from each page to bring it into memory. A checksum 171 // is computed as we go along to prevent the compiler from otherwise 172 // considering the loop as dead code. 173 Unsafe unsafe = Unsafe.getUnsafe(); 174 int ps = Bits.pageSize(); 175 int count = Bits.pageCount(length); 176 long a = mappingAddress(offset); 177 byte x = 0; 178 for (int i=0; i<count; i++) { 179 x ^= unsafe.getByte(a); 180 a += ps; 181 } 182 if (unused != 0) 183 unused = x; 184 185 return this; 186 } 187 188 /** 189 * Forces any changes made to this buffer's content to be written to the 190 * storage device containing the mapped file. 191 * 192 * <p> If the file mapped into this buffer resides on a local storage 193 * device then when this method returns it is guaranteed that all changes 194 * made to the buffer since it was created, or since this method was last 195 * invoked, will have been written to that device. 196 * 197 * <p> If the file does not reside on a local device then no such guarantee 198 * is made. 199 * 200 * <p> If this buffer was not mapped in read/write mode ({@link 201 * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this 202 * method has no effect. </p> 203 * 204 * @return This buffer 205 */ force()206 public final MappedByteBuffer force() { 207 checkMapped(); 208 if ((address != 0) && (capacity() != 0)) { 209 long offset = mappingOffset(); 210 force0(fd, mappingAddress(offset), mappingLength(offset)); 211 } 212 return this; 213 } 214 isLoaded0(long address, long length, int pageCount)215 private native boolean isLoaded0(long address, long length, int pageCount); load0(long address, long length)216 private native void load0(long address, long length); force0(FileDescriptor fd, long address, long length)217 private native void force0(FileDescriptor fd, long address, long length); 218 } 219