Path: blob/master/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
67771 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.io.FileDescriptor;28import java.io.IOException;29import java.io.UncheckedIOException;30import java.lang.ref.Cleaner.Cleanable;31import java.nio.ByteBuffer;32import java.nio.MappedByteBuffer;33import java.nio.channels.AsynchronousCloseException;34import java.nio.channels.ClosedByInterruptException;35import java.nio.channels.ClosedChannelException;36import java.nio.channels.FileChannel;37import java.nio.channels.FileLock;38import java.nio.channels.FileLockInterruptionException;39import java.nio.channels.NonReadableChannelException;40import java.nio.channels.NonWritableChannelException;41import java.nio.channels.ReadableByteChannel;42import java.nio.channels.SelectableChannel;43import java.nio.channels.WritableByteChannel;44import java.util.Objects;4546import jdk.internal.access.JavaIOFileDescriptorAccess;47import jdk.internal.access.SharedSecrets;48import jdk.internal.misc.ExtendedMapMode;49import jdk.internal.misc.Unsafe;50import jdk.internal.misc.VM;51import jdk.internal.misc.VM.BufferPool;52import jdk.internal.ref.Cleaner;53import jdk.internal.ref.CleanerFactory;5455import jdk.internal.access.foreign.UnmapperProxy;5657public class FileChannelImpl58extends FileChannel59{60// Memory allocation size for mapping buffers61private static final long allocationGranularity;6263// Access to FileDescriptor internals64private static final JavaIOFileDescriptorAccess fdAccess =65SharedSecrets.getJavaIOFileDescriptorAccess();6667// Maximum direct transfer size68private static final int MAX_DIRECT_TRANSFER_SIZE;6970// Used to make native read and write calls71private final FileDispatcher nd;7273// File descriptor74private final FileDescriptor fd;7576// File access mode (immutable)77private final boolean writable;78private final boolean readable;7980// Required to prevent finalization of creating stream (immutable)81private final Object parent;8283// The path of the referenced file84// (null if the parent stream is created with a file descriptor)85private final String path;8687// Thread-safe set of IDs of native threads, for signalling88private final NativeThreadSet threads = new NativeThreadSet(2);8990// Lock for operations involving position and size91private final Object positionLock = new Object();9293// blocking operations are not interruptible94private volatile boolean uninterruptible;9596// DirectIO flag97private final boolean direct;9899// IO alignment value for DirectIO100private final int alignment;101102// Cleanable with an action which closes this channel's file descriptor103private final Cleanable closer;104105private static class Closer implements Runnable {106private final FileDescriptor fd;107108Closer(FileDescriptor fd) {109this.fd = fd;110}111112public void run() {113try {114fdAccess.close(fd);115} catch (IOException ioe) {116// Rethrow as unchecked so the exception can be propagated as needed117throw new UncheckedIOException("close", ioe);118}119}120}121122private FileChannelImpl(FileDescriptor fd, String path, boolean readable,123boolean writable, boolean direct, Object parent)124{125this.fd = fd;126this.readable = readable;127this.writable = writable;128this.parent = parent;129this.path = path;130this.direct = direct;131this.nd = new FileDispatcherImpl();132if (direct) {133assert path != null;134this.alignment = nd.setDirectIO(fd, path);135} else {136this.alignment = -1;137}138139// Register a cleaning action if and only if there is no parent140// as the parent will take care of closing the file descriptor.141// FileChannel is used by the LambdaMetaFactory so a lambda cannot142// be used here hence we use a nested class instead.143this.closer = parent != null ? null :144CleanerFactory.cleaner().register(this, new Closer(fd));145}146147// Used by FileInputStream.getChannel(), FileOutputStream.getChannel148// and RandomAccessFile.getChannel()149public static FileChannel open(FileDescriptor fd, String path,150boolean readable, boolean writable,151boolean direct, Object parent)152{153return new FileChannelImpl(fd, path, readable, writable, direct, parent);154}155156private void ensureOpen() throws IOException {157if (!isOpen())158throw new ClosedChannelException();159}160161public void setUninterruptible() {162uninterruptible = true;163}164165private void beginBlocking() {166if (!uninterruptible) begin();167}168169private void endBlocking(boolean completed) throws AsynchronousCloseException {170if (!uninterruptible) end(completed);171}172173// -- Standard channel operations --174175protected void implCloseChannel() throws IOException {176if (!fd.valid())177return; // nothing to do178179// Release and invalidate any locks that we still hold180if (fileLockTable != null) {181for (FileLock fl: fileLockTable.removeAll()) {182synchronized (fl) {183if (fl.isValid()) {184nd.release(fd, fl.position(), fl.size());185((FileLockImpl)fl).invalidate();186}187}188}189}190191// signal any threads blocked on this channel192threads.signalAndWait();193194if (parent != null) {195196// Close the fd via the parent stream's close method. The parent197// will reinvoke our close method, which is defined in the198// superclass AbstractInterruptibleChannel, but the isOpen logic in199// that method will prevent this method from being reinvoked.200//201((java.io.Closeable)parent).close();202} else if (closer != null) {203// Perform the cleaning action so it is not redone when204// this channel becomes phantom reachable.205try {206closer.clean();207} catch (UncheckedIOException uioe) {208throw uioe.getCause();209}210} else {211fdAccess.close(fd);212}213214}215216public int read(ByteBuffer dst) throws IOException {217ensureOpen();218if (!readable)219throw new NonReadableChannelException();220synchronized (positionLock) {221if (direct)222Util.checkChannelPositionAligned(position(), alignment);223int n = 0;224int ti = -1;225try {226beginBlocking();227ti = threads.add();228if (!isOpen())229return 0;230do {231n = IOUtil.read(fd, dst, -1, direct, alignment, nd);232} while ((n == IOStatus.INTERRUPTED) && isOpen());233return IOStatus.normalize(n);234} finally {235threads.remove(ti);236endBlocking(n > 0);237assert IOStatus.check(n);238}239}240}241242public long read(ByteBuffer[] dsts, int offset, int length)243throws IOException244{245Objects.checkFromIndexSize(offset, length, dsts.length);246ensureOpen();247if (!readable)248throw new NonReadableChannelException();249synchronized (positionLock) {250if (direct)251Util.checkChannelPositionAligned(position(), alignment);252long n = 0;253int ti = -1;254try {255beginBlocking();256ti = threads.add();257if (!isOpen())258return 0;259do {260n = IOUtil.read(fd, dsts, offset, length,261direct, alignment, nd);262} while ((n == IOStatus.INTERRUPTED) && isOpen());263return IOStatus.normalize(n);264} finally {265threads.remove(ti);266endBlocking(n > 0);267assert IOStatus.check(n);268}269}270}271272public int write(ByteBuffer src) throws IOException {273ensureOpen();274if (!writable)275throw new NonWritableChannelException();276synchronized (positionLock) {277if (direct)278Util.checkChannelPositionAligned(position(), alignment);279int n = 0;280int ti = -1;281try {282beginBlocking();283ti = threads.add();284if (!isOpen())285return 0;286do {287n = IOUtil.write(fd, src, -1, direct, alignment, nd);288} while ((n == IOStatus.INTERRUPTED) && isOpen());289return IOStatus.normalize(n);290} finally {291threads.remove(ti);292endBlocking(n > 0);293assert IOStatus.check(n);294}295}296}297298public long write(ByteBuffer[] srcs, int offset, int length)299throws IOException300{301Objects.checkFromIndexSize(offset, length, srcs.length);302ensureOpen();303if (!writable)304throw new NonWritableChannelException();305synchronized (positionLock) {306if (direct)307Util.checkChannelPositionAligned(position(), alignment);308long n = 0;309int ti = -1;310try {311beginBlocking();312ti = threads.add();313if (!isOpen())314return 0;315do {316n = IOUtil.write(fd, srcs, offset, length,317direct, alignment, nd);318} while ((n == IOStatus.INTERRUPTED) && isOpen());319return IOStatus.normalize(n);320} finally {321threads.remove(ti);322endBlocking(n > 0);323assert IOStatus.check(n);324}325}326}327328// -- Other operations --329330public long position() throws IOException {331ensureOpen();332synchronized (positionLock) {333long p = -1;334int ti = -1;335try {336beginBlocking();337ti = threads.add();338if (!isOpen())339return 0;340boolean append = fdAccess.getAppend(fd);341do {342// in append-mode then position is advanced to end before writing343p = (append) ? nd.size(fd) : nd.seek(fd, -1);344} while ((p == IOStatus.INTERRUPTED) && isOpen());345return IOStatus.normalize(p);346} finally {347threads.remove(ti);348endBlocking(p > -1);349assert IOStatus.check(p);350}351}352}353354public FileChannel position(long newPosition) throws IOException {355ensureOpen();356if (newPosition < 0)357throw new IllegalArgumentException();358synchronized (positionLock) {359long p = -1;360int ti = -1;361try {362beginBlocking();363ti = threads.add();364if (!isOpen())365return null;366do {367p = nd.seek(fd, newPosition);368} while ((p == IOStatus.INTERRUPTED) && isOpen());369return this;370} finally {371threads.remove(ti);372endBlocking(p > -1);373assert IOStatus.check(p);374}375}376}377378public long size() throws IOException {379ensureOpen();380synchronized (positionLock) {381long s = -1;382int ti = -1;383try {384beginBlocking();385ti = threads.add();386if (!isOpen())387return -1;388do {389s = nd.size(fd);390} while ((s == IOStatus.INTERRUPTED) && isOpen());391return IOStatus.normalize(s);392} finally {393threads.remove(ti);394endBlocking(s > -1);395assert IOStatus.check(s);396}397}398}399400public FileChannel truncate(long newSize) throws IOException {401ensureOpen();402if (newSize < 0)403throw new IllegalArgumentException("Negative size");404if (!writable)405throw new NonWritableChannelException();406synchronized (positionLock) {407int rv = -1;408long p = -1;409int ti = -1;410long rp = -1;411try {412beginBlocking();413ti = threads.add();414if (!isOpen())415return null;416417// get current size418long size;419do {420size = nd.size(fd);421} while ((size == IOStatus.INTERRUPTED) && isOpen());422if (!isOpen())423return null;424425// get current position426do {427p = nd.seek(fd, -1);428} while ((p == IOStatus.INTERRUPTED) && isOpen());429if (!isOpen())430return null;431assert p >= 0;432433// truncate file if given size is less than the current size434if (newSize < size) {435do {436rv = nd.truncate(fd, newSize);437} while ((rv == IOStatus.INTERRUPTED) && isOpen());438if (!isOpen())439return null;440}441442// if position is beyond new size then adjust it443if (p > newSize)444p = newSize;445do {446rp = nd.seek(fd, p);447} while ((rp == IOStatus.INTERRUPTED) && isOpen());448return this;449} finally {450threads.remove(ti);451endBlocking(rv > -1);452assert IOStatus.check(rv);453}454}455}456457public void force(boolean metaData) throws IOException {458ensureOpen();459int rv = -1;460int ti = -1;461try {462beginBlocking();463ti = threads.add();464if (!isOpen())465return;466do {467rv = nd.force(fd, metaData);468} while ((rv == IOStatus.INTERRUPTED) && isOpen());469} finally {470threads.remove(ti);471endBlocking(rv > -1);472assert IOStatus.check(rv);473}474}475476// Assume at first that the underlying kernel supports sendfile();477// set this to false if we find out later that it doesn't478//479private static volatile boolean transferSupported = true;480481// Assume that the underlying kernel sendfile() will work if the target482// fd is a pipe; set this to false if we find out later that it doesn't483//484private static volatile boolean pipeSupported = true;485486// Assume that the underlying kernel sendfile() will work if the target487// fd is a file; set this to false if we find out later that it doesn't488//489private static volatile boolean fileSupported = true;490491private long transferToDirectlyInternal(long position, int icount,492WritableByteChannel target,493FileDescriptor targetFD)494throws IOException495{496assert !nd.transferToDirectlyNeedsPositionLock() ||497Thread.holdsLock(positionLock);498499long n = -1;500int ti = -1;501try {502beginBlocking();503ti = threads.add();504if (!isOpen())505return -1;506do {507n = transferTo0(fd, position, icount, targetFD);508} while ((n == IOStatus.INTERRUPTED) && isOpen());509if (n == IOStatus.UNSUPPORTED_CASE) {510if (target instanceof SinkChannelImpl)511pipeSupported = false;512if (target instanceof FileChannelImpl)513fileSupported = false;514return IOStatus.UNSUPPORTED_CASE;515}516if (n == IOStatus.UNSUPPORTED) {517// Don't bother trying again518transferSupported = false;519return IOStatus.UNSUPPORTED;520}521return IOStatus.normalize(n);522} finally {523threads.remove(ti);524end (n > -1);525}526}527528private long transferToDirectly(long position, int icount,529WritableByteChannel target)530throws IOException531{532if (!transferSupported)533return IOStatus.UNSUPPORTED;534535FileDescriptor targetFD = null;536if (target instanceof FileChannelImpl) {537if (!fileSupported)538return IOStatus.UNSUPPORTED_CASE;539targetFD = ((FileChannelImpl)target).fd;540} else if (target instanceof SelChImpl) {541// Direct transfer to pipe causes EINVAL on some configurations542if ((target instanceof SinkChannelImpl) && !pipeSupported)543return IOStatus.UNSUPPORTED_CASE;544545// Platform-specific restrictions. Now there is only one:546// Direct transfer to non-blocking channel could be forbidden547SelectableChannel sc = (SelectableChannel)target;548if (!nd.canTransferToDirectly(sc))549return IOStatus.UNSUPPORTED_CASE;550551targetFD = ((SelChImpl)target).getFD();552}553554if (targetFD == null)555return IOStatus.UNSUPPORTED;556int thisFDVal = IOUtil.fdVal(fd);557int targetFDVal = IOUtil.fdVal(targetFD);558if (thisFDVal == targetFDVal) // Not supported on some configurations559return IOStatus.UNSUPPORTED;560561if (nd.transferToDirectlyNeedsPositionLock()) {562synchronized (positionLock) {563long pos = position();564try {565return transferToDirectlyInternal(position, icount,566target, targetFD);567} finally {568position(pos);569}570}571} else {572return transferToDirectlyInternal(position, icount, target, targetFD);573}574}575576// Maximum size to map when using a mapped buffer577private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;578579private long transferToTrustedChannel(long position, long count,580WritableByteChannel target)581throws IOException582{583boolean isSelChImpl = (target instanceof SelChImpl);584if (!((target instanceof FileChannelImpl) || isSelChImpl))585return IOStatus.UNSUPPORTED;586587if (target == this) {588long posThis = position();589if (posThis - count + 1 <= position &&590position - count + 1 <= posThis &&591!nd.canTransferToFromOverlappedMap()) {592return IOStatus.UNSUPPORTED_CASE;593}594}595596// Trusted target: Use a mapped buffer597long remaining = count;598while (remaining > 0L) {599long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);600try {601MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);602try {603// ## Bug: Closing this channel will not terminate the write604int n = target.write(dbb);605assert n >= 0;606remaining -= n;607if (isSelChImpl) {608// one attempt to write to selectable channel609break;610}611assert n > 0;612position += n;613} finally {614unmap(dbb);615}616} catch (ClosedByInterruptException e) {617// target closed by interrupt as ClosedByInterruptException needs618// to be thrown after closing this channel.619assert !target.isOpen();620try {621close();622} catch (Throwable suppressed) {623e.addSuppressed(suppressed);624}625throw e;626} catch (IOException ioe) {627// Only throw exception if no bytes have been written628if (remaining == count)629throw ioe;630break;631}632}633return count - remaining;634}635636private long transferToArbitraryChannel(long position, long count,637WritableByteChannel target)638throws IOException639{640// Untrusted target: Use a newly-erased buffer641int c = (int)Math.min(count, TRANSFER_SIZE);642ByteBuffer bb = ByteBuffer.allocate(c);643long tw = 0; // Total bytes written644long pos = position;645try {646while (tw < count) {647bb.limit((int)Math.min(count - tw, TRANSFER_SIZE));648int nr = read(bb, pos);649if (nr <= 0)650break;651bb.flip();652// ## Bug: Will block writing target if this channel653// ## is asynchronously closed654int nw = target.write(bb);655tw += nw;656if (nw != nr)657break;658pos += nw;659bb.clear();660}661return tw;662} catch (IOException x) {663if (tw > 0)664return tw;665throw x;666}667}668669public long transferTo(long position, long count,670WritableByteChannel target)671throws IOException672{673ensureOpen();674if (!target.isOpen())675throw new ClosedChannelException();676if (!readable)677throw new NonReadableChannelException();678if (target instanceof FileChannelImpl &&679!((FileChannelImpl)target).writable)680throw new NonWritableChannelException();681if ((position < 0) || (count < 0))682throw new IllegalArgumentException();683long sz = size();684if (position > sz)685return 0;686687if ((sz - position) < count)688count = sz - position;689690// Attempt a direct transfer, if the kernel supports it, limiting691// the number of bytes according to which platform692int icount = (int)Math.min(count, MAX_DIRECT_TRANSFER_SIZE);693long n;694if ((n = transferToDirectly(position, icount, target)) >= 0)695return n;696697// Attempt a mapped transfer, but only to trusted channel types698if ((n = transferToTrustedChannel(position, count, target)) >= 0)699return n;700701// Slow path for untrusted targets702return transferToArbitraryChannel(position, count, target);703}704705private long transferFromFileChannel(FileChannelImpl src,706long position, long count)707throws IOException708{709if (!src.readable)710throw new NonReadableChannelException();711synchronized (src.positionLock) {712long pos = src.position();713long max = Math.min(count, src.size() - pos);714715if (src == this) {716if (position() - max + 1 <= pos &&717pos - max + 1 <= position() &&718!nd.canTransferToFromOverlappedMap()) {719return IOStatus.UNSUPPORTED_CASE;720}721}722723long remaining = max;724long p = pos;725while (remaining > 0L) {726long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);727// ## Bug: Closing this channel will not terminate the write728MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);729try {730long n = write(bb, position);731assert n > 0;732p += n;733position += n;734remaining -= n;735} catch (IOException ioe) {736// Only throw exception if no bytes have been written737if (remaining == max)738throw ioe;739break;740} finally {741unmap(bb);742}743}744long nwritten = max - remaining;745src.position(pos + nwritten);746return nwritten;747}748}749750private static final int TRANSFER_SIZE = 8192;751752private long transferFromArbitraryChannel(ReadableByteChannel src,753long position, long count)754throws IOException755{756// Untrusted target: Use a newly-erased buffer757int c = (int)Math.min(count, TRANSFER_SIZE);758ByteBuffer bb = ByteBuffer.allocate(c);759long tw = 0; // Total bytes written760long pos = position;761try {762while (tw < count) {763bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));764// ## Bug: Will block reading src if this channel765// ## is asynchronously closed766int nr = src.read(bb);767if (nr <= 0)768break;769bb.flip();770int nw = write(bb, pos);771tw += nw;772if (nw != nr)773break;774pos += nw;775bb.clear();776}777return tw;778} catch (IOException x) {779if (tw > 0)780return tw;781throw x;782}783}784785public long transferFrom(ReadableByteChannel src,786long position, long count)787throws IOException788{789ensureOpen();790if (!src.isOpen())791throw new ClosedChannelException();792if (!writable)793throw new NonWritableChannelException();794if ((position < 0) || (count < 0))795throw new IllegalArgumentException();796if (position > size())797return 0;798799if (src instanceof FileChannelImpl fci) {800long n = transferFromFileChannel(fci, position, count);801if (n >= 0)802return n;803}804805return transferFromArbitraryChannel(src, position, count);806}807808public int read(ByteBuffer dst, long position) throws IOException {809if (dst == null)810throw new NullPointerException();811if (position < 0)812throw new IllegalArgumentException("Negative position");813ensureOpen();814if (!readable)815throw new NonReadableChannelException();816if (direct)817Util.checkChannelPositionAligned(position, alignment);818if (nd.needsPositionLock()) {819synchronized (positionLock) {820return readInternal(dst, position);821}822} else {823return readInternal(dst, position);824}825}826827private int readInternal(ByteBuffer dst, long position) throws IOException {828assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);829int n = 0;830int ti = -1;831832try {833beginBlocking();834ti = threads.add();835if (!isOpen())836return -1;837do {838n = IOUtil.read(fd, dst, position, direct, alignment, nd);839} while ((n == IOStatus.INTERRUPTED) && isOpen());840return IOStatus.normalize(n);841} finally {842threads.remove(ti);843endBlocking(n > 0);844assert IOStatus.check(n);845}846}847848public int write(ByteBuffer src, long position) throws IOException {849if (src == null)850throw new NullPointerException();851if (position < 0)852throw new IllegalArgumentException("Negative position");853ensureOpen();854if (!writable)855throw new NonWritableChannelException();856if (direct)857Util.checkChannelPositionAligned(position, alignment);858if (nd.needsPositionLock()) {859synchronized (positionLock) {860return writeInternal(src, position);861}862} else {863return writeInternal(src, position);864}865}866867private int writeInternal(ByteBuffer src, long position) throws IOException {868assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);869int n = 0;870int ti = -1;871try {872beginBlocking();873ti = threads.add();874if (!isOpen())875return -1;876do {877n = IOUtil.write(fd, src, position, direct, alignment, nd);878} while ((n == IOStatus.INTERRUPTED) && isOpen());879return IOStatus.normalize(n);880} finally {881threads.remove(ti);882endBlocking(n > 0);883assert IOStatus.check(n);884}885}886887888// -- Memory-mapped buffers --889890private static abstract class Unmapper891implements Runnable, UnmapperProxy892{893// may be required to close file894private static final NativeDispatcher nd = new FileDispatcherImpl();895896private volatile long address;897protected final long size;898protected final long cap;899private final FileDescriptor fd;900private final int pagePosition;901902private Unmapper(long address, long size, long cap,903FileDescriptor fd, int pagePosition)904{905assert (address != 0);906this.address = address;907this.size = size;908this.cap = cap;909this.fd = fd;910this.pagePosition = pagePosition;911}912913@Override914public long address() {915return address + pagePosition;916}917918@Override919public FileDescriptor fileDescriptor() {920return fd;921}922923@Override924public void run() {925unmap();926}927928public void unmap() {929if (address == 0)930return;931unmap0(address, size);932address = 0;933934// if this mapping has a valid file descriptor then we close it935if (fd.valid()) {936try {937nd.close(fd);938} catch (IOException ignore) {939// nothing we can do940}941}942943decrementStats();944}945protected abstract void incrementStats();946protected abstract void decrementStats();947}948949private static class DefaultUnmapper extends Unmapper {950951// keep track of non-sync mapped buffer usage952static volatile int count;953static volatile long totalSize;954static volatile long totalCapacity;955956public DefaultUnmapper(long address, long size, long cap,957FileDescriptor fd, int pagePosition) {958super(address, size, cap, fd, pagePosition);959incrementStats();960}961962protected void incrementStats() {963synchronized (DefaultUnmapper.class) {964count++;965totalSize += size;966totalCapacity += cap;967}968}969protected void decrementStats() {970synchronized (DefaultUnmapper.class) {971count--;972totalSize -= size;973totalCapacity -= cap;974}975}976977public boolean isSync() {978return false;979}980}981982private static class SyncUnmapper extends Unmapper {983984// keep track of mapped buffer usage985static volatile int count;986static volatile long totalSize;987static volatile long totalCapacity;988989public SyncUnmapper(long address, long size, long cap,990FileDescriptor fd, int pagePosition) {991super(address, size, cap, fd, pagePosition);992incrementStats();993}994995protected void incrementStats() {996synchronized (SyncUnmapper.class) {997count++;998totalSize += size;999totalCapacity += cap;1000}1001}1002protected void decrementStats() {1003synchronized (SyncUnmapper.class) {1004count--;1005totalSize -= size;1006totalCapacity -= cap;1007}1008}10091010public boolean isSync() {1011return true;1012}1013}10141015private static void unmap(MappedByteBuffer bb) {1016Cleaner cl = ((DirectBuffer)bb).cleaner();1017if (cl != null)1018cl.clean();1019}10201021private static final int MAP_INVALID = -1;1022private static final int MAP_RO = 0;1023private static final int MAP_RW = 1;1024private static final int MAP_PV = 2;10251026public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {1027if (size > Integer.MAX_VALUE)1028throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");1029boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));1030int prot = toProt(mode);1031Unmapper unmapper = mapInternal(mode, position, size, prot, isSync);1032if (unmapper == null) {1033// a valid file descriptor is not required1034FileDescriptor dummy = new FileDescriptor();1035if ((!writable) || (prot == MAP_RO))1036return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);1037else1038return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);1039} else if ((!writable) || (prot == MAP_RO)) {1040return Util.newMappedByteBufferR((int)unmapper.cap,1041unmapper.address + unmapper.pagePosition,1042unmapper.fd,1043unmapper, isSync);1044} else {1045return Util.newMappedByteBuffer((int)unmapper.cap,1046unmapper.address + unmapper.pagePosition,1047unmapper.fd,1048unmapper, isSync);1049}1050}10511052public Unmapper mapInternal(MapMode mode, long position, long size) throws IOException {1053boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));1054int prot = toProt(mode);1055return mapInternal(mode, position, size, prot, isSync);1056}10571058private Unmapper mapInternal(MapMode mode, long position, long size, int prot, boolean isSync)1059throws IOException1060{1061ensureOpen();1062if (mode == null)1063throw new NullPointerException("Mode is null");1064if (position < 0L)1065throw new IllegalArgumentException("Negative position");1066if (size < 0L)1067throw new IllegalArgumentException("Negative size");1068if (position + size < 0)1069throw new IllegalArgumentException("Position + size overflow");10701071checkMode(mode, prot, isSync);1072long addr = -1;1073int ti = -1;1074try {1075beginBlocking();1076ti = threads.add();1077if (!isOpen())1078return null;10791080long mapSize;1081int pagePosition;1082synchronized (positionLock) {1083long filesize;1084do {1085filesize = nd.size(fd);1086} while ((filesize == IOStatus.INTERRUPTED) && isOpen());1087if (!isOpen())1088return null;10891090if (filesize < position + size) { // Extend file size1091if (!writable) {1092throw new IOException("Channel not open for writing " +1093"- cannot extend file to required size");1094}1095int rv;1096do {1097rv = nd.truncate(fd, position + size);1098} while ((rv == IOStatus.INTERRUPTED) && isOpen());1099if (!isOpen())1100return null;1101}11021103if (size == 0) {1104return null;1105}11061107pagePosition = (int)(position % allocationGranularity);1108long mapPosition = position - pagePosition;1109mapSize = size + pagePosition;1110try {1111// If map0 did not throw an exception, the address is valid1112addr = map0(prot, mapPosition, mapSize, isSync);1113} catch (OutOfMemoryError x) {1114// An OutOfMemoryError may indicate that we've exhausted1115// memory so force gc and re-attempt map1116System.gc();1117try {1118Thread.sleep(100);1119} catch (InterruptedException y) {1120Thread.currentThread().interrupt();1121}1122try {1123addr = map0(prot, mapPosition, mapSize, isSync);1124} catch (OutOfMemoryError y) {1125// After a second OOME, fail1126throw new IOException("Map failed", y);1127}1128}1129} // synchronized11301131// On Windows, and potentially other platforms, we need an open1132// file descriptor for some mapping operations.1133FileDescriptor mfd;1134try {1135mfd = nd.duplicateForMapping(fd);1136} catch (IOException ioe) {1137unmap0(addr, mapSize);1138throw ioe;1139}11401141assert (IOStatus.checkAll(addr));1142assert (addr % allocationGranularity == 0);1143Unmapper um = (isSync1144? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition)1145: new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition));1146return um;1147} finally {1148threads.remove(ti);1149endBlocking(IOStatus.checkAll(addr));1150}1151}11521153private boolean isSync(MapMode mode) {1154// Do not want to initialize ExtendedMapMode until1155// after the module system has been initialized1156return !VM.isModuleSystemInited() ? false :1157(mode == ExtendedMapMode.READ_ONLY_SYNC ||1158mode == ExtendedMapMode.READ_WRITE_SYNC);1159}11601161private int toProt(MapMode mode) {1162int prot;1163if (mode == MapMode.READ_ONLY) {1164prot = MAP_RO;1165} else if (mode == MapMode.READ_WRITE) {1166prot = MAP_RW;1167} else if (mode == MapMode.PRIVATE) {1168prot = MAP_PV;1169} else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {1170prot = MAP_RO;1171} else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {1172prot = MAP_RW;1173} else {1174prot = MAP_INVALID;1175}1176return prot;1177}11781179private void checkMode(MapMode mode, int prot, boolean isSync) {1180if (prot == MAP_INVALID) {1181throw new UnsupportedOperationException();1182}1183if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)1184throw new NonWritableChannelException();1185if (!readable)1186throw new NonReadableChannelException();1187// reject SYNC request if writeback is not enabled for this platform1188if (isSync && !Unsafe.isWritebackEnabled()) {1189throw new UnsupportedOperationException();1190}1191}11921193/**1194* Invoked by sun.management.ManagementFactoryHelper to create the management1195* interface for mapped buffers.1196*/1197public static BufferPool getMappedBufferPool() {1198return new BufferPool() {1199@Override1200public String getName() {1201return "mapped";1202}1203@Override1204public long getCount() {1205return DefaultUnmapper.count;1206}1207@Override1208public long getTotalCapacity() {1209return DefaultUnmapper.totalCapacity;1210}1211@Override1212public long getMemoryUsed() {1213return DefaultUnmapper.totalSize;1214}1215};1216}12171218/**1219* Invoked by sun.management.ManagementFactoryHelper to create the management1220* interface for sync mapped buffers.1221*/1222public static BufferPool getSyncMappedBufferPool() {1223return new BufferPool() {1224@Override1225public String getName() {1226return "mapped - 'non-volatile memory'";1227}1228@Override1229public long getCount() {1230return SyncUnmapper.count;1231}1232@Override1233public long getTotalCapacity() {1234return SyncUnmapper.totalCapacity;1235}1236@Override1237public long getMemoryUsed() {1238return SyncUnmapper.totalSize;1239}1240};1241}12421243// -- Locks --12441245// keeps track of locks on this file1246private volatile FileLockTable fileLockTable;12471248private FileLockTable fileLockTable() throws IOException {1249if (fileLockTable == null) {1250synchronized (this) {1251if (fileLockTable == null) {1252int ti = threads.add();1253try {1254ensureOpen();1255fileLockTable = new FileLockTable(this, fd);1256} finally {1257threads.remove(ti);1258}1259}1260}1261}1262return fileLockTable;1263}12641265public FileLock lock(long position, long size, boolean shared)1266throws IOException1267{1268ensureOpen();1269if (shared && !readable)1270throw new NonReadableChannelException();1271if (!shared && !writable)1272throw new NonWritableChannelException();1273FileLockImpl fli = new FileLockImpl(this, position, size, shared);1274FileLockTable flt = fileLockTable();1275flt.add(fli);1276boolean completed = false;1277int ti = -1;1278try {1279beginBlocking();1280ti = threads.add();1281if (!isOpen())1282return null;1283int n;1284do {1285n = nd.lock(fd, true, position, size, shared);1286} while ((n == FileDispatcher.INTERRUPTED) && isOpen());1287if (isOpen()) {1288if (n == FileDispatcher.RET_EX_LOCK) {1289assert shared;1290FileLockImpl fli2 = new FileLockImpl(this, position, size,1291false);1292flt.replace(fli, fli2);1293fli = fli2;1294}1295completed = true;1296}1297} finally {1298if (!completed)1299flt.remove(fli);1300threads.remove(ti);1301try {1302endBlocking(completed);1303} catch (ClosedByInterruptException e) {1304throw new FileLockInterruptionException();1305}1306}1307return fli;1308}13091310public FileLock tryLock(long position, long size, boolean shared)1311throws IOException1312{1313ensureOpen();1314if (shared && !readable)1315throw new NonReadableChannelException();1316if (!shared && !writable)1317throw new NonWritableChannelException();1318FileLockImpl fli = new FileLockImpl(this, position, size, shared);1319FileLockTable flt = fileLockTable();1320flt.add(fli);1321int result;13221323int ti = threads.add();1324try {1325try {1326ensureOpen();1327result = nd.lock(fd, false, position, size, shared);1328} catch (IOException e) {1329flt.remove(fli);1330throw e;1331}1332if (result == FileDispatcher.NO_LOCK) {1333flt.remove(fli);1334return null;1335}1336if (result == FileDispatcher.RET_EX_LOCK) {1337assert shared;1338FileLockImpl fli2 = new FileLockImpl(this, position, size,1339false);1340flt.replace(fli, fli2);1341return fli2;1342}1343return fli;1344} finally {1345threads.remove(ti);1346}1347}13481349void release(FileLockImpl fli) throws IOException {1350int ti = threads.add();1351try {1352ensureOpen();1353nd.release(fd, fli.position(), fli.size());1354} finally {1355threads.remove(ti);1356}1357assert fileLockTable != null;1358fileLockTable.remove(fli);1359}13601361// -- Native methods --13621363// Creates a new mapping1364private native long map0(int prot, long position, long length, boolean isSync)1365throws IOException;13661367// Removes an existing mapping1368private static native int unmap0(long address, long length);13691370// Transfers from src to dst, or returns -2 if kernel can't do that1371private native long transferTo0(FileDescriptor src, long position,1372long count, FileDescriptor dst);13731374// Retrieves the maximum size of a transfer1375private static native int maxDirectTransferSize0();13761377// Caches fieldIDs1378private static native long initIDs();13791380static {1381IOUtil.load();1382allocationGranularity = initIDs();1383MAX_DIRECT_TRANSFER_SIZE = maxDirectTransferSize0();1384}1385}138613871388