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