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 
31 import sun.misc.Unsafe;
32 
33 
34 /**
35  * A direct byte buffer whose content is a memory-mapped region of a file.
36  *
37  * <p> Mapped byte buffers are created via the {@link
38  * java.nio.channels.FileChannel#map FileChannel.map} method.  This class
39  * extends the {@link ByteBuffer} class with operations that are specific to
40  * memory-mapped file regions.
41  *
42  * <p> A mapped byte buffer and the file mapping that it represents remain
43  * valid until the buffer itself is garbage-collected.
44  *
45  * <p> The content of a mapped byte buffer can change at any time, for example
46  * if the content of the corresponding region of the mapped file is changed by
47  * this program or another.  Whether or not such changes occur, and when they
48  * occur, is operating-system dependent and therefore unspecified.
49  *
50  * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become
51  * inaccessible at any time, for example if the mapped file is truncated.  An
52  * attempt to access an inaccessible region of a mapped byte buffer will not
53  * change the buffer's content and will cause an unspecified exception to be
54  * thrown either at the time of the access or at some later time.  It is
55  * therefore strongly recommended that appropriate precautions be taken to
56  * avoid the manipulation of a mapped file by this program, or by a
57  * concurrently running program, except to read or write the file's content.
58  *
59  * <p> Mapped byte buffers otherwise behave no differently than ordinary direct
60  * byte buffers. </p>
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     // This is a little bit backwards: By rights MappedByteBuffer should be a
71     // subclass of DirectByteBuffer, but to keep the spec clear and simple, and
72     // for optimization purposes, it's easier to do it the other way around.
73     // This works because DirectByteBuffer is a package-private class.
74 
75     // For mapped buffers, a FileDescriptor that may be used for mapping
76     // operations if valid; null if the buffer is not mapped.
77     private final FileDescriptor fd;
78 
79     // This should only be invoked by the DirectByteBuffer constructors
80     //
MappedByteBuffer(int mark, int pos, int lim, int cap, FileDescriptor fd)81     MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
82                      FileDescriptor fd) {
83         super(mark, pos, lim, cap);
84         this.fd = fd;
85     }
86 
MappedByteBuffer(int mark, int pos, int lim, int cap, byte[] buf, int offset)87     MappedByteBuffer(int mark, int pos, int lim, int cap, byte[] buf, int offset) {
88         super(mark, pos, lim, cap, buf, offset);
89         this.fd = null;
90     }
91 
MappedByteBuffer(int mark, int pos, int lim, int cap)92     MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
93         super(mark, pos, lim, cap);
94         this.fd = null;
95     }
96 
checkMapped()97     private void checkMapped() {
98         if (fd == null)
99             // Can only happen if a luser explicitly casts a direct byte buffer
100             throw new UnsupportedOperationException();
101     }
102 
103     // Returns the distance (in bytes) of the buffer from the page aligned address
104     // of the mapping. Computed each time to avoid storing in every direct buffer.
mappingOffset()105     private long mappingOffset() {
106         int ps = Bits.pageSize();
107         long offset = address % ps;
108         return (offset >= 0) ? offset : (ps + offset);
109     }
110 
mappingAddress(long mappingOffset)111     private long mappingAddress(long mappingOffset) {
112         return address - mappingOffset;
113     }
114 
mappingLength(long mappingOffset)115     private long mappingLength(long mappingOffset) {
116         return (long) capacity() + mappingOffset;
117     }
118 
119     /**
120      * Tells whether or not this buffer's content is resident in physical
121      * memory.
122      *
123      * <p> A return value of <tt>true</tt> implies that it is highly likely
124      * that all of the data in this buffer is resident in physical memory and
125      * may therefore be accessed without incurring any virtual-memory page
126      * faults or I/O operations.  A return value of <tt>false</tt> does not
127      * necessarily imply that the buffer's content is not resident in physical
128      * memory.
129      *
130      * <p> The returned value is a hint, rather than a guarantee, because the
131      * underlying operating system may have paged out some of the buffer's data
132      * by the time that an invocation of this method returns.  </p>
133      *
134      * @return <tt>true</tt> if it is likely that this buffer's content
135      * is resident in physical memory
136      */
isLoaded()137     public final boolean isLoaded() {
138         checkMapped();
139         if ((address == 0) || (capacity() == 0))
140             return true;
141         long offset = mappingOffset();
142         long length = mappingLength(offset);
143         return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length));
144     }
145 
146     // not used, but a potential target for a store, see load() for details.
147     private static byte unused;
148 
149     /**
150      * Loads this buffer's content into physical memory.
151      *
152      * <p> This method makes a best effort to ensure that, when it returns,
153      * this buffer's content is resident in physical memory.  Invoking this
154      * method may cause some number of page faults and I/O operations to
155      * occur. </p>
156      *
157      * @return This buffer
158      */
load()159     public final MappedByteBuffer load() {
160         checkMapped();
161         if ((address == 0) || (capacity() == 0))
162             return this;
163         long offset = mappingOffset();
164         long length = mappingLength(offset);
165         load0(mappingAddress(offset), length);
166 
167         // Read a byte from each page to bring it into memory. A checksum
168         // is computed as we go along to prevent the compiler from otherwise
169         // considering the loop as dead code.
170         Unsafe unsafe = Unsafe.getUnsafe();
171         int ps = Bits.pageSize();
172         int count = Bits.pageCount(length);
173         long a = mappingAddress(offset);
174         byte x = 0;
175         for (int i = 0; i < count; i++) {
176             x ^= unsafe.getByte(a);
177             a += ps;
178         }
179         if (unused != 0)
180             unused = x;
181 
182         return this;
183     }
184 
185     /**
186      * Forces any changes made to this buffer's content to be written to the
187      * storage device containing the mapped file.
188      *
189      * <p> If the file mapped into this buffer resides on a local storage
190      * device then when this method returns it is guaranteed that all changes
191      * made to the buffer since it was created, or since this method was last
192      * invoked, will have been written to that device.
193      *
194      * <p> If the file does not reside on a local device then no such guarantee
195      * is made.
196      *
197      * <p> If this buffer was not mapped in read/write mode ({@link
198      * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this
199      * method has no effect. </p>
200      *
201      * @return This buffer
202      */
force()203     public final MappedByteBuffer force() {
204         checkMapped();
205         if ((address != 0) && (capacity() != 0)) {
206             long offset = mappingOffset();
207             force0(fd, mappingAddress(offset), mappingLength(offset));
208         }
209         return this;
210     }
211 
isLoaded0(long address, long length, int pageCount)212     private native boolean isLoaded0(long address, long length, int pageCount);
213 
load0(long address, long length)214     private native void load0(long address, long length);
215 
force0(FileDescriptor fd, long address, long length)216     private native void force0(FileDescriptor fd, long address, long length);
217 }
218