1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.UncheckedIOException; 31 import java.lang.ref.Cleaner.Cleanable; 32 import java.nio.ByteBuffer; 33 import java.nio.MappedByteBuffer; 34 import java.nio.channels.AsynchronousCloseException; 35 import java.nio.channels.ClosedByInterruptException; 36 import java.nio.channels.ClosedChannelException; 37 import java.nio.channels.FileChannel; 38 import java.nio.channels.FileLock; 39 import java.nio.channels.FileLockInterruptionException; 40 import java.nio.channels.NonReadableChannelException; 41 import java.nio.channels.NonWritableChannelException; 42 import java.nio.channels.ReadableByteChannel; 43 import java.nio.channels.SelectableChannel; 44 import java.nio.channels.WritableByteChannel; 45 46 import jdk.internal.misc.JavaIOFileDescriptorAccess; 47 import jdk.internal.misc.JavaNioAccess; 48 import jdk.internal.misc.SharedSecrets; 49 import jdk.internal.ref.Cleaner; 50 import jdk.internal.ref.CleanerFactory; 51 52 public class FileChannelImpl 53 extends FileChannel 54 { 55 // Memory allocation size for mapping buffers 56 private static final long allocationGranularity; 57 58 // Access to FileDescriptor internals 59 private static final JavaIOFileDescriptorAccess fdAccess = 60 SharedSecrets.getJavaIOFileDescriptorAccess(); 61 62 // Used to make native read and write calls 63 private final FileDispatcher nd; 64 65 // File descriptor 66 private final FileDescriptor fd; 67 68 // File access mode (immutable) 69 private final boolean writable; 70 private final boolean readable; 71 72 // Required to prevent finalization of creating stream (immutable) 73 private final Object parent; 74 75 // The path of the referenced file 76 // (null if the parent stream is created with a file descriptor) 77 private final String path; 78 79 // Thread-safe set of IDs of native threads, for signalling 80 private final NativeThreadSet threads = new NativeThreadSet(2); 81 82 // Lock for operations involving position and size 83 private final Object positionLock = new Object(); 84 85 // blocking operations are not interruptible 86 private volatile boolean uninterruptible; 87 88 // DirectIO flag 89 private final boolean direct; 90 91 // IO alignment value for DirectIO 92 private final int alignment; 93 94 // Cleanable with an action which closes this channel's file descriptor 95 private final Cleanable closer; 96 97 private static class Closer implements Runnable { 98 private final FileDescriptor fd; 99 100 Closer(FileDescriptor fd) { 101 this.fd = fd; 102 } 103 104 public void run() { 105 try { 106 fdAccess.close(fd); 107 } catch (IOException ioe) { 108 // Rethrow as unchecked so the exception can be propagated as needed 109 throw new UncheckedIOException("close", ioe); 110 } 111 } 112 } 113 114 private FileChannelImpl(FileDescriptor fd, String path, boolean readable, 115 boolean writable, boolean direct, Object parent) 116 { 117 this.fd = fd; 118 this.readable = readable; 119 this.writable = writable; 120 this.parent = parent; 121 this.path = path; 122 this.direct = direct; 123 this.nd = new FileDispatcherImpl(); 124 if (direct) { 125 assert path != null; 126 this.alignment = nd.setDirectIO(fd, path); 127 } else { 128 this.alignment = -1; 129 } 130 131 // Register a cleaning action if and only if there is no parent 132 // as the parent will take care of closing the file descriptor. 133 // FileChannel is used by the LambdaMetaFactory so a lambda cannot 134 // be used here hence we use a nested class instead. 135 this.closer = parent != null ? null : 136 CleanerFactory.cleaner().register(this, new Closer(fd)); 137 } 138 139 // Used by FileInputStream.getChannel(), FileOutputStream.getChannel 140 // and RandomAccessFile.getChannel() 141 public static FileChannel open(FileDescriptor fd, String path, 142 boolean readable, boolean writable, 143 boolean direct, Object parent) 144 { 145 return new FileChannelImpl(fd, path, readable, writable, direct, parent); 146 } 147 148 private void ensureOpen() throws IOException { 149 if (!isOpen()) 150 throw new ClosedChannelException(); 151 } 152 153 public void setUninterruptible() { 154 uninterruptible = true; 155 } 156 157 private void beginBlocking() { 158 if (!uninterruptible) begin(); 159 } 160 161 private void endBlocking(boolean completed) throws AsynchronousCloseException { 162 if (!uninterruptible) end(completed); 163 } 164 165 // -- Standard channel operations -- 166 167 protected void implCloseChannel() throws IOException { 168 if (!fd.valid()) 169 return; // nothing to do 170 171 // Release and invalidate any locks that we still hold 172 if (fileLockTable != null) { 173 for (FileLock fl: fileLockTable.removeAll()) { 174 synchronized (fl) { 175 if (fl.isValid()) { 176 nd.release(fd, fl.position(), fl.size()); 177 ((FileLockImpl)fl).invalidate(); 178 } 179 } 180 } 181 } 182 183 // signal any threads blocked on this channel 184 threads.signalAndWait(); 185 186 if (parent != null) { 187 188 // Close the fd via the parent stream's close method. The parent 189 // will reinvoke our close method, which is defined in the 190 // superclass AbstractInterruptibleChannel, but the isOpen logic in 191 // that method will prevent this method from being reinvoked. 192 // 193 ((java.io.Closeable)parent).close(); 194 } else if (closer != null) { 195 // Perform the cleaning action so it is not redone when 196 // this channel becomes phantom reachable. 197 try { 198 closer.clean(); 199 } catch (UncheckedIOException uioe) { 200 throw uioe.getCause(); 201 } 202 } else { 203 fdAccess.close(fd); 204 } 205 206 } 207 208 public int read(ByteBuffer dst) throws IOException { 209 ensureOpen(); 210 if (!readable) 211 throw new NonReadableChannelException(); 212 synchronized (positionLock) { 213 if (direct) 214 Util.checkChannelPositionAligned(position(), alignment); 215 int n = 0; 216 int ti = -1; 217 try { 218 beginBlocking(); 219 ti = threads.add(); 220 if (!isOpen()) 221 return 0; 222 do { 223 n = IOUtil.read(fd, dst, -1, direct, alignment, nd); 224 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 225 return IOStatus.normalize(n); 226 } finally { 227 threads.remove(ti); 228 endBlocking(n > 0); 229 assert IOStatus.check(n); 230 } 231 } 232 } 233 234 public long read(ByteBuffer[] dsts, int offset, int length) 235 throws IOException 236 { 237 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 238 throw new IndexOutOfBoundsException(); 239 ensureOpen(); 240 if (!readable) 241 throw new NonReadableChannelException(); 242 synchronized (positionLock) { 243 if (direct) 244 Util.checkChannelPositionAligned(position(), alignment); 245 long n = 0; 246 int ti = -1; 247 try { 248 beginBlocking(); 249 ti = threads.add(); 250 if (!isOpen()) 251 return 0; 252 do { 253 n = IOUtil.read(fd, dsts, offset, length, 254 direct, alignment, nd); 255 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 256 return IOStatus.normalize(n); 257 } finally { 258 threads.remove(ti); 259 endBlocking(n > 0); 260 assert IOStatus.check(n); 261 } 262 } 263 } 264 265 public int write(ByteBuffer src) throws IOException { 266 ensureOpen(); 267 if (!writable) 268 throw new NonWritableChannelException(); 269 synchronized (positionLock) { 270 if (direct) 271 Util.checkChannelPositionAligned(position(), alignment); 272 int n = 0; 273 int ti = -1; 274 try { 275 beginBlocking(); 276 ti = threads.add(); 277 if (!isOpen()) 278 return 0; 279 do { 280 n = IOUtil.write(fd, src, -1, direct, alignment, nd); 281 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 282 return IOStatus.normalize(n); 283 } finally { 284 threads.remove(ti); 285 endBlocking(n > 0); 286 assert IOStatus.check(n); 287 } 288 } 289 } 290 291 public long write(ByteBuffer[] srcs, int offset, int length) 292 throws IOException 293 { 294 if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) 295 throw new IndexOutOfBoundsException(); 296 ensureOpen(); 297 if (!writable) 298 throw new NonWritableChannelException(); 299 synchronized (positionLock) { 300 if (direct) 301 Util.checkChannelPositionAligned(position(), alignment); 302 long n = 0; 303 int ti = -1; 304 try { 305 beginBlocking(); 306 ti = threads.add(); 307 if (!isOpen()) 308 return 0; 309 do { 310 n = IOUtil.write(fd, srcs, offset, length, 311 direct, alignment, nd); 312 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 313 return IOStatus.normalize(n); 314 } finally { 315 threads.remove(ti); 316 endBlocking(n > 0); 317 assert IOStatus.check(n); 318 } 319 } 320 } 321 322 // -- Other operations -- 323 324 public long position() throws IOException { 325 ensureOpen(); 326 synchronized (positionLock) { 327 long p = -1; 328 int ti = -1; 329 try { 330 beginBlocking(); 331 ti = threads.add(); 332 if (!isOpen()) 333 return 0; 334 boolean append = fdAccess.getAppend(fd); 335 do { 336 // in append-mode then position is advanced to end before writing 337 p = (append) ? nd.size(fd) : nd.seek(fd, -1); 338 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 339 return IOStatus.normalize(p); 340 } finally { 341 threads.remove(ti); 342 endBlocking(p > -1); 343 assert IOStatus.check(p); 344 } 345 } 346 } 347 348 public FileChannel position(long newPosition) throws IOException { 349 ensureOpen(); 350 if (newPosition < 0) 351 throw new IllegalArgumentException(); 352 synchronized (positionLock) { 353 long p = -1; 354 int ti = -1; 355 try { 356 beginBlocking(); 357 ti = threads.add(); 358 if (!isOpen()) 359 return null; 360 do { 361 p = nd.seek(fd, newPosition); 362 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 363 return this; 364 } finally { 365 threads.remove(ti); 366 endBlocking(p > -1); 367 assert IOStatus.check(p); 368 } 369 } 370 } 371 372 public long size() throws IOException { 373 ensureOpen(); 374 synchronized (positionLock) { 375 long s = -1; 376 int ti = -1; 377 try { 378 beginBlocking(); 379 ti = threads.add(); 380 if (!isOpen()) 381 return -1; 382 do { 383 s = nd.size(fd); 384 } while ((s == IOStatus.INTERRUPTED) && isOpen()); 385 return IOStatus.normalize(s); 386 } finally { 387 threads.remove(ti); 388 endBlocking(s > -1); 389 assert IOStatus.check(s); 390 } 391 } 392 } 393 394 public FileChannel truncate(long newSize) throws IOException { 395 ensureOpen(); 396 if (newSize < 0) 397 throw new IllegalArgumentException("Negative size"); 398 if (!writable) 399 throw new NonWritableChannelException(); 400 synchronized (positionLock) { 401 int rv = -1; 402 long p = -1; 403 int ti = -1; 404 long rp = -1; 405 try { 406 beginBlocking(); 407 ti = threads.add(); 408 if (!isOpen()) 409 return null; 410 411 // get current size 412 long size; 413 do { 414 size = nd.size(fd); 415 } while ((size == IOStatus.INTERRUPTED) && isOpen()); 416 if (!isOpen()) 417 return null; 418 419 // get current position 420 do { 421 p = nd.seek(fd, -1); 422 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 423 if (!isOpen()) 424 return null; 425 assert p >= 0; 426 427 // truncate file if given size is less than the current size 428 if (newSize < size) { 429 do { 430 rv = nd.truncate(fd, newSize); 431 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 432 if (!isOpen()) 433 return null; 434 } 435 436 // if position is beyond new size then adjust it 437 if (p > newSize) 438 p = newSize; 439 do { 440 rp = nd.seek(fd, p); 441 } while ((rp == IOStatus.INTERRUPTED) && isOpen()); 442 return this; 443 } finally { 444 threads.remove(ti); 445 endBlocking(rv > -1); 446 assert IOStatus.check(rv); 447 } 448 } 449 } 450 451 public void force(boolean metaData) throws IOException { 452 ensureOpen(); 453 int rv = -1; 454 int ti = -1; 455 try { 456 beginBlocking(); 457 ti = threads.add(); 458 if (!isOpen()) 459 return; 460 do { 461 rv = nd.force(fd, metaData); 462 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 463 } finally { 464 threads.remove(ti); 465 endBlocking(rv > -1); 466 assert IOStatus.check(rv); 467 } 468 } 469 470 // Assume at first that the underlying kernel supports sendfile(); 471 // set this to false if we find out later that it doesn't 472 // 473 private static volatile boolean transferSupported = true; 474 475 // Assume that the underlying kernel sendfile() will work if the target 476 // fd is a pipe; set this to false if we find out later that it doesn't 477 // 478 private static volatile boolean pipeSupported = true; 479 480 // Assume that the underlying kernel sendfile() will work if the target 481 // fd is a file; set this to false if we find out later that it doesn't 482 // 483 private static volatile boolean fileSupported = true; 484 485 private long transferToDirectlyInternal(long position, int icount, 486 WritableByteChannel target, 487 FileDescriptor targetFD) 488 throws IOException 489 { 490 assert !nd.transferToDirectlyNeedsPositionLock() || 491 Thread.holdsLock(positionLock); 492 493 long n = -1; 494 int ti = -1; 495 try { 496 beginBlocking(); 497 ti = threads.add(); 498 if (!isOpen()) 499 return -1; 500 do { 501 n = transferTo0(fd, position, icount, targetFD); 502 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 503 if (n == IOStatus.UNSUPPORTED_CASE) { 504 if (target instanceof SinkChannelImpl) 505 pipeSupported = false; 506 if (target instanceof FileChannelImpl) 507 fileSupported = false; 508 return IOStatus.UNSUPPORTED_CASE; 509 } 510 if (n == IOStatus.UNSUPPORTED) { 511 // Don't bother trying again 512 transferSupported = false; 513 return IOStatus.UNSUPPORTED; 514 } 515 return IOStatus.normalize(n); 516 } finally { 517 threads.remove(ti); 518 end (n > -1); 519 } 520 } 521 522 private long transferToDirectly(long position, int icount, 523 WritableByteChannel target) 524 throws IOException 525 { 526 if (!transferSupported) 527 return IOStatus.UNSUPPORTED; 528 529 FileDescriptor targetFD = null; 530 if (target instanceof FileChannelImpl) { 531 if (!fileSupported) 532 return IOStatus.UNSUPPORTED_CASE; 533 targetFD = ((FileChannelImpl)target).fd; 534 } else if (target instanceof SelChImpl) { 535 // Direct transfer to pipe causes EINVAL on some configurations 536 if ((target instanceof SinkChannelImpl) && !pipeSupported) 537 return IOStatus.UNSUPPORTED_CASE; 538 539 // Platform-specific restrictions. Now there is only one: 540 // Direct transfer to non-blocking channel could be forbidden 541 SelectableChannel sc = (SelectableChannel)target; 542 if (!nd.canTransferToDirectly(sc)) 543 return IOStatus.UNSUPPORTED_CASE; 544 545 targetFD = ((SelChImpl)target).getFD(); 546 } 547 548 if (targetFD == null) 549 return IOStatus.UNSUPPORTED; 550 int thisFDVal = IOUtil.fdVal(fd); 551 int targetFDVal = IOUtil.fdVal(targetFD); 552 if (thisFDVal == targetFDVal) // Not supported on some configurations 553 return IOStatus.UNSUPPORTED; 554 555 if (nd.transferToDirectlyNeedsPositionLock()) { 556 synchronized (positionLock) { 557 long pos = position(); 558 try { 559 return transferToDirectlyInternal(position, icount, 560 target, targetFD); 561 } finally { 562 position(pos); 563 } 564 } 565 } else { 566 return transferToDirectlyInternal(position, icount, target, targetFD); 567 } 568 } 569 570 // Maximum size to map when using a mapped buffer 571 private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; 572 573 private long transferToTrustedChannel(long position, long count, 574 WritableByteChannel target) 575 throws IOException 576 { 577 boolean isSelChImpl = (target instanceof SelChImpl); 578 if (!((target instanceof FileChannelImpl) || isSelChImpl)) 579 return IOStatus.UNSUPPORTED; 580 581 // Trusted target: Use a mapped buffer 582 long remaining = count; 583 while (remaining > 0L) { 584 long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); 585 try { 586 MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); 587 try { 588 // ## Bug: Closing this channel will not terminate the write 589 int n = target.write(dbb); 590 assert n >= 0; 591 remaining -= n; 592 if (isSelChImpl) { 593 // one attempt to write to selectable channel 594 break; 595 } 596 assert n > 0; 597 position += n; 598 } finally { 599 unmap(dbb); 600 } 601 } catch (ClosedByInterruptException e) { 602 // target closed by interrupt as ClosedByInterruptException needs 603 // to be thrown after closing this channel. 604 assert !target.isOpen(); 605 try { 606 close(); 607 } catch (Throwable suppressed) { 608 e.addSuppressed(suppressed); 609 } 610 throw e; 611 } catch (IOException ioe) { 612 // Only throw exception if no bytes have been written 613 if (remaining == count) 614 throw ioe; 615 break; 616 } 617 } 618 return count - remaining; 619 } 620 621 private long transferToArbitraryChannel(long position, int icount, 622 WritableByteChannel target) 623 throws IOException 624 { 625 // Untrusted target: Use a newly-erased buffer 626 int c = Math.min(icount, TRANSFER_SIZE); 627 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); 628 long tw = 0; // Total bytes written 629 long pos = position; 630 try { 631 Util.erase(bb); 632 while (tw < icount) { 633 bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE)); 634 int nr = read(bb, pos); 635 if (nr <= 0) 636 break; 637 bb.flip(); 638 // ## Bug: Will block writing target if this channel 639 // ## is asynchronously closed 640 int nw = target.write(bb); 641 tw += nw; 642 if (nw != nr) 643 break; 644 pos += nw; 645 bb.clear(); 646 } 647 return tw; 648 } catch (IOException x) { 649 if (tw > 0) 650 return tw; 651 throw x; 652 } finally { 653 Util.releaseTemporaryDirectBuffer(bb); 654 } 655 } 656 657 public long transferTo(long position, long count, 658 WritableByteChannel target) 659 throws IOException 660 { 661 ensureOpen(); 662 if (!target.isOpen()) 663 throw new ClosedChannelException(); 664 if (!readable) 665 throw new NonReadableChannelException(); 666 if (target instanceof FileChannelImpl && 667 !((FileChannelImpl)target).writable) 668 throw new NonWritableChannelException(); 669 if ((position < 0) || (count < 0)) 670 throw new IllegalArgumentException(); 671 long sz = size(); 672 if (position > sz) 673 return 0; 674 int icount = (int)Math.min(count, Integer.MAX_VALUE); 675 if ((sz - position) < icount) 676 icount = (int)(sz - position); 677 678 long n; 679 680 // Attempt a direct transfer, if the kernel supports it 681 if ((n = transferToDirectly(position, icount, target)) >= 0) 682 return n; 683 684 // Attempt a mapped transfer, but only to trusted channel types 685 if ((n = transferToTrustedChannel(position, icount, target)) >= 0) 686 return n; 687 688 // Slow path for untrusted targets 689 return transferToArbitraryChannel(position, icount, target); 690 } 691 692 private long transferFromFileChannel(FileChannelImpl src, 693 long position, long count) 694 throws IOException 695 { 696 if (!src.readable) 697 throw new NonReadableChannelException(); 698 synchronized (src.positionLock) { 699 long pos = src.position(); 700 long max = Math.min(count, src.size() - pos); 701 702 long remaining = max; 703 long p = pos; 704 while (remaining > 0L) { 705 long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); 706 // ## Bug: Closing this channel will not terminate the write 707 MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size); 708 try { 709 long n = write(bb, position); 710 assert n > 0; 711 p += n; 712 position += n; 713 remaining -= n; 714 } catch (IOException ioe) { 715 // Only throw exception if no bytes have been written 716 if (remaining == max) 717 throw ioe; 718 break; 719 } finally { 720 unmap(bb); 721 } 722 } 723 long nwritten = max - remaining; 724 src.position(pos + nwritten); 725 return nwritten; 726 } 727 } 728 729 private static final int TRANSFER_SIZE = 8192; 730 731 private long transferFromArbitraryChannel(ReadableByteChannel src, 732 long position, long count) 733 throws IOException 734 { 735 // Untrusted target: Use a newly-erased buffer 736 int c = (int)Math.min(count, TRANSFER_SIZE); 737 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); 738 long tw = 0; // Total bytes written 739 long pos = position; 740 try { 741 Util.erase(bb); 742 while (tw < count) { 743 bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE)); 744 // ## Bug: Will block reading src if this channel 745 // ## is asynchronously closed 746 int nr = src.read(bb); 747 if (nr <= 0) 748 break; 749 bb.flip(); 750 int nw = write(bb, pos); 751 tw += nw; 752 if (nw != nr) 753 break; 754 pos += nw; 755 bb.clear(); 756 } 757 return tw; 758 } catch (IOException x) { 759 if (tw > 0) 760 return tw; 761 throw x; 762 } finally { 763 Util.releaseTemporaryDirectBuffer(bb); 764 } 765 } 766 767 public long transferFrom(ReadableByteChannel src, 768 long position, long count) 769 throws IOException 770 { 771 ensureOpen(); 772 if (!src.isOpen()) 773 throw new ClosedChannelException(); 774 if (!writable) 775 throw new NonWritableChannelException(); 776 if ((position < 0) || (count < 0)) 777 throw new IllegalArgumentException(); 778 if (position > size()) 779 return 0; 780 if (src instanceof FileChannelImpl) 781 return transferFromFileChannel((FileChannelImpl)src, 782 position, count); 783 784 return transferFromArbitraryChannel(src, position, count); 785 } 786 787 public int read(ByteBuffer dst, long position) throws IOException { 788 if (dst == null) 789 throw new NullPointerException(); 790 if (position < 0) 791 throw new IllegalArgumentException("Negative position"); 792 if (!readable) 793 throw new NonReadableChannelException(); 794 if (direct) 795 Util.checkChannelPositionAligned(position, alignment); 796 ensureOpen(); 797 if (nd.needsPositionLock()) { 798 synchronized (positionLock) { 799 return readInternal(dst, position); 800 } 801 } else { 802 return readInternal(dst, position); 803 } 804 } 805 806 private int readInternal(ByteBuffer dst, long position) throws IOException { 807 assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); 808 int n = 0; 809 int ti = -1; 810 811 try { 812 beginBlocking(); 813 ti = threads.add(); 814 if (!isOpen()) 815 return -1; 816 do { 817 n = IOUtil.read(fd, dst, position, direct, alignment, nd); 818 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 819 return IOStatus.normalize(n); 820 } finally { 821 threads.remove(ti); 822 endBlocking(n > 0); 823 assert IOStatus.check(n); 824 } 825 } 826 827 public int write(ByteBuffer src, long position) throws IOException { 828 if (src == null) 829 throw new NullPointerException(); 830 if (position < 0) 831 throw new IllegalArgumentException("Negative position"); 832 if (!writable) 833 throw new NonWritableChannelException(); 834 if (direct) 835 Util.checkChannelPositionAligned(position, alignment); 836 ensureOpen(); 837 if (nd.needsPositionLock()) { 838 synchronized (positionLock) { 839 return writeInternal(src, position); 840 } 841 } else { 842 return writeInternal(src, position); 843 } 844 } 845 846 private int writeInternal(ByteBuffer src, long position) throws IOException { 847 assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); 848 int n = 0; 849 int ti = -1; 850 try { 851 beginBlocking(); 852 ti = threads.add(); 853 if (!isOpen()) 854 return -1; 855 do { 856 n = IOUtil.write(fd, src, position, direct, alignment, nd); 857 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 858 return IOStatus.normalize(n); 859 } finally { 860 threads.remove(ti); 861 endBlocking(n > 0); 862 assert IOStatus.check(n); 863 } 864 } 865 866 867 // -- Memory-mapped buffers -- 868 869 private static class Unmapper 870 implements Runnable 871 { 872 // may be required to close file 873 private static final NativeDispatcher nd = new FileDispatcherImpl(); 874 875 // keep track of mapped buffer usage 876 static volatile int count; 877 static volatile long totalSize; 878 static volatile long totalCapacity; 879 880 private volatile long address; 881 private final long size; 882 private final int cap; 883 private final FileDescriptor fd; 884 885 private Unmapper(long address, long size, int cap, 886 FileDescriptor fd) 887 { 888 assert (address != 0); 889 this.address = address; 890 this.size = size; 891 this.cap = cap; 892 this.fd = fd; 893 894 synchronized (Unmapper.class) { 895 count++; 896 totalSize += size; 897 totalCapacity += cap; 898 } 899 } 900 901 public void run() { 902 if (address == 0) 903 return; 904 unmap0(address, size); 905 address = 0; 906 907 // if this mapping has a valid file descriptor then we close it 908 if (fd.valid()) { 909 try { 910 nd.close(fd); 911 } catch (IOException ignore) { 912 // nothing we can do 913 } 914 } 915 916 synchronized (Unmapper.class) { 917 count--; 918 totalSize -= size; 919 totalCapacity -= cap; 920 } 921 } 922 } 923 924 private static void unmap(MappedByteBuffer bb) { 925 Cleaner cl = ((DirectBuffer)bb).cleaner(); 926 if (cl != null) 927 cl.clean(); 928 } 929 930 private static final int MAP_RO = 0; 931 private static final int MAP_RW = 1; 932 private static final int MAP_PV = 2; 933 934 public MappedByteBuffer map(MapMode mode, long position, long size) 935 throws IOException 936 { 937 ensureOpen(); 938 if (mode == null) 939 throw new NullPointerException("Mode is null"); 940 if (position < 0L) 941 throw new IllegalArgumentException("Negative position"); 942 if (size < 0L) 943 throw new IllegalArgumentException("Negative size"); 944 if (position + size < 0) 945 throw new IllegalArgumentException("Position + size overflow"); 946 if (size > Integer.MAX_VALUE) 947 throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE"); 948 949 int imode = -1; 950 if (mode == MapMode.READ_ONLY) 951 imode = MAP_RO; 952 else if (mode == MapMode.READ_WRITE) 953 imode = MAP_RW; 954 else if (mode == MapMode.PRIVATE) 955 imode = MAP_PV; 956 assert (imode >= 0); 957 if ((mode != MapMode.READ_ONLY) && !writable) 958 throw new NonWritableChannelException(); 959 if (!readable) 960 throw new NonReadableChannelException(); 961 962 long addr = -1; 963 int ti = -1; 964 try { 965 beginBlocking(); 966 ti = threads.add(); 967 if (!isOpen()) 968 return null; 969 970 long mapSize; 971 int pagePosition; 972 synchronized (positionLock) { 973 long filesize; 974 do { 975 filesize = nd.size(fd); 976 } while ((filesize == IOStatus.INTERRUPTED) && isOpen()); 977 if (!isOpen()) 978 return null; 979 980 if (filesize < position + size) { // Extend file size 981 if (!writable) { 982 throw new IOException("Channel not open for writing " + 983 "- cannot extend file to required size"); 984 } 985 int rv; 986 do { 987 rv = nd.truncate(fd, position + size); 988 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 989 if (!isOpen()) 990 return null; 991 } 992 993 if (size == 0) { 994 addr = 0; 995 // a valid file descriptor is not required 996 FileDescriptor dummy = new FileDescriptor(); 997 if ((!writable) || (imode == MAP_RO)) 998 return Util.newMappedByteBufferR(0, 0, dummy, null); 999 else 1000 return Util.newMappedByteBuffer(0, 0, dummy, null); 1001 } 1002 1003 pagePosition = (int)(position % allocationGranularity); 1004 long mapPosition = position - pagePosition; 1005 mapSize = size + pagePosition; 1006 try { 1007 // If map0 did not throw an exception, the address is valid 1008 addr = map0(imode, mapPosition, mapSize); 1009 } catch (OutOfMemoryError x) { 1010 // An OutOfMemoryError may indicate that we've exhausted 1011 // memory so force gc and re-attempt map 1012 System.gc(); 1013 try { 1014 Thread.sleep(100); 1015 } catch (InterruptedException y) { 1016 Thread.currentThread().interrupt(); 1017 } 1018 try { 1019 addr = map0(imode, mapPosition, mapSize); 1020 } catch (OutOfMemoryError y) { 1021 // After a second OOME, fail 1022 throw new IOException("Map failed", y); 1023 } 1024 } 1025 } // synchronized 1026 1027 // On Windows, and potentially other platforms, we need an open 1028 // file descriptor for some mapping operations. 1029 FileDescriptor mfd; 1030 try { 1031 mfd = nd.duplicateForMapping(fd); 1032 } catch (IOException ioe) { 1033 unmap0(addr, mapSize); 1034 throw ioe; 1035 } 1036 1037 assert (IOStatus.checkAll(addr)); 1038 assert (addr % allocationGranularity == 0); 1039 int isize = (int)size; 1040 Unmapper um = new Unmapper(addr, mapSize, isize, mfd); 1041 if ((!writable) || (imode == MAP_RO)) { 1042 return Util.newMappedByteBufferR(isize, 1043 addr + pagePosition, 1044 mfd, 1045 um); 1046 } else { 1047 return Util.newMappedByteBuffer(isize, 1048 addr + pagePosition, 1049 mfd, 1050 um); 1051 } 1052 } finally { 1053 threads.remove(ti); 1054 endBlocking(IOStatus.checkAll(addr)); 1055 } 1056 } 1057 1058 /** 1059 * Invoked by sun.management.ManagementFactoryHelper to create the management 1060 * interface for mapped buffers. 1061 */ 1062 public static JavaNioAccess.BufferPool getMappedBufferPool() { 1063 return new JavaNioAccess.BufferPool() { 1064 @Override 1065 public String getName() { 1066 return "mapped"; 1067 } 1068 @Override 1069 public long getCount() { 1070 return Unmapper.count; 1071 } 1072 @Override 1073 public long getTotalCapacity() { 1074 return Unmapper.totalCapacity; 1075 } 1076 @Override 1077 public long getMemoryUsed() { 1078 return Unmapper.totalSize; 1079 } 1080 }; 1081 } 1082 1083 // -- Locks -- 1084 1085 // keeps track of locks on this file 1086 private volatile FileLockTable fileLockTable; 1087 1088 private FileLockTable fileLockTable() throws IOException { 1089 if (fileLockTable == null) { 1090 synchronized (this) { 1091 if (fileLockTable == null) { 1092 int ti = threads.add(); 1093 try { 1094 ensureOpen(); 1095 fileLockTable = new FileLockTable(this, fd); 1096 } finally { 1097 threads.remove(ti); 1098 } 1099 } 1100 } 1101 } 1102 return fileLockTable; 1103 } 1104 1105 public FileLock lock(long position, long size, boolean shared) 1106 throws IOException 1107 { 1108 ensureOpen(); 1109 if (shared && !readable) 1110 throw new NonReadableChannelException(); 1111 if (!shared && !writable) 1112 throw new NonWritableChannelException(); 1113 FileLockImpl fli = new FileLockImpl(this, position, size, shared); 1114 FileLockTable flt = fileLockTable(); 1115 flt.add(fli); 1116 boolean completed = false; 1117 int ti = -1; 1118 try { 1119 beginBlocking(); 1120 ti = threads.add(); 1121 if (!isOpen()) 1122 return null; 1123 int n; 1124 do { 1125 n = nd.lock(fd, true, position, size, shared); 1126 } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); 1127 if (isOpen()) { 1128 if (n == FileDispatcher.RET_EX_LOCK) { 1129 assert shared; 1130 FileLockImpl fli2 = new FileLockImpl(this, position, size, 1131 false); 1132 flt.replace(fli, fli2); 1133 fli = fli2; 1134 } 1135 completed = true; 1136 } 1137 } finally { 1138 if (!completed) 1139 flt.remove(fli); 1140 threads.remove(ti); 1141 try { 1142 endBlocking(completed); 1143 } catch (ClosedByInterruptException e) { 1144 throw new FileLockInterruptionException(); 1145 } 1146 } 1147 return fli; 1148 } 1149 1150 public FileLock tryLock(long position, long size, boolean shared) 1151 throws IOException 1152 { 1153 ensureOpen(); 1154 if (shared && !readable) 1155 throw new NonReadableChannelException(); 1156 if (!shared && !writable) 1157 throw new NonWritableChannelException(); 1158 FileLockImpl fli = new FileLockImpl(this, position, size, shared); 1159 FileLockTable flt = fileLockTable(); 1160 flt.add(fli); 1161 int result; 1162 1163 int ti = threads.add(); 1164 try { 1165 try { 1166 ensureOpen(); 1167 result = nd.lock(fd, false, position, size, shared); 1168 } catch (IOException e) { 1169 flt.remove(fli); 1170 throw e; 1171 } 1172 if (result == FileDispatcher.NO_LOCK) { 1173 flt.remove(fli); 1174 return null; 1175 } 1176 if (result == FileDispatcher.RET_EX_LOCK) { 1177 assert shared; 1178 FileLockImpl fli2 = new FileLockImpl(this, position, size, 1179 false); 1180 flt.replace(fli, fli2); 1181 return fli2; 1182 } 1183 return fli; 1184 } finally { 1185 threads.remove(ti); 1186 } 1187 } 1188 1189 void release(FileLockImpl fli) throws IOException { 1190 int ti = threads.add(); 1191 try { 1192 ensureOpen(); 1193 nd.release(fd, fli.position(), fli.size()); 1194 } finally { 1195 threads.remove(ti); 1196 } 1197 assert fileLockTable != null; 1198 fileLockTable.remove(fli); 1199 } 1200 1201 // -- Native methods -- 1202 1203 // Creates a new mapping 1204 private native long map0(int prot, long position, long length) 1205 throws IOException; 1206 1207 // Removes an existing mapping 1208 private static native int unmap0(long address, long length); 1209 1210 // Transfers from src to dst, or returns -2 if kernel can't do that 1211 private native long transferTo0(FileDescriptor src, long position, 1212 long count, FileDescriptor dst); 1213 1214 // Caches fieldIDs 1215 private static native long initIDs(); 1216 1217 static { 1218 IOUtil.load(); 1219 allocationGranularity = initIDs(); 1220 } 1221 }