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