0N/A/*
3909N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.nio.ch;
0N/A
0N/Aimport java.io.FileDescriptor;
0N/Aimport java.io.IOException;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.MappedByteBuffer;
0N/Aimport java.nio.channels.*;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.List;
0N/Aimport java.security.AccessController;
0N/Aimport sun.misc.Cleaner;
5503N/Aimport sun.misc.IoTrace;
0N/Aimport sun.security.action.GetPropertyAction;
0N/A
0N/Apublic class FileChannelImpl
0N/A extends FileChannel
0N/A{
3200N/A // Memory allocation size for mapping buffers
3200N/A private static final long allocationGranularity;
0N/A
0N/A // Used to make native read and write calls
3200N/A private final FileDispatcher nd;
0N/A
0N/A // File descriptor
24N/A private final FileDescriptor fd;
0N/A
0N/A // File access mode (immutable)
24N/A private final boolean writable;
24N/A private final boolean readable;
3585N/A private final boolean append;
0N/A
0N/A // Required to prevent finalization of creating stream (immutable)
24N/A private final Object parent;
0N/A
5503N/A // The path of the referenced file (null if the parent stream is created with a file descriptor)
5503N/A private final String path;
5503N/A
0N/A // Thread-safe set of IDs of native threads, for signalling
24N/A private final NativeThreadSet threads = new NativeThreadSet(2);
0N/A
0N/A // Lock for operations involving position and size
24N/A private final Object positionLock = new Object();
0N/A
5503N/A private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
3200N/A boolean writable, boolean append, Object parent)
0N/A {
0N/A this.fd = fd;
0N/A this.readable = readable;
0N/A this.writable = writable;
3585N/A this.append = append;
0N/A this.parent = parent;
5503N/A this.path = path;
3200N/A this.nd = new FileDispatcherImpl(append);
0N/A }
0N/A
3200N/A // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
5503N/A public static FileChannel open(FileDescriptor fd, String path,
0N/A boolean readable, boolean writable,
0N/A Object parent)
0N/A {
5503N/A return new FileChannelImpl(fd, path, readable, writable, false, parent);
3200N/A }
3200N/A
3200N/A // Used by FileOutputStream.getChannel
5503N/A public static FileChannel open(FileDescriptor fd, String path,
3200N/A boolean readable, boolean writable,
3200N/A boolean append, Object parent)
3200N/A {
5503N/A return new FileChannelImpl(fd, path, readable, writable, append, parent);
0N/A }
0N/A
0N/A private void ensureOpen() throws IOException {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A }
0N/A
0N/A
0N/A // -- Standard channel operations --
0N/A
0N/A protected void implCloseChannel() throws IOException {
1109N/A // Release and invalidate any locks that we still hold
0N/A if (fileLockTable != null) {
1109N/A for (FileLock fl: fileLockTable.removeAll()) {
1109N/A synchronized (fl) {
1109N/A if (fl.isValid()) {
1109N/A nd.release(fd, fl.position(), fl.size());
1109N/A ((FileLockImpl)fl).invalidate();
1109N/A }
0N/A }
1109N/A }
0N/A }
0N/A
893N/A nd.preClose(fd);
893N/A threads.signalAndWait();
893N/A
0N/A if (parent != null) {
0N/A
0N/A // Close the fd via the parent stream's close method. The parent
0N/A // will reinvoke our close method, which is defined in the
0N/A // superclass AbstractInterruptibleChannel, but the isOpen logic in
0N/A // that method will prevent this method from being reinvoked.
0N/A //
24N/A ((java.io.Closeable)parent).close();
0N/A } else {
0N/A nd.close(fd);
0N/A }
0N/A
0N/A }
0N/A
0N/A public int read(ByteBuffer dst) throws IOException {
0N/A ensureOpen();
0N/A if (!readable)
0N/A throw new NonReadableChannelException();
0N/A synchronized (positionLock) {
0N/A int n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileReadBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return 0;
0N/A do {
6050N/A n = IOUtil.read(fd, dst, -1, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
5503N/A IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0);
0N/A end(n > 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long read(ByteBuffer[] dsts, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A ensureOpen();
0N/A if (!readable)
0N/A throw new NonReadableChannelException();
0N/A synchronized (positionLock) {
0N/A long n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileReadBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return 0;
0N/A do {
2655N/A n = IOUtil.read(fd, dsts, offset, length, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
5503N/A IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0);
0N/A end(n > 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public int write(ByteBuffer src) throws IOException {
0N/A ensureOpen();
0N/A if (!writable)
0N/A throw new NonWritableChannelException();
0N/A synchronized (positionLock) {
0N/A int n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileWriteBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return 0;
0N/A do {
6050N/A n = IOUtil.write(fd, src, -1, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(n > 0);
5503N/A IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long write(ByteBuffer[] srcs, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A ensureOpen();
0N/A if (!writable)
0N/A throw new NonWritableChannelException();
0N/A synchronized (positionLock) {
0N/A long n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileWriteBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return 0;
0N/A do {
2655N/A n = IOUtil.write(fd, srcs, offset, length, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
5503N/A IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0);
0N/A end(n > 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // -- Other operations --
0N/A
0N/A public long position() throws IOException {
0N/A ensureOpen();
0N/A synchronized (positionLock) {
0N/A long p = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return 0;
0N/A do {
3585N/A // in append-mode then position is advanced to end before writing
3585N/A p = (append) ? nd.size(fd) : position0(fd, -1);
0N/A } while ((p == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(p);
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(p > -1);
0N/A assert IOStatus.check(p);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public FileChannel position(long newPosition) throws IOException {
0N/A ensureOpen();
0N/A if (newPosition < 0)
0N/A throw new IllegalArgumentException();
0N/A synchronized (positionLock) {
0N/A long p = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return null;
0N/A do {
0N/A p = position0(fd, newPosition);
0N/A } while ((p == IOStatus.INTERRUPTED) && isOpen());
0N/A return this;
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(p > -1);
0N/A assert IOStatus.check(p);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public long size() throws IOException {
0N/A ensureOpen();
0N/A synchronized (positionLock) {
0N/A long s = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return -1;
0N/A do {
893N/A s = nd.size(fd);
0N/A } while ((s == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(s);
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(s > -1);
0N/A assert IOStatus.check(s);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public FileChannel truncate(long size) throws IOException {
0N/A ensureOpen();
0N/A if (size < 0)
0N/A throw new IllegalArgumentException();
0N/A if (size > size())
0N/A return this;
0N/A if (!writable)
0N/A throw new NonWritableChannelException();
0N/A synchronized (positionLock) {
0N/A int rv = -1;
0N/A long p = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return null;
0N/A
0N/A // get current position
0N/A do {
0N/A p = position0(fd, -1);
0N/A } while ((p == IOStatus.INTERRUPTED) && isOpen());
0N/A if (!isOpen())
0N/A return null;
0N/A assert p >= 0;
0N/A
0N/A // truncate file
0N/A do {
893N/A rv = nd.truncate(fd, size);
0N/A } while ((rv == IOStatus.INTERRUPTED) && isOpen());
0N/A if (!isOpen())
0N/A return null;
0N/A
0N/A // set position to size if greater than size
0N/A if (p > size)
0N/A p = size;
0N/A do {
0N/A rv = (int)position0(fd, p);
0N/A } while ((rv == IOStatus.INTERRUPTED) && isOpen());
0N/A return this;
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(rv > -1);
0N/A assert IOStatus.check(rv);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void force(boolean metaData) throws IOException {
0N/A ensureOpen();
0N/A int rv = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return;
0N/A do {
893N/A rv = nd.force(fd, metaData);
0N/A } while ((rv == IOStatus.INTERRUPTED) && isOpen());
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(rv > -1);
0N/A assert IOStatus.check(rv);
0N/A }
0N/A }
0N/A
0N/A // Assume at first that the underlying kernel supports sendfile();
0N/A // set this to false if we find out later that it doesn't
0N/A //
0N/A private static volatile boolean transferSupported = true;
0N/A
0N/A // Assume that the underlying kernel sendfile() will work if the target
0N/A // fd is a pipe; set this to false if we find out later that it doesn't
0N/A //
0N/A private static volatile boolean pipeSupported = true;
0N/A
0N/A // Assume that the underlying kernel sendfile() will work if the target
0N/A // fd is a file; set this to false if we find out later that it doesn't
0N/A //
0N/A private static volatile boolean fileSupported = true;
0N/A
0N/A private long transferToDirectly(long position, int icount,
0N/A WritableByteChannel target)
0N/A throws IOException
0N/A {
0N/A if (!transferSupported)
0N/A return IOStatus.UNSUPPORTED;
0N/A
0N/A FileDescriptor targetFD = null;
0N/A if (target instanceof FileChannelImpl) {
0N/A if (!fileSupported)
0N/A return IOStatus.UNSUPPORTED_CASE;
0N/A targetFD = ((FileChannelImpl)target).fd;
0N/A } else if (target instanceof SelChImpl) {
0N/A // Direct transfer to pipe causes EINVAL on some configurations
0N/A if ((target instanceof SinkChannelImpl) && !pipeSupported)
0N/A return IOStatus.UNSUPPORTED_CASE;
0N/A targetFD = ((SelChImpl)target).getFD();
0N/A }
0N/A if (targetFD == null)
0N/A return IOStatus.UNSUPPORTED;
0N/A int thisFDVal = IOUtil.fdVal(fd);
0N/A int targetFDVal = IOUtil.fdVal(targetFD);
0N/A if (thisFDVal == targetFDVal) // Not supported on some configurations
0N/A return IOStatus.UNSUPPORTED;
0N/A
0N/A long n = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return -1;
0N/A do {
0N/A n = transferTo0(thisFDVal, position, icount, targetFDVal);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A if (n == IOStatus.UNSUPPORTED_CASE) {
0N/A if (target instanceof SinkChannelImpl)
0N/A pipeSupported = false;
0N/A if (target instanceof FileChannelImpl)
0N/A fileSupported = false;
0N/A return IOStatus.UNSUPPORTED_CASE;
0N/A }
0N/A if (n == IOStatus.UNSUPPORTED) {
0N/A // Don't bother trying again
0N/A transferSupported = false;
0N/A return IOStatus.UNSUPPORTED;
0N/A }
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
0N/A end (n > -1);
0N/A }
0N/A }
0N/A
2673N/A // Maximum size to map when using a mapped buffer
2673N/A private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;
2673N/A
2673N/A private long transferToTrustedChannel(long position, long count,
0N/A WritableByteChannel target)
0N/A throws IOException
0N/A {
2673N/A boolean isSelChImpl = (target instanceof SelChImpl);
2673N/A if (!((target instanceof FileChannelImpl) || isSelChImpl))
0N/A return IOStatus.UNSUPPORTED;
0N/A
0N/A // Trusted target: Use a mapped buffer
2673N/A long remaining = count;
2673N/A while (remaining > 0L) {
2673N/A long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
2673N/A try {
2673N/A MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);
2673N/A try {
2673N/A // ## Bug: Closing this channel will not terminate the write
2673N/A int n = target.write(dbb);
2673N/A assert n >= 0;
2673N/A remaining -= n;
2673N/A if (isSelChImpl) {
2673N/A // one attempt to write to selectable channel
2673N/A break;
2673N/A }
2673N/A assert n > 0;
2673N/A position += n;
2673N/A } finally {
2673N/A unmap(dbb);
2673N/A }
3048N/A } catch (ClosedByInterruptException e) {
3048N/A // target closed by interrupt as ClosedByInterruptException needs
3048N/A // to be thrown after closing this channel.
3048N/A assert !target.isOpen();
3048N/A try {
3048N/A close();
3642N/A } catch (Throwable suppressed) {
3642N/A e.addSuppressed(suppressed);
3048N/A }
3048N/A throw e;
2673N/A } catch (IOException ioe) {
2673N/A // Only throw exception if no bytes have been written
2673N/A if (remaining == count)
2673N/A throw ioe;
2673N/A break;
2673N/A }
0N/A }
2673N/A return count - remaining;
0N/A }
0N/A
0N/A private long transferToArbitraryChannel(long position, int icount,
0N/A WritableByteChannel target)
0N/A throws IOException
0N/A {
0N/A // Untrusted target: Use a newly-erased buffer
0N/A int c = Math.min(icount, TRANSFER_SIZE);
0N/A ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
0N/A long tw = 0; // Total bytes written
0N/A long pos = position;
0N/A try {
0N/A Util.erase(bb);
0N/A while (tw < icount) {
0N/A bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE));
0N/A int nr = read(bb, pos);
0N/A if (nr <= 0)
0N/A break;
0N/A bb.flip();
0N/A // ## Bug: Will block writing target if this channel
0N/A // ## is asynchronously closed
0N/A int nw = target.write(bb);
0N/A tw += nw;
0N/A if (nw != nr)
0N/A break;
0N/A pos += nw;
0N/A bb.clear();
0N/A }
0N/A return tw;
0N/A } catch (IOException x) {
0N/A if (tw > 0)
0N/A return tw;
0N/A throw x;
0N/A } finally {
0N/A Util.releaseTemporaryDirectBuffer(bb);
0N/A }
0N/A }
0N/A
0N/A public long transferTo(long position, long count,
0N/A WritableByteChannel target)
0N/A throws IOException
0N/A {
0N/A ensureOpen();
0N/A if (!target.isOpen())
0N/A throw new ClosedChannelException();
0N/A if (!readable)
0N/A throw new NonReadableChannelException();
0N/A if (target instanceof FileChannelImpl &&
0N/A !((FileChannelImpl)target).writable)
0N/A throw new NonWritableChannelException();
0N/A if ((position < 0) || (count < 0))
0N/A throw new IllegalArgumentException();
0N/A long sz = size();
0N/A if (position > sz)
0N/A return 0;
0N/A int icount = (int)Math.min(count, Integer.MAX_VALUE);
0N/A if ((sz - position) < icount)
0N/A icount = (int)(sz - position);
0N/A
0N/A long n;
0N/A
0N/A // Attempt a direct transfer, if the kernel supports it
0N/A if ((n = transferToDirectly(position, icount, target)) >= 0)
0N/A return n;
0N/A
0N/A // Attempt a mapped transfer, but only to trusted channel types
0N/A if ((n = transferToTrustedChannel(position, icount, target)) >= 0)
0N/A return n;
0N/A
0N/A // Slow path for untrusted targets
0N/A return transferToArbitraryChannel(position, icount, target);
0N/A }
0N/A
0N/A private long transferFromFileChannel(FileChannelImpl src,
0N/A long position, long count)
0N/A throws IOException
0N/A {
2756N/A if (!src.readable)
2756N/A throw new NonReadableChannelException();
0N/A synchronized (src.positionLock) {
2673N/A long pos = src.position();
2673N/A long max = Math.min(count, src.size() - pos);
2673N/A
2673N/A long remaining = max;
2673N/A long p = pos;
2673N/A while (remaining > 0L) {
2673N/A long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
2673N/A // ## Bug: Closing this channel will not terminate the write
2673N/A MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
2673N/A try {
2673N/A long n = write(bb, position);
2673N/A assert n > 0;
2673N/A p += n;
2673N/A position += n;
2673N/A remaining -= n;
2673N/A } catch (IOException ioe) {
2673N/A // Only throw exception if no bytes have been written
2673N/A if (remaining == max)
2673N/A throw ioe;
2673N/A break;
2673N/A } finally {
2673N/A unmap(bb);
2673N/A }
0N/A }
2673N/A long nwritten = max - remaining;
2673N/A src.position(pos + nwritten);
2673N/A return nwritten;
0N/A }
0N/A }
0N/A
0N/A private static final int TRANSFER_SIZE = 8192;
0N/A
0N/A private long transferFromArbitraryChannel(ReadableByteChannel src,
0N/A long position, long count)
0N/A throws IOException
0N/A {
0N/A // Untrusted target: Use a newly-erased buffer
0N/A int c = (int)Math.min(count, TRANSFER_SIZE);
0N/A ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
0N/A long tw = 0; // Total bytes written
0N/A long pos = position;
0N/A try {
0N/A Util.erase(bb);
0N/A while (tw < count) {
0N/A bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));
0N/A // ## Bug: Will block reading src if this channel
0N/A // ## is asynchronously closed
0N/A int nr = src.read(bb);
0N/A if (nr <= 0)
0N/A break;
0N/A bb.flip();
0N/A int nw = write(bb, pos);
0N/A tw += nw;
0N/A if (nw != nr)
0N/A break;
0N/A pos += nw;
0N/A bb.clear();
0N/A }
0N/A return tw;
0N/A } catch (IOException x) {
0N/A if (tw > 0)
0N/A return tw;
0N/A throw x;
0N/A } finally {
0N/A Util.releaseTemporaryDirectBuffer(bb);
0N/A }
0N/A }
0N/A
0N/A public long transferFrom(ReadableByteChannel src,
0N/A long position, long count)
0N/A throws IOException
0N/A {
0N/A ensureOpen();
0N/A if (!src.isOpen())
0N/A throw new ClosedChannelException();
0N/A if (!writable)
0N/A throw new NonWritableChannelException();
0N/A if ((position < 0) || (count < 0))
0N/A throw new IllegalArgumentException();
0N/A if (position > size())
0N/A return 0;
0N/A if (src instanceof FileChannelImpl)
0N/A return transferFromFileChannel((FileChannelImpl)src,
0N/A position, count);
0N/A
0N/A return transferFromArbitraryChannel(src, position, count);
0N/A }
0N/A
0N/A public int read(ByteBuffer dst, long position) throws IOException {
0N/A if (dst == null)
0N/A throw new NullPointerException();
0N/A if (position < 0)
0N/A throw new IllegalArgumentException("Negative position");
0N/A if (!readable)
0N/A throw new NonReadableChannelException();
0N/A ensureOpen();
6050N/A if (nd.needsPositionLock()) {
6050N/A synchronized (positionLock) {
6050N/A return readInternal(dst, position);
6050N/A }
6050N/A } else {
6050N/A return readInternal(dst, position);
6050N/A }
6050N/A }
6050N/A
6050N/A private int readInternal(ByteBuffer dst, long position) throws IOException {
6050N/A assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
0N/A int n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileReadBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return -1;
0N/A do {
6050N/A n = IOUtil.read(fd, dst, position, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
5503N/A IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0);
0N/A end(n > 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A
0N/A public int write(ByteBuffer src, long position) throws IOException {
0N/A if (src == null)
0N/A throw new NullPointerException();
0N/A if (position < 0)
0N/A throw new IllegalArgumentException("Negative position");
0N/A if (!writable)
0N/A throw new NonWritableChannelException();
0N/A ensureOpen();
6050N/A if (nd.needsPositionLock()) {
6050N/A synchronized (positionLock) {
6050N/A return writeInternal(src, position);
6050N/A }
6050N/A } else {
6050N/A return writeInternal(src, position);
6050N/A }
6050N/A }
6050N/A
6050N/A private int writeInternal(ByteBuffer src, long position) throws IOException {
6050N/A assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
0N/A int n = 0;
1035N/A int ti = -1;
5503N/A Object traceContext = IoTrace.fileWriteBegin(path);
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return -1;
0N/A do {
6050N/A n = IOUtil.write(fd, src, position, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(n > 0);
5503N/A IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0);
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A
0N/A
0N/A // -- Memory-mapped buffers --
0N/A
0N/A private static class Unmapper
0N/A implements Runnable
0N/A {
3200N/A // may be required to close file
3200N/A private static final NativeDispatcher nd = new FileDispatcherImpl();
3200N/A
515N/A // keep track of mapped buffer usage
515N/A static volatile int count;
515N/A static volatile long totalSize;
515N/A static volatile long totalCapacity;
0N/A
2984N/A private volatile long address;
2984N/A private final long size;
2984N/A private final int cap;
2984N/A private final FileDescriptor fd;
0N/A
2984N/A private Unmapper(long address, long size, int cap,
2984N/A FileDescriptor fd)
2984N/A {
0N/A assert (address != 0);
0N/A this.address = address;
0N/A this.size = size;
515N/A this.cap = cap;
2984N/A this.fd = fd;
515N/A
515N/A synchronized (Unmapper.class) {
515N/A count++;
515N/A totalSize += size;
515N/A totalCapacity += cap;
515N/A }
0N/A }
0N/A
0N/A public void run() {
0N/A if (address == 0)
0N/A return;
0N/A unmap0(address, size);
0N/A address = 0;
515N/A
2984N/A // if this mapping has a valid file descriptor then we close it
2984N/A if (fd.valid()) {
2984N/A try {
2984N/A nd.close(fd);
2984N/A } catch (IOException ignore) {
2984N/A // nothing we can do
2984N/A }
2984N/A }
2984N/A
515N/A synchronized (Unmapper.class) {
515N/A count--;
515N/A totalSize -= size;
515N/A totalCapacity -= cap;
515N/A }
0N/A }
0N/A }
0N/A
0N/A private static void unmap(MappedByteBuffer bb) {
0N/A Cleaner cl = ((DirectBuffer)bb).cleaner();
0N/A if (cl != null)
0N/A cl.clean();
0N/A }
0N/A
0N/A private static final int MAP_RO = 0;
0N/A private static final int MAP_RW = 1;
0N/A private static final int MAP_PV = 2;
0N/A
0N/A public MappedByteBuffer map(MapMode mode, long position, long size)
0N/A throws IOException
0N/A {
0N/A ensureOpen();
0N/A if (position < 0L)
0N/A throw new IllegalArgumentException("Negative position");
0N/A if (size < 0L)
0N/A throw new IllegalArgumentException("Negative size");
0N/A if (position + size < 0)
0N/A throw new IllegalArgumentException("Position + size overflow");
0N/A if (size > Integer.MAX_VALUE)
0N/A throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
0N/A int imode = -1;
0N/A if (mode == MapMode.READ_ONLY)
0N/A imode = MAP_RO;
0N/A else if (mode == MapMode.READ_WRITE)
0N/A imode = MAP_RW;
0N/A else if (mode == MapMode.PRIVATE)
0N/A imode = MAP_PV;
0N/A assert (imode >= 0);
0N/A if ((mode != MapMode.READ_ONLY) && !writable)
0N/A throw new NonWritableChannelException();
0N/A if (!readable)
0N/A throw new NonReadableChannelException();
0N/A
0N/A long addr = -1;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return null;
0N/A if (size() < position + size) { // Extend file size
0N/A if (!writable) {
0N/A throw new IOException("Channel not open for writing " +
0N/A "- cannot extend file to required size");
0N/A }
0N/A int rv;
0N/A do {
893N/A rv = nd.truncate(fd, position + size);
0N/A } while ((rv == IOStatus.INTERRUPTED) && isOpen());
0N/A }
0N/A if (size == 0) {
0N/A addr = 0;
2984N/A // a valid file descriptor is not required
2984N/A FileDescriptor dummy = new FileDescriptor();
0N/A if ((!writable) || (imode == MAP_RO))
2984N/A return Util.newMappedByteBufferR(0, 0, dummy, null);
0N/A else
2984N/A return Util.newMappedByteBuffer(0, 0, dummy, null);
0N/A }
0N/A
0N/A int pagePosition = (int)(position % allocationGranularity);
0N/A long mapPosition = position - pagePosition;
0N/A long mapSize = size + pagePosition;
0N/A try {
0N/A // If no exception was thrown from map0, the address is valid
0N/A addr = map0(imode, mapPosition, mapSize);
0N/A } catch (OutOfMemoryError x) {
0N/A // An OutOfMemoryError may indicate that we've exhausted memory
0N/A // so force gc and re-attempt map
0N/A System.gc();
0N/A try {
0N/A Thread.sleep(100);
0N/A } catch (InterruptedException y) {
0N/A Thread.currentThread().interrupt();
0N/A }
0N/A try {
0N/A addr = map0(imode, mapPosition, mapSize);
0N/A } catch (OutOfMemoryError y) {
0N/A // After a second OOME, fail
0N/A throw new IOException("Map failed", y);
0N/A }
0N/A }
0N/A
2984N/A // On Windows, and potentially other platforms, we need an open
2984N/A // file descriptor for some mapping operations.
2984N/A FileDescriptor mfd;
2984N/A try {
2984N/A mfd = nd.duplicateForMapping(fd);
2984N/A } catch (IOException ioe) {
2984N/A unmap0(addr, mapSize);
2984N/A throw ioe;
2984N/A }
2984N/A
0N/A assert (IOStatus.checkAll(addr));
0N/A assert (addr % allocationGranularity == 0);
0N/A int isize = (int)size;
2984N/A Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
2984N/A if ((!writable) || (imode == MAP_RO)) {
2984N/A return Util.newMappedByteBufferR(isize,
2984N/A addr + pagePosition,
2984N/A mfd,
2984N/A um);
2984N/A } else {
2984N/A return Util.newMappedByteBuffer(isize,
2984N/A addr + pagePosition,
2984N/A mfd,
2984N/A um);
2984N/A }
0N/A } finally {
0N/A threads.remove(ti);
0N/A end(IOStatus.checkAll(addr));
0N/A }
0N/A }
0N/A
515N/A /**
1320N/A * Invoked by sun.management.ManagementFactoryHelper to create the management
1320N/A * interface for mapped buffers.
515N/A */
1320N/A public static sun.misc.JavaNioAccess.BufferPool getMappedBufferPool() {
1320N/A return new sun.misc.JavaNioAccess.BufferPool() {
1320N/A @Override
1320N/A public String getName() {
1320N/A return "mapped";
515N/A }
1320N/A @Override
1320N/A public long getCount() {
1320N/A return Unmapper.count;
1320N/A }
1320N/A @Override
1320N/A public long getTotalCapacity() {
1320N/A return Unmapper.totalCapacity;
1320N/A }
1320N/A @Override
1320N/A public long getMemoryUsed() {
1320N/A return Unmapper.totalSize;
1320N/A }
1320N/A };
515N/A }
0N/A
0N/A // -- Locks --
0N/A
893N/A
0N/A
0N/A // keeps track of locks on this file
0N/A private volatile FileLockTable fileLockTable;
0N/A
0N/A // indicates if file locks are maintained system-wide (as per spec)
0N/A private static boolean isSharedFileLockTable;
0N/A
0N/A // indicates if the disableSystemWideOverlappingFileLockCheck property
0N/A // has been checked
0N/A private static volatile boolean propertyChecked;
0N/A
0N/A // The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so
0N/A // the overlap check wasn't system wide when there were multiple channels to
0N/A // the same file. This property is used to get 1.4/5.0 behavior if desired.
0N/A private static boolean isSharedFileLockTable() {
0N/A if (!propertyChecked) {
0N/A synchronized (FileChannelImpl.class) {
0N/A if (!propertyChecked) {
0N/A String value = AccessController.doPrivileged(
0N/A new GetPropertyAction(
0N/A "sun.nio.ch.disableSystemWideOverlappingFileLockCheck"));
0N/A isSharedFileLockTable = ((value == null) || value.equals("false"));
0N/A propertyChecked = true;
0N/A }
0N/A }
0N/A }
0N/A return isSharedFileLockTable;
0N/A }
0N/A
893N/A private FileLockTable fileLockTable() throws IOException {
0N/A if (fileLockTable == null) {
0N/A synchronized (this) {
0N/A if (fileLockTable == null) {
893N/A if (isSharedFileLockTable()) {
893N/A int ti = threads.add();
893N/A try {
893N/A ensureOpen();
893N/A fileLockTable = FileLockTable.newSharedFileLockTable(this, fd);
893N/A } finally {
893N/A threads.remove(ti);
893N/A }
893N/A } else {
893N/A fileLockTable = new SimpleFileLockTable();
893N/A }
0N/A }
0N/A }
0N/A }
0N/A return fileLockTable;
0N/A }
0N/A
0N/A public FileLock lock(long position, long size, boolean shared)
0N/A throws IOException
0N/A {
0N/A ensureOpen();
0N/A if (shared && !readable)
0N/A throw new NonReadableChannelException();
0N/A if (!shared && !writable)
0N/A throw new NonWritableChannelException();
0N/A FileLockImpl fli = new FileLockImpl(this, position, size, shared);
0N/A FileLockTable flt = fileLockTable();
0N/A flt.add(fli);
1109N/A boolean completed = false;
1035N/A int ti = -1;
0N/A try {
0N/A begin();
1035N/A ti = threads.add();
0N/A if (!isOpen())
0N/A return null;
1109N/A int n;
1109N/A do {
1109N/A n = nd.lock(fd, true, position, size, shared);
1109N/A } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
1109N/A if (isOpen()) {
1109N/A if (n == FileDispatcher.RET_EX_LOCK) {
1109N/A assert shared;
1109N/A FileLockImpl fli2 = new FileLockImpl(this, position, size,
1109N/A false);
1109N/A flt.replace(fli, fli2);
1109N/A fli = fli2;
1109N/A }
1109N/A completed = true;
0N/A }
1109N/A } finally {
1109N/A if (!completed)
0N/A flt.remove(fli);
0N/A threads.remove(ti);
0N/A try {
1109N/A end(completed);
0N/A } catch (ClosedByInterruptException e) {
0N/A throw new FileLockInterruptionException();
0N/A }
0N/A }
0N/A return fli;
0N/A }
0N/A
0N/A public FileLock tryLock(long position, long size, boolean shared)
0N/A throws IOException
0N/A {
0N/A ensureOpen();
0N/A if (shared && !readable)
0N/A throw new NonReadableChannelException();
0N/A if (!shared && !writable)
0N/A throw new NonWritableChannelException();
0N/A FileLockImpl fli = new FileLockImpl(this, position, size, shared);
0N/A FileLockTable flt = fileLockTable();
0N/A flt.add(fli);
893N/A int result;
893N/A
893N/A int ti = threads.add();
893N/A try {
893N/A try {
893N/A ensureOpen();
893N/A result = nd.lock(fd, false, position, size, shared);
893N/A } catch (IOException e) {
893N/A flt.remove(fli);
893N/A throw e;
893N/A }
893N/A if (result == FileDispatcher.NO_LOCK) {
893N/A flt.remove(fli);
893N/A return null;
893N/A }
893N/A if (result == FileDispatcher.RET_EX_LOCK) {
893N/A assert shared;
893N/A FileLockImpl fli2 = new FileLockImpl(this, position, size,
893N/A false);
893N/A flt.replace(fli, fli2);
893N/A return fli2;
893N/A }
893N/A return fli;
893N/A } finally {
893N/A threads.remove(ti);
0N/A }
0N/A }
0N/A
0N/A void release(FileLockImpl fli) throws IOException {
893N/A int ti = threads.add();
893N/A try {
893N/A ensureOpen();
893N/A nd.release(fd, fli.position(), fli.size());
893N/A } finally {
893N/A threads.remove(ti);
893N/A }
0N/A assert fileLockTable != null;
0N/A fileLockTable.remove(fli);
0N/A }
0N/A
893N/A // -- File lock support --
0N/A
0N/A /**
0N/A * A simple file lock table that maintains a list of FileLocks obtained by a
0N/A * FileChannel. Use to get 1.4/5.0 behaviour.
0N/A */
893N/A private static class SimpleFileLockTable extends FileLockTable {
0N/A // synchronize on list for access
1109N/A private final List<FileLock> lockList = new ArrayList<FileLock>(2);
0N/A
0N/A public SimpleFileLockTable() {
0N/A }
0N/A
0N/A private void checkList(long position, long size)
0N/A throws OverlappingFileLockException
0N/A {
0N/A assert Thread.holdsLock(lockList);
0N/A for (FileLock fl: lockList) {
0N/A if (fl.overlaps(position, size)) {
0N/A throw new OverlappingFileLockException();
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void add(FileLock fl) throws OverlappingFileLockException {
0N/A synchronized (lockList) {
0N/A checkList(fl.position(), fl.size());
0N/A lockList.add(fl);
0N/A }
0N/A }
0N/A
0N/A public void remove(FileLock fl) {
0N/A synchronized (lockList) {
0N/A lockList.remove(fl);
0N/A }
0N/A }
0N/A
1109N/A public List<FileLock> removeAll() {
0N/A synchronized(lockList) {
1109N/A List<FileLock> result = new ArrayList<FileLock>(lockList);
1109N/A lockList.clear();
1109N/A return result;
0N/A }
0N/A }
0N/A
0N/A public void replace(FileLock fl1, FileLock fl2) {
0N/A synchronized (lockList) {
0N/A lockList.remove(fl1);
0N/A lockList.add(fl2);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // -- Native methods --
0N/A
0N/A // Creates a new mapping
0N/A private native long map0(int prot, long position, long length)
0N/A throws IOException;
0N/A
0N/A // Removes an existing mapping
0N/A private static native int unmap0(long address, long length);
0N/A
0N/A // Transfers from src to dst, or returns -2 if kernel can't do that
0N/A private native long transferTo0(int src, long position, long count, int dst);
0N/A
0N/A // Sets or reports this file's position
0N/A // If offset is -1, the current position is returned
0N/A // otherwise the position is set to offset
0N/A private native long position0(FileDescriptor fd, long offset);
0N/A
0N/A // Caches fieldIDs
0N/A private static native long initIDs();
0N/A
0N/A static {
0N/A Util.load();
0N/A allocationGranularity = initIDs();
0N/A }
0N/A
0N/A}