1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 2000, 2010, 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
27package java.nio;
28
29import java.io.FileDescriptor;
30
31import 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"><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
67public 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    //
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
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
92    MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
93        super(mark, pos, lim, cap);
94        this.fd = null;
95    }
96
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.
105    private long mappingOffset() {
106        int ps = Bits.pageSize();
107        long offset = address % ps;
108        return (offset >= 0) ? offset : (ps + offset);
109    }
110
111    private long mappingAddress(long mappingOffset) {
112        return address - mappingOffset;
113    }
114
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     */
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     */
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     */
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
212    private native boolean isLoaded0(long address, long length, int pageCount);
213
214    private native void load0(long address, long length);
215
216    private native void force0(FileDescriptor fd, long address, long length);
217}
218