Path: blob/master/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
41159 views
/*1* Copyright (c) 2000, 2020, 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// Used to make native read and write calls68private final FileDispatcher nd;6970// File descriptor71private final FileDescriptor fd;7273// File access mode (immutable)74private final boolean writable;75private final boolean readable;7677// Required to prevent finalization of creating stream (immutable)78private final Object parent;7980// The path of the referenced file81// (null if the parent stream is created with a file descriptor)82private final String path;8384// Thread-safe set of IDs of native threads, for signalling85private final NativeThreadSet threads = new NativeThreadSet(2);8687// Lock for operations involving position and size88private final Object positionLock = new Object();8990// blocking operations are not interruptible91private volatile boolean uninterruptible;9293// DirectIO flag94private final boolean direct;9596// IO alignment value for DirectIO97private final int alignment;9899// Cleanable with an action which closes this channel's file descriptor100private final Cleanable closer;101102private static class Closer implements Runnable {103private final FileDescriptor fd;104105Closer(FileDescriptor fd) {106this.fd = fd;107}108109public void run() {110try {111fdAccess.close(fd);112} catch (IOException ioe) {113// Rethrow as unchecked so the exception can be propagated as needed114throw new UncheckedIOException("close", ioe);115}116}117}118119private FileChannelImpl(FileDescriptor fd, String path, boolean readable,120boolean writable, boolean direct, Object parent)121{122this.fd = fd;123this.readable = readable;124this.writable = writable;125this.parent = parent;126this.path = path;127this.direct = direct;128this.nd = new FileDispatcherImpl();129if (direct) {130assert path != null;131this.alignment = nd.setDirectIO(fd, path);132} else {133this.alignment = -1;134}135136// Register a cleaning action if and only if there is no parent137// as the parent will take care of closing the file descriptor.138// FileChannel is used by the LambdaMetaFactory so a lambda cannot139// be used here hence we use a nested class instead.140this.closer = parent != null ? null :141CleanerFactory.cleaner().register(this, new Closer(fd));142}143144// Used by FileInputStream.getChannel(), FileOutputStream.getChannel145// and RandomAccessFile.getChannel()146public static FileChannel open(FileDescriptor fd, String path,147boolean readable, boolean writable,148boolean direct, Object parent)149{150return new FileChannelImpl(fd, path, readable, writable, direct, parent);151}152153private void ensureOpen() throws IOException {154if (!isOpen())155throw new ClosedChannelException();156}157158public void setUninterruptible() {159uninterruptible = true;160}161162private void beginBlocking() {163if (!uninterruptible) begin();164}165166private void endBlocking(boolean completed) throws AsynchronousCloseException {167if (!uninterruptible) end(completed);168}169170// -- Standard channel operations --171172protected void implCloseChannel() throws IOException {173if (!fd.valid())174return; // nothing to do175176// Release and invalidate any locks that we still hold177if (fileLockTable != null) {178for (FileLock fl: fileLockTable.removeAll()) {179synchronized (fl) {180if (fl.isValid()) {181nd.release(fd, fl.position(), fl.size());182((FileLockImpl)fl).invalidate();183}184}185}186}187188// signal any threads blocked on this channel189threads.signalAndWait();190191if (parent != null) {192193// Close the fd via the parent stream's close method. The parent194// will reinvoke our close method, which is defined in the195// superclass AbstractInterruptibleChannel, but the isOpen logic in196// that method will prevent this method from being reinvoked.197//198((java.io.Closeable)parent).close();199} else if (closer != null) {200// Perform the cleaning action so it is not redone when201// this channel becomes phantom reachable.202try {203closer.clean();204} catch (UncheckedIOException uioe) {205throw uioe.getCause();206}207} else {208fdAccess.close(fd);209}210211}212213public int read(ByteBuffer dst) throws IOException {214ensureOpen();215if (!readable)216throw new NonReadableChannelException();217synchronized (positionLock) {218if (direct)219Util.checkChannelPositionAligned(position(), alignment);220int n = 0;221int ti = -1;222try {223beginBlocking();224ti = threads.add();225if (!isOpen())226return 0;227do {228n = IOUtil.read(fd, dst, -1, direct, alignment, nd);229} while ((n == IOStatus.INTERRUPTED) && isOpen());230return IOStatus.normalize(n);231} finally {232threads.remove(ti);233endBlocking(n > 0);234assert IOStatus.check(n);235}236}237}238239public long read(ByteBuffer[] dsts, int offset, int length)240throws IOException241{242Objects.checkFromIndexSize(offset, length, dsts.length);243ensureOpen();244if (!readable)245throw new NonReadableChannelException();246synchronized (positionLock) {247if (direct)248Util.checkChannelPositionAligned(position(), alignment);249long n = 0;250int ti = -1;251try {252beginBlocking();253ti = threads.add();254if (!isOpen())255return 0;256do {257n = IOUtil.read(fd, dsts, offset, length,258direct, alignment, nd);259} while ((n == IOStatus.INTERRUPTED) && isOpen());260return IOStatus.normalize(n);261} finally {262threads.remove(ti);263endBlocking(n > 0);264assert IOStatus.check(n);265}266}267}268269public int write(ByteBuffer src) throws IOException {270ensureOpen();271if (!writable)272throw new NonWritableChannelException();273synchronized (positionLock) {274if (direct)275Util.checkChannelPositionAligned(position(), alignment);276int n = 0;277int ti = -1;278try {279beginBlocking();280ti = threads.add();281if (!isOpen())282return 0;283do {284n = IOUtil.write(fd, src, -1, direct, alignment, nd);285} while ((n == IOStatus.INTERRUPTED) && isOpen());286return IOStatus.normalize(n);287} finally {288threads.remove(ti);289endBlocking(n > 0);290assert IOStatus.check(n);291}292}293}294295public long write(ByteBuffer[] srcs, int offset, int length)296throws IOException297{298Objects.checkFromIndexSize(offset, length, srcs.length);299ensureOpen();300if (!writable)301throw new NonWritableChannelException();302synchronized (positionLock) {303if (direct)304Util.checkChannelPositionAligned(position(), alignment);305long n = 0;306int ti = -1;307try {308beginBlocking();309ti = threads.add();310if (!isOpen())311return 0;312do {313n = IOUtil.write(fd, srcs, offset, length,314direct, alignment, nd);315} while ((n == IOStatus.INTERRUPTED) && isOpen());316return IOStatus.normalize(n);317} finally {318threads.remove(ti);319endBlocking(n > 0);320assert IOStatus.check(n);321}322}323}324325// -- Other operations --326327public long position() throws IOException {328ensureOpen();329synchronized (positionLock) {330long p = -1;331int ti = -1;332try {333beginBlocking();334ti = threads.add();335if (!isOpen())336return 0;337boolean append = fdAccess.getAppend(fd);338do {339// in append-mode then position is advanced to end before writing340p = (append) ? nd.size(fd) : nd.seek(fd, -1);341} while ((p == IOStatus.INTERRUPTED) && isOpen());342return IOStatus.normalize(p);343} finally {344threads.remove(ti);345endBlocking(p > -1);346assert IOStatus.check(p);347}348}349}350351public FileChannel position(long newPosition) throws IOException {352ensureOpen();353if (newPosition < 0)354throw new IllegalArgumentException();355synchronized (positionLock) {356long p = -1;357int ti = -1;358try {359beginBlocking();360ti = threads.add();361if (!isOpen())362return null;363do {364p = nd.seek(fd, newPosition);365} while ((p == IOStatus.INTERRUPTED) && isOpen());366return this;367} finally {368threads.remove(ti);369endBlocking(p > -1);370assert IOStatus.check(p);371}372}373}374375public long size() throws IOException {376ensureOpen();377synchronized (positionLock) {378long s = -1;379int ti = -1;380try {381beginBlocking();382ti = threads.add();383if (!isOpen())384return -1;385do {386s = nd.size(fd);387} while ((s == IOStatus.INTERRUPTED) && isOpen());388return IOStatus.normalize(s);389} finally {390threads.remove(ti);391endBlocking(s > -1);392assert IOStatus.check(s);393}394}395}396397public FileChannel truncate(long newSize) throws IOException {398ensureOpen();399if (newSize < 0)400throw new IllegalArgumentException("Negative size");401if (!writable)402throw new NonWritableChannelException();403synchronized (positionLock) {404int rv = -1;405long p = -1;406int ti = -1;407long rp = -1;408try {409beginBlocking();410ti = threads.add();411if (!isOpen())412return null;413414// get current size415long size;416do {417size = nd.size(fd);418} while ((size == IOStatus.INTERRUPTED) && isOpen());419if (!isOpen())420return null;421422// get current position423do {424p = nd.seek(fd, -1);425} while ((p == IOStatus.INTERRUPTED) && isOpen());426if (!isOpen())427return null;428assert p >= 0;429430// truncate file if given size is less than the current size431if (newSize < size) {432do {433rv = nd.truncate(fd, newSize);434} while ((rv == IOStatus.INTERRUPTED) && isOpen());435if (!isOpen())436return null;437}438439// if position is beyond new size then adjust it440if (p > newSize)441p = newSize;442do {443rp = nd.seek(fd, p);444} while ((rp == IOStatus.INTERRUPTED) && isOpen());445return this;446} finally {447threads.remove(ti);448endBlocking(rv > -1);449assert IOStatus.check(rv);450}451}452}453454public void force(boolean metaData) throws IOException {455ensureOpen();456int rv = -1;457int ti = -1;458try {459beginBlocking();460ti = threads.add();461if (!isOpen())462return;463do {464rv = nd.force(fd, metaData);465} while ((rv == IOStatus.INTERRUPTED) && isOpen());466} finally {467threads.remove(ti);468endBlocking(rv > -1);469assert IOStatus.check(rv);470}471}472473// Assume at first that the underlying kernel supports sendfile();474// set this to false if we find out later that it doesn't475//476private static volatile boolean transferSupported = true;477478// Assume that the underlying kernel sendfile() will work if the target479// fd is a pipe; set this to false if we find out later that it doesn't480//481private static volatile boolean pipeSupported = true;482483// Assume that the underlying kernel sendfile() will work if the target484// fd is a file; set this to false if we find out later that it doesn't485//486private static volatile boolean fileSupported = true;487488private long transferToDirectlyInternal(long position, int icount,489WritableByteChannel target,490FileDescriptor targetFD)491throws IOException492{493assert !nd.transferToDirectlyNeedsPositionLock() ||494Thread.holdsLock(positionLock);495496long n = -1;497int ti = -1;498try {499beginBlocking();500ti = threads.add();501if (!isOpen())502return -1;503do {504n = transferTo0(fd, position, icount, targetFD);505} while ((n == IOStatus.INTERRUPTED) && isOpen());506if (n == IOStatus.UNSUPPORTED_CASE) {507if (target instanceof SinkChannelImpl)508pipeSupported = false;509if (target instanceof FileChannelImpl)510fileSupported = false;511return IOStatus.UNSUPPORTED_CASE;512}513if (n == IOStatus.UNSUPPORTED) {514// Don't bother trying again515transferSupported = false;516return IOStatus.UNSUPPORTED;517}518return IOStatus.normalize(n);519} finally {520threads.remove(ti);521end (n > -1);522}523}524525private long transferToDirectly(long position, int icount,526WritableByteChannel target)527throws IOException528{529if (!transferSupported)530return IOStatus.UNSUPPORTED;531532FileDescriptor targetFD = null;533if (target instanceof FileChannelImpl) {534if (!fileSupported)535return IOStatus.UNSUPPORTED_CASE;536targetFD = ((FileChannelImpl)target).fd;537} else if (target instanceof SelChImpl) {538// Direct transfer to pipe causes EINVAL on some configurations539if ((target instanceof SinkChannelImpl) && !pipeSupported)540return IOStatus.UNSUPPORTED_CASE;541542// Platform-specific restrictions. Now there is only one:543// Direct transfer to non-blocking channel could be forbidden544SelectableChannel sc = (SelectableChannel)target;545if (!nd.canTransferToDirectly(sc))546return IOStatus.UNSUPPORTED_CASE;547548targetFD = ((SelChImpl)target).getFD();549}550551if (targetFD == null)552return IOStatus.UNSUPPORTED;553int thisFDVal = IOUtil.fdVal(fd);554int targetFDVal = IOUtil.fdVal(targetFD);555if (thisFDVal == targetFDVal) // Not supported on some configurations556return IOStatus.UNSUPPORTED;557558if (nd.transferToDirectlyNeedsPositionLock()) {559synchronized (positionLock) {560long pos = position();561try {562return transferToDirectlyInternal(position, icount,563target, targetFD);564} finally {565position(pos);566}567}568} else {569return transferToDirectlyInternal(position, icount, target, targetFD);570}571}572573// Maximum size to map when using a mapped buffer574private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;575576private long transferToTrustedChannel(long position, long count,577WritableByteChannel target)578throws IOException579{580boolean isSelChImpl = (target instanceof SelChImpl);581if (!((target instanceof FileChannelImpl) || isSelChImpl))582return IOStatus.UNSUPPORTED;583584// Trusted target: Use a mapped buffer585long remaining = count;586while (remaining > 0L) {587long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);588try {589MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);590try {591// ## Bug: Closing this channel will not terminate the write592int n = target.write(dbb);593assert n >= 0;594remaining -= n;595if (isSelChImpl) {596// one attempt to write to selectable channel597break;598}599assert n > 0;600position += n;601} finally {602unmap(dbb);603}604} catch (ClosedByInterruptException e) {605// target closed by interrupt as ClosedByInterruptException needs606// to be thrown after closing this channel.607assert !target.isOpen();608try {609close();610} catch (Throwable suppressed) {611e.addSuppressed(suppressed);612}613throw e;614} catch (IOException ioe) {615// Only throw exception if no bytes have been written616if (remaining == count)617throw ioe;618break;619}620}621return count - remaining;622}623624private long transferToArbitraryChannel(long position, int icount,625WritableByteChannel target)626throws IOException627{628// Untrusted target: Use a newly-erased buffer629int c = Math.min(icount, TRANSFER_SIZE);630ByteBuffer bb = ByteBuffer.allocate(c);631long tw = 0; // Total bytes written632long pos = position;633try {634while (tw < icount) {635bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE));636int nr = read(bb, pos);637if (nr <= 0)638break;639bb.flip();640// ## Bug: Will block writing target if this channel641// ## is asynchronously closed642int nw = target.write(bb);643tw += nw;644if (nw != nr)645break;646pos += nw;647bb.clear();648}649return tw;650} catch (IOException x) {651if (tw > 0)652return tw;653throw x;654}655}656657public long transferTo(long position, long count,658WritableByteChannel target)659throws IOException660{661ensureOpen();662if (!target.isOpen())663throw new ClosedChannelException();664if (!readable)665throw new NonReadableChannelException();666if (target instanceof FileChannelImpl &&667!((FileChannelImpl)target).writable)668throw new NonWritableChannelException();669if ((position < 0) || (count < 0))670throw new IllegalArgumentException();671long sz = size();672if (position > sz)673return 0;674int icount = (int)Math.min(count, Integer.MAX_VALUE);675if ((sz - position) < icount)676icount = (int)(sz - position);677678long n;679680// Attempt a direct transfer, if the kernel supports it681if ((n = transferToDirectly(position, icount, target)) >= 0)682return n;683684// Attempt a mapped transfer, but only to trusted channel types685if ((n = transferToTrustedChannel(position, icount, target)) >= 0)686return n;687688// Slow path for untrusted targets689return transferToArbitraryChannel(position, icount, target);690}691692private long transferFromFileChannel(FileChannelImpl src,693long position, long count)694throws IOException695{696if (!src.readable)697throw new NonReadableChannelException();698synchronized (src.positionLock) {699long pos = src.position();700long max = Math.min(count, src.size() - pos);701702long remaining = max;703long p = pos;704while (remaining > 0L) {705long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);706// ## Bug: Closing this channel will not terminate the write707MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);708try {709long n = write(bb, position);710assert n > 0;711p += n;712position += n;713remaining -= n;714} catch (IOException ioe) {715// Only throw exception if no bytes have been written716if (remaining == max)717throw ioe;718break;719} finally {720unmap(bb);721}722}723long nwritten = max - remaining;724src.position(pos + nwritten);725return nwritten;726}727}728729private static final int TRANSFER_SIZE = 8192;730731private long transferFromArbitraryChannel(ReadableByteChannel src,732long position, long count)733throws IOException734{735// Untrusted target: Use a newly-erased buffer736int c = (int)Math.min(count, TRANSFER_SIZE);737ByteBuffer bb = ByteBuffer.allocate(c);738long tw = 0; // Total bytes written739long pos = position;740try {741while (tw < count) {742bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));743// ## Bug: Will block reading src if this channel744// ## is asynchronously closed745int nr = src.read(bb);746if (nr <= 0)747break;748bb.flip();749int nw = write(bb, pos);750tw += nw;751if (nw != nr)752break;753pos += nw;754bb.clear();755}756return tw;757} catch (IOException x) {758if (tw > 0)759return tw;760throw x;761}762}763764public long transferFrom(ReadableByteChannel src,765long position, long count)766throws IOException767{768ensureOpen();769if (!src.isOpen())770throw new ClosedChannelException();771if (!writable)772throw new NonWritableChannelException();773if ((position < 0) || (count < 0))774throw new IllegalArgumentException();775if (position > size())776return 0;777if (src instanceof FileChannelImpl)778return transferFromFileChannel((FileChannelImpl)src,779position, count);780781return transferFromArbitraryChannel(src, position, count);782}783784public int read(ByteBuffer dst, long position) throws IOException {785if (dst == null)786throw new NullPointerException();787if (position < 0)788throw new IllegalArgumentException("Negative position");789ensureOpen();790if (!readable)791throw new NonReadableChannelException();792if (direct)793Util.checkChannelPositionAligned(position, alignment);794if (nd.needsPositionLock()) {795synchronized (positionLock) {796return readInternal(dst, position);797}798} else {799return readInternal(dst, position);800}801}802803private int readInternal(ByteBuffer dst, long position) throws IOException {804assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);805int n = 0;806int ti = -1;807808try {809beginBlocking();810ti = threads.add();811if (!isOpen())812return -1;813do {814n = IOUtil.read(fd, dst, position, direct, alignment, nd);815} while ((n == IOStatus.INTERRUPTED) && isOpen());816return IOStatus.normalize(n);817} finally {818threads.remove(ti);819endBlocking(n > 0);820assert IOStatus.check(n);821}822}823824public int write(ByteBuffer src, long position) throws IOException {825if (src == null)826throw new NullPointerException();827if (position < 0)828throw new IllegalArgumentException("Negative position");829ensureOpen();830if (!writable)831throw new NonWritableChannelException();832if (direct)833Util.checkChannelPositionAligned(position, alignment);834if (nd.needsPositionLock()) {835synchronized (positionLock) {836return writeInternal(src, position);837}838} else {839return writeInternal(src, position);840}841}842843private int writeInternal(ByteBuffer src, long position) throws IOException {844assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);845int n = 0;846int ti = -1;847try {848beginBlocking();849ti = threads.add();850if (!isOpen())851return -1;852do {853n = IOUtil.write(fd, src, position, direct, alignment, nd);854} while ((n == IOStatus.INTERRUPTED) && isOpen());855return IOStatus.normalize(n);856} finally {857threads.remove(ti);858endBlocking(n > 0);859assert IOStatus.check(n);860}861}862863864// -- Memory-mapped buffers --865866private static abstract class Unmapper867implements Runnable, UnmapperProxy868{869// may be required to close file870private static final NativeDispatcher nd = new FileDispatcherImpl();871872private volatile long address;873protected final long size;874protected final long cap;875private final FileDescriptor fd;876private final int pagePosition;877878private Unmapper(long address, long size, long cap,879FileDescriptor fd, int pagePosition)880{881assert (address != 0);882this.address = address;883this.size = size;884this.cap = cap;885this.fd = fd;886this.pagePosition = pagePosition;887}888889@Override890public long address() {891return address + pagePosition;892}893894@Override895public FileDescriptor fileDescriptor() {896return fd;897}898899@Override900public void run() {901unmap();902}903904public void unmap() {905if (address == 0)906return;907unmap0(address, size);908address = 0;909910// if this mapping has a valid file descriptor then we close it911if (fd.valid()) {912try {913nd.close(fd);914} catch (IOException ignore) {915// nothing we can do916}917}918919decrementStats();920}921protected abstract void incrementStats();922protected abstract void decrementStats();923}924925private static class DefaultUnmapper extends Unmapper {926927// keep track of non-sync mapped buffer usage928static volatile int count;929static volatile long totalSize;930static volatile long totalCapacity;931932public DefaultUnmapper(long address, long size, long cap,933FileDescriptor fd, int pagePosition) {934super(address, size, cap, fd, pagePosition);935incrementStats();936}937938protected void incrementStats() {939synchronized (DefaultUnmapper.class) {940count++;941totalSize += size;942totalCapacity += cap;943}944}945protected void decrementStats() {946synchronized (DefaultUnmapper.class) {947count--;948totalSize -= size;949totalCapacity -= cap;950}951}952953public boolean isSync() {954return false;955}956}957958private static class SyncUnmapper extends Unmapper {959960// keep track of mapped buffer usage961static volatile int count;962static volatile long totalSize;963static volatile long totalCapacity;964965public SyncUnmapper(long address, long size, long cap,966FileDescriptor fd, int pagePosition) {967super(address, size, cap, fd, pagePosition);968incrementStats();969}970971protected void incrementStats() {972synchronized (SyncUnmapper.class) {973count++;974totalSize += size;975totalCapacity += cap;976}977}978protected void decrementStats() {979synchronized (SyncUnmapper.class) {980count--;981totalSize -= size;982totalCapacity -= cap;983}984}985986public boolean isSync() {987return true;988}989}990991private static void unmap(MappedByteBuffer bb) {992Cleaner cl = ((DirectBuffer)bb).cleaner();993if (cl != null)994cl.clean();995}996997private static final int MAP_INVALID = -1;998private static final int MAP_RO = 0;999private static final int MAP_RW = 1;1000private static final int MAP_PV = 2;10011002public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {1003if (size > Integer.MAX_VALUE)1004throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");1005boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));1006int prot = toProt(mode);1007Unmapper unmapper = mapInternal(mode, position, size, prot, isSync);1008if (unmapper == null) {1009// a valid file descriptor is not required1010FileDescriptor dummy = new FileDescriptor();1011if ((!writable) || (prot == MAP_RO))1012return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);1013else1014return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);1015} else if ((!writable) || (prot == MAP_RO)) {1016return Util.newMappedByteBufferR((int)unmapper.cap,1017unmapper.address + unmapper.pagePosition,1018unmapper.fd,1019unmapper, isSync);1020} else {1021return Util.newMappedByteBuffer((int)unmapper.cap,1022unmapper.address + unmapper.pagePosition,1023unmapper.fd,1024unmapper, isSync);1025}1026}10271028public Unmapper mapInternal(MapMode mode, long position, long size) throws IOException {1029boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));1030int prot = toProt(mode);1031return mapInternal(mode, position, size, prot, isSync);1032}10331034private Unmapper mapInternal(MapMode mode, long position, long size, int prot, boolean isSync)1035throws IOException1036{1037ensureOpen();1038if (mode == null)1039throw new NullPointerException("Mode is null");1040if (position < 0L)1041throw new IllegalArgumentException("Negative position");1042if (size < 0L)1043throw new IllegalArgumentException("Negative size");1044if (position + size < 0)1045throw new IllegalArgumentException("Position + size overflow");10461047checkMode(mode, prot, isSync);1048long addr = -1;1049int ti = -1;1050try {1051beginBlocking();1052ti = threads.add();1053if (!isOpen())1054return null;10551056long mapSize;1057int pagePosition;1058synchronized (positionLock) {1059long filesize;1060do {1061filesize = nd.size(fd);1062} while ((filesize == IOStatus.INTERRUPTED) && isOpen());1063if (!isOpen())1064return null;10651066if (filesize < position + size) { // Extend file size1067if (!writable) {1068throw new IOException("Channel not open for writing " +1069"- cannot extend file to required size");1070}1071int rv;1072do {1073rv = nd.truncate(fd, position + size);1074} while ((rv == IOStatus.INTERRUPTED) && isOpen());1075if (!isOpen())1076return null;1077}10781079if (size == 0) {1080return null;1081}10821083pagePosition = (int)(position % allocationGranularity);1084long mapPosition = position - pagePosition;1085mapSize = size + pagePosition;1086try {1087// If map0 did not throw an exception, the address is valid1088addr = map0(prot, mapPosition, mapSize, isSync);1089} catch (OutOfMemoryError x) {1090// An OutOfMemoryError may indicate that we've exhausted1091// memory so force gc and re-attempt map1092System.gc();1093try {1094Thread.sleep(100);1095} catch (InterruptedException y) {1096Thread.currentThread().interrupt();1097}1098try {1099addr = map0(prot, mapPosition, mapSize, isSync);1100} catch (OutOfMemoryError y) {1101// After a second OOME, fail1102throw new IOException("Map failed", y);1103}1104}1105} // synchronized11061107// On Windows, and potentially other platforms, we need an open1108// file descriptor for some mapping operations.1109FileDescriptor mfd;1110try {1111mfd = nd.duplicateForMapping(fd);1112} catch (IOException ioe) {1113unmap0(addr, mapSize);1114throw ioe;1115}11161117assert (IOStatus.checkAll(addr));1118assert (addr % allocationGranularity == 0);1119Unmapper um = (isSync1120? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition)1121: new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition));1122return um;1123} finally {1124threads.remove(ti);1125endBlocking(IOStatus.checkAll(addr));1126}1127}11281129private boolean isSync(MapMode mode) {1130// Do not want to initialize ExtendedMapMode until1131// after the module system has been initialized1132return !VM.isModuleSystemInited() ? false :1133(mode == ExtendedMapMode.READ_ONLY_SYNC ||1134mode == ExtendedMapMode.READ_WRITE_SYNC);1135}11361137private int toProt(MapMode mode) {1138int prot;1139if (mode == MapMode.READ_ONLY) {1140prot = MAP_RO;1141} else if (mode == MapMode.READ_WRITE) {1142prot = MAP_RW;1143} else if (mode == MapMode.PRIVATE) {1144prot = MAP_PV;1145} else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {1146prot = MAP_RO;1147} else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {1148prot = MAP_RW;1149} else {1150prot = MAP_INVALID;1151}1152return prot;1153}11541155private void checkMode(MapMode mode, int prot, boolean isSync) {1156if (prot == MAP_INVALID) {1157throw new UnsupportedOperationException();1158}1159if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)1160throw new NonWritableChannelException();1161if (!readable)1162throw new NonReadableChannelException();1163// reject SYNC request if writeback is not enabled for this platform1164if (isSync && !Unsafe.isWritebackEnabled()) {1165throw new UnsupportedOperationException();1166}1167}11681169/**1170* Invoked by sun.management.ManagementFactoryHelper to create the management1171* interface for mapped buffers.1172*/1173public static BufferPool getMappedBufferPool() {1174return new BufferPool() {1175@Override1176public String getName() {1177return "mapped";1178}1179@Override1180public long getCount() {1181return DefaultUnmapper.count;1182}1183@Override1184public long getTotalCapacity() {1185return DefaultUnmapper.totalCapacity;1186}1187@Override1188public long getMemoryUsed() {1189return DefaultUnmapper.totalSize;1190}1191};1192}11931194/**1195* Invoked by sun.management.ManagementFactoryHelper to create the management1196* interface for sync mapped buffers.1197*/1198public static BufferPool getSyncMappedBufferPool() {1199return new BufferPool() {1200@Override1201public String getName() {1202return "mapped - 'non-volatile memory'";1203}1204@Override1205public long getCount() {1206return SyncUnmapper.count;1207}1208@Override1209public long getTotalCapacity() {1210return SyncUnmapper.totalCapacity;1211}1212@Override1213public long getMemoryUsed() {1214return SyncUnmapper.totalSize;1215}1216};1217}12181219// -- Locks --12201221// keeps track of locks on this file1222private volatile FileLockTable fileLockTable;12231224private FileLockTable fileLockTable() throws IOException {1225if (fileLockTable == null) {1226synchronized (this) {1227if (fileLockTable == null) {1228int ti = threads.add();1229try {1230ensureOpen();1231fileLockTable = new FileLockTable(this, fd);1232} finally {1233threads.remove(ti);1234}1235}1236}1237}1238return fileLockTable;1239}12401241public FileLock lock(long position, long size, boolean shared)1242throws IOException1243{1244ensureOpen();1245if (shared && !readable)1246throw new NonReadableChannelException();1247if (!shared && !writable)1248throw new NonWritableChannelException();1249FileLockImpl fli = new FileLockImpl(this, position, size, shared);1250FileLockTable flt = fileLockTable();1251flt.add(fli);1252boolean completed = false;1253int ti = -1;1254try {1255beginBlocking();1256ti = threads.add();1257if (!isOpen())1258return null;1259int n;1260do {1261n = nd.lock(fd, true, position, size, shared);1262} while ((n == FileDispatcher.INTERRUPTED) && isOpen());1263if (isOpen()) {1264if (n == FileDispatcher.RET_EX_LOCK) {1265assert shared;1266FileLockImpl fli2 = new FileLockImpl(this, position, size,1267false);1268flt.replace(fli, fli2);1269fli = fli2;1270}1271completed = true;1272}1273} finally {1274if (!completed)1275flt.remove(fli);1276threads.remove(ti);1277try {1278endBlocking(completed);1279} catch (ClosedByInterruptException e) {1280throw new FileLockInterruptionException();1281}1282}1283return fli;1284}12851286public FileLock tryLock(long position, long size, boolean shared)1287throws IOException1288{1289ensureOpen();1290if (shared && !readable)1291throw new NonReadableChannelException();1292if (!shared && !writable)1293throw new NonWritableChannelException();1294FileLockImpl fli = new FileLockImpl(this, position, size, shared);1295FileLockTable flt = fileLockTable();1296flt.add(fli);1297int result;12981299int ti = threads.add();1300try {1301try {1302ensureOpen();1303result = nd.lock(fd, false, position, size, shared);1304} catch (IOException e) {1305flt.remove(fli);1306throw e;1307}1308if (result == FileDispatcher.NO_LOCK) {1309flt.remove(fli);1310return null;1311}1312if (result == FileDispatcher.RET_EX_LOCK) {1313assert shared;1314FileLockImpl fli2 = new FileLockImpl(this, position, size,1315false);1316flt.replace(fli, fli2);1317return fli2;1318}1319return fli;1320} finally {1321threads.remove(ti);1322}1323}13241325void release(FileLockImpl fli) throws IOException {1326int ti = threads.add();1327try {1328ensureOpen();1329nd.release(fd, fli.position(), fli.size());1330} finally {1331threads.remove(ti);1332}1333assert fileLockTable != null;1334fileLockTable.remove(fli);1335}13361337// -- Native methods --13381339// Creates a new mapping1340private native long map0(int prot, long position, long length, boolean isSync)1341throws IOException;13421343// Removes an existing mapping1344private static native int unmap0(long address, long length);13451346// Transfers from src to dst, or returns -2 if kernel can't do that1347private native long transferTo0(FileDescriptor src, long position,1348long count, FileDescriptor dst);13491350// Caches fieldIDs1351private static native long initIDs();13521353static {1354IOUtil.load();1355allocationGranularity = initIDs();1356}1357}135813591360