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