< prev index next >

src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java

Print this page

  61 import jdk.internal.ref.CleanerFactory;
  62 
  63 import jdk.internal.access.foreign.UnmapperProxy;
  64 
  65 public class FileChannelImpl
  66     extends FileChannel
  67 {
  68     // Access to FileDescriptor internals
  69     private static final JavaIOFileDescriptorAccess fdAccess =
  70         SharedSecrets.getJavaIOFileDescriptorAccess();
  71 
  72     // Used to make native read and write calls
  73     private static final FileDispatcher nd = new FileDispatcherImpl();
  74 
  75     // File descriptor
  76     private final FileDescriptor fd;
  77 
  78     // File access mode (immutable)
  79     private final boolean writable;
  80     private final boolean readable;

  81 
  82     // Required to prevent finalization of creating stream (immutable)
  83     private final Closeable parent;
  84 
  85     // The path of the referenced file
  86     // (null if the parent stream is created with a file descriptor)
  87     private final String path;
  88 
  89     // Thread-safe set of IDs of native threads, for signalling
  90     private final NativeThreadSet threads = new NativeThreadSet(2);
  91 
  92     // Lock for operations involving position and size
  93     private final Object positionLock = new Object();
  94 
  95     // blocking operations are not interruptible
  96     private volatile boolean uninterruptible;
  97 
  98     // DirectIO flag
  99     private final boolean direct;
 100 

 105     private final Cleanable closer;
 106 
 107     private static class Closer implements Runnable {
 108         private final FileDescriptor fd;
 109 
 110         Closer(FileDescriptor fd) {
 111             this.fd = fd;
 112         }
 113 
 114         public void run() {
 115             try {
 116                 fdAccess.close(fd);
 117             } catch (IOException ioe) {
 118                 // Rethrow as unchecked so the exception can be propagated as needed
 119                 throw new UncheckedIOException("close", ioe);
 120             }
 121         }
 122     }
 123 
 124     private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
 125                             boolean writable, boolean direct, Closeable parent)

 126     {
 127         this.fd = fd;
 128         this.path = path;
 129         this.readable = readable;
 130         this.writable = writable;

 131         this.direct = direct;
 132         this.parent = parent;
 133         if (direct) {
 134             assert path != null;
 135             this.alignment = nd.setDirectIO(fd, path);
 136         } else {
 137             this.alignment = -1;
 138         }
 139 
 140         // Register a cleaning action if and only if there is no parent
 141         // as the parent will take care of closing the file descriptor.
 142         // FileChannel is used by the LambdaMetaFactory so a lambda cannot
 143         // be used here hence we use a nested class instead.
 144         this.closer = parent != null ? null :
 145             CleanerFactory.cleaner().register(this, new Closer(fd));
 146     }
 147 
 148 
 149     // Used by FileInputStream::getChannel, FileOutputStream::getChannel,
 150     // and RandomAccessFile::getChannel
 151     public static FileChannel open(FileDescriptor fd, String path,
 152                                    boolean readable, boolean writable,
 153                                    boolean direct, Closeable parent)
 154     {
 155         return new FileChannelImpl(fd, path, readable, writable, direct, parent);
 156     }
 157 
 158     private void ensureOpen() throws IOException {
 159         if (!isOpen())
 160             throw new ClosedChannelException();
 161     }
 162 
 163     public void setUninterruptible() {
 164         uninterruptible = true;
 165     }
 166 
 167     private void beginBlocking() {
 168         if (!uninterruptible) begin();
 169     }
 170 
 171     private void endBlocking(boolean completed) throws AsynchronousCloseException {
 172         if (!uninterruptible) end(completed);
 173     }
 174 
 175     // -- Standard channel operations --

 213             }
 214         }
 215     }
 216 
 217     @Override
 218     public int read(ByteBuffer dst) throws IOException {
 219         ensureOpen();
 220         if (!readable)
 221             throw new NonReadableChannelException();
 222         synchronized (positionLock) {
 223             if (direct)
 224                 Util.checkChannelPositionAligned(position(), alignment);
 225             int n = 0;
 226             int ti = -1;
 227             try {
 228                 beginBlocking();
 229                 ti = threads.add();
 230                 if (!isOpen())
 231                     return 0;
 232                 do {
 233                     long comp = Blocker.begin();
 234                     try {
 235                         n = IOUtil.read(fd, dst, -1, direct, alignment, nd);
 236                     } finally {
 237                         Blocker.end(comp);
 238                     }
 239                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 240                 return IOStatus.normalize(n);
 241             } finally {
 242                 threads.remove(ti);
 243                 endBlocking(n > 0);
 244                 assert IOStatus.check(n);
 245             }
 246         }
 247     }
 248 
 249     @Override
 250     public long read(ByteBuffer[] dsts, int offset, int length)
 251         throws IOException
 252     {
 253         Objects.checkFromIndexSize(offset, length, dsts.length);
 254         ensureOpen();
 255         if (!readable)
 256             throw new NonReadableChannelException();
 257         synchronized (positionLock) {
 258             if (direct)
 259                 Util.checkChannelPositionAligned(position(), alignment);
 260             long n = 0;
 261             int ti = -1;
 262             try {
 263                 beginBlocking();
 264                 ti = threads.add();
 265                 if (!isOpen())
 266                     return 0;
 267                 do {
 268                     long comp = Blocker.begin();
 269                     try {
 270                         n = IOUtil.read(fd, dsts, offset, length, direct, alignment, nd);
 271                     } finally {
 272                         Blocker.end(comp);
 273                     }
 274 
 275                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 276                 return IOStatus.normalize(n);
 277             } finally {
 278                 threads.remove(ti);
 279                 endBlocking(n > 0);
 280                 assert IOStatus.check(n);
 281             }
 282         }
 283     }
 284 
 285     @Override
 286     public int write(ByteBuffer src) throws IOException {
 287         ensureOpen();
 288         if (!writable)
 289             throw new NonWritableChannelException();
 290         synchronized (positionLock) {
 291             if (direct)
 292                 Util.checkChannelPositionAligned(position(), alignment);
 293             int n = 0;
 294             int ti = -1;
 295             try {
 296                 beginBlocking();
 297                 ti = threads.add();
 298                 if (!isOpen())
 299                     return 0;
 300                 do {
 301                     long comp = Blocker.begin();
 302                     try {
 303                         n = IOUtil.write(fd, src, -1, direct, alignment, nd);
 304                     } finally {
 305                         Blocker.end(comp);
 306                     }
 307 
 308                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 309                 return IOStatus.normalize(n);
 310             } finally {
 311                 threads.remove(ti);
 312                 endBlocking(n > 0);
 313                 assert IOStatus.check(n);
 314             }
 315         }
 316     }
 317 
 318     @Override
 319     public long write(ByteBuffer[] srcs, int offset, int length)
 320         throws IOException
 321     {
 322         Objects.checkFromIndexSize(offset, length, srcs.length);
 323         ensureOpen();
 324         if (!writable)
 325             throw new NonWritableChannelException();
 326         synchronized (positionLock) {
 327             if (direct)
 328                 Util.checkChannelPositionAligned(position(), alignment);
 329             long n = 0;
 330             int ti = -1;
 331             try {
 332                 beginBlocking();
 333                 ti = threads.add();
 334                 if (!isOpen())
 335                     return 0;
 336                 do {
 337                     long comp = Blocker.begin();
 338                     try {
 339                         n = IOUtil.write(fd, srcs, offset, length, direct, alignment, nd);
 340                     } finally {
 341                         Blocker.end(comp);
 342                     }
 343                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 344                 return IOStatus.normalize(n);
 345             } finally {
 346                 threads.remove(ti);
 347                 endBlocking(n > 0);
 348                 assert IOStatus.check(n);
 349             }
 350         }
 351     }
 352 
 353     // -- Other operations --
 354 
 355     @Override
 356     public long position() throws IOException {
 357         ensureOpen();
 358         synchronized (positionLock) {
 359             long p = -1;
 360             int ti = -1;
 361             try {
 362                 beginBlocking();
 363                 ti = threads.add();
 364                 if (!isOpen())
 365                     return 0;
 366                 boolean append = fdAccess.getAppend(fd);
 367                 do {
 368                     long comp = Blocker.begin();
 369                     try {
 370                         // in append-mode then position is advanced to end before writing
 371                         p = (append) ? nd.size(fd) : nd.seek(fd, -1);
 372                     } finally {
 373                         Blocker.end(comp);
 374                     }
 375                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 376                 return IOStatus.normalize(p);
 377             } finally {
 378                 threads.remove(ti);
 379                 endBlocking(p > -1);
 380                 assert IOStatus.check(p);
 381             }
 382         }
 383     }
 384 
 385     @Override
 386     public FileChannel position(long newPosition) throws IOException {
 387         ensureOpen();
 388         if (newPosition < 0)
 389             throw new IllegalArgumentException();
 390         synchronized (positionLock) {
 391             long p = -1;
 392             int ti = -1;
 393             try {
 394                 beginBlocking();
 395                 ti = threads.add();
 396                 if (!isOpen())
 397                     return null;
 398                 do {
 399                     long comp = Blocker.begin();
 400                     try {
 401                         p = nd.seek(fd, newPosition);
 402                     } finally {
 403                         Blocker.end(comp);
 404                     }
 405                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 406                 return this;
 407             } finally {
 408                 threads.remove(ti);
 409                 endBlocking(p > -1);
 410                 assert IOStatus.check(p);
 411             }
 412         }
 413     }
 414 
 415     @Override
 416     public long size() throws IOException {
 417         ensureOpen();
 418         synchronized (positionLock) {
 419             long s = -1;
 420             int ti = -1;
 421             try {
 422                 beginBlocking();
 423                 ti = threads.add();
 424                 if (!isOpen())
 425                     return -1;
 426                 do {
 427                     long comp = Blocker.begin();
 428                     try {
 429                         s = nd.size(fd);
 430                     } finally {
 431                         Blocker.end(comp);
 432                     }
 433                 } while ((s == IOStatus.INTERRUPTED) && isOpen());
 434                 return IOStatus.normalize(s);
 435             } finally {
 436                 threads.remove(ti);
 437                 endBlocking(s > -1);
 438                 assert IOStatus.check(s);
 439             }
 440         }
 441     }
 442 
 443     @Override
 444     public FileChannel truncate(long newSize) throws IOException {
 445         ensureOpen();
 446         if (newSize < 0)
 447             throw new IllegalArgumentException("Negative size");
 448         if (!writable)
 449             throw new NonWritableChannelException();
 450         synchronized (positionLock) {
 451             int rv = -1;
 452             long p = -1;
 453             int ti = -1;
 454             long rp = -1;
 455             try {
 456                 beginBlocking();
 457                 ti = threads.add();
 458                 if (!isOpen())
 459                     return null;
 460 
 461                 // get current size
 462                 long size;
 463                 do {
 464                     long comp = Blocker.begin();
 465                     try {
 466                         size = nd.size(fd);
 467                     } finally {
 468                         Blocker.end(comp);
 469                     }
 470                 } while ((size == IOStatus.INTERRUPTED) && isOpen());
 471                 if (!isOpen())
 472                     return null;
 473 
 474                 // get current position
 475                 do {
 476                     long comp = Blocker.begin();
 477                     try {
 478                         p = nd.seek(fd, -1);
 479                     } finally {
 480                         Blocker.end(comp);
 481                     }
 482                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 483                 if (!isOpen())
 484                     return null;
 485                 assert p >= 0;
 486 
 487                 // truncate file if given size is less than the current size
 488                 if (newSize < size) {
 489                     do {
 490                         long comp = Blocker.begin();
 491                         try {
 492                             rv = nd.truncate(fd, newSize);
 493                         } finally {
 494                             Blocker.end(comp);
 495                         }
 496                     } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 497                     if (!isOpen())
 498                         return null;
 499                 }
 500 
 501                 // if position is beyond new size then adjust it
 502                 if (p > newSize)
 503                     p = newSize;
 504                 do {
 505                     long comp = Blocker.begin();
 506                     try {
 507                         rp = nd.seek(fd, p);
 508                     } finally {
 509                         Blocker.end(comp);
 510                     }
 511                 } while ((rp == IOStatus.INTERRUPTED) && isOpen());
 512                 return this;
 513             } finally {
 514                 threads.remove(ti);
 515                 endBlocking(rv > -1);
 516                 assert IOStatus.check(rv);
 517             }
 518         }
 519     }
 520 
 521     @Override
 522     public void force(boolean metaData) throws IOException {
 523         ensureOpen();
 524         int rv = -1;
 525         int ti = -1;
 526         try {
 527             beginBlocking();
 528             ti = threads.add();
 529             if (!isOpen())
 530                 return;
 531             do {
 532                 long comp = Blocker.begin();
 533                 try {
 534                     rv = nd.force(fd, metaData);
 535                 } finally {
 536                     Blocker.end(comp);
 537                 }
 538             } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 539         } finally {
 540             threads.remove(ti);
 541             endBlocking(rv > -1);
 542             assert IOStatus.check(rv);
 543         }
 544     }
 545 
 546     // Assume at first that the underlying kernel supports sendfile/equivalent;
 547     // set this to true if we find out later that it doesn't
 548     //
 549     private static volatile boolean transferToDirectNotSupported;
 550 
 551     // Assume at first that the underlying kernel supports copy_file_range/equivalent;
 552     // set this to true if we find out later that it doesn't
 553     //
 554     private static volatile boolean transferFromDirectNotSupported;
 555 
 556     /**

 607 
 608         }
 609         // one of the channels was closed during the transfer
 610         if (cce instanceof AsynchronousCloseException ace) {
 611             return ace;
 612         } else {
 613             var ace = new AsynchronousCloseException();
 614             ace.addSuppressed(cce);
 615             return ace;
 616         }
 617     }
 618 
 619     /**
 620      * Transfers bytes from this channel's file to the resource that the given file
 621      * descriptor is connected to.
 622      */
 623     private long transferToFileDescriptor(long position, int count, FileDescriptor targetFD) {
 624         long n;
 625         boolean append = fdAccess.getAppend(targetFD);
 626         do {
 627             long comp = Blocker.begin();
 628             try {
 629                 n = nd.transferTo(fd, position, count, targetFD, append);
 630             } finally {
 631                 Blocker.end(comp);
 632             }
 633         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 634         return n;
 635     }
 636 
 637     /**
 638      * Transfers bytes from this channel's file to the given channel's file.
 639      */
 640     private long transferToFileChannel(long position, int count, FileChannelImpl target)
 641         throws IOException
 642     {
 643         final FileChannelImpl source = this;
 644         boolean completed = false;
 645         try {
 646             beginBlocking();
 647             int sourceIndex = source.beforeTransfer();
 648             try {
 649                 int targetIndex = target.beforeTransfer();
 650                 try {
 651                     long n = transferToFileDescriptor(position, count, target.fd);
 652                     completed = (n >= 0);

 878                 if ((n = transferToTrustedChannel(position, count, target)) >= 0)
 879                     return n;
 880             }
 881 
 882             // fallback to read/write loop
 883             return transferToArbitraryChannel(position, count, target);
 884         } catch (ClosedChannelException e) {
 885             // throw AsynchronousCloseException or ClosedByInterruptException
 886             throw transferFailed(e, target);
 887         }
 888     }
 889 
 890     /**
 891      * Transfers bytes into this channel's file from the resource that the given file
 892      * descriptor is connected to.
 893      */
 894     private long transferFromFileDescriptor(FileDescriptor srcFD, long position, long count) {
 895         long n;
 896         boolean append = fdAccess.getAppend(fd);
 897         do {
 898             long comp = Blocker.begin();
 899             try {
 900                 n = nd.transferFrom(srcFD, fd, position, count, append);
 901             } finally {
 902                 Blocker.end(comp);
 903             }
 904         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 905         return n;
 906     }
 907 
 908     /**
 909      * Transfers bytes into this channel's file from the given channel's file. This
 910      * implementation uses copy_file_range or equivalent.
 911      */
 912     private long transferFromDirect(FileChannelImpl src, long position, long count)
 913         throws IOException
 914     {
 915         if (transferFromDirectNotSupported)
 916             return IOStatus.UNSUPPORTED;
 917 
 918         final FileChannelImpl target = this;
 919         boolean completed = false;
 920         try {
 921             beginBlocking();
 922             int srcIndex = src.beforeTransfer();
 923             try {

1071         if (nd.needsPositionLock()) {
1072             synchronized (positionLock) {
1073                 return readInternal(dst, position);
1074             }
1075         } else {
1076             return readInternal(dst, position);
1077         }
1078     }
1079 
1080     private int readInternal(ByteBuffer dst, long position) throws IOException {
1081         assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
1082         int n = 0;
1083         int ti = -1;
1084 
1085         try {
1086             beginBlocking();
1087             ti = threads.add();
1088             if (!isOpen())
1089                 return -1;
1090             do {
1091                 long comp = Blocker.begin();
1092                 try {
1093                     n = IOUtil.read(fd, dst, position, direct, alignment, nd);
1094                 } finally {
1095                     Blocker.end(comp);
1096                 }
1097             } while ((n == IOStatus.INTERRUPTED) && isOpen());
1098             return IOStatus.normalize(n);
1099         } finally {
1100             threads.remove(ti);
1101             endBlocking(n > 0);
1102             assert IOStatus.check(n);
1103         }
1104     }
1105 
1106     @Override
1107     public int write(ByteBuffer src, long position) throws IOException {
1108         if (src == null)
1109             throw new NullPointerException();
1110         if (position < 0)
1111             throw new IllegalArgumentException("Negative position");
1112         ensureOpen();
1113         if (!writable)
1114             throw new NonWritableChannelException();
1115         if (direct)
1116             Util.checkChannelPositionAligned(position, alignment);
1117         if (nd.needsPositionLock()) {
1118             synchronized (positionLock) {
1119                 return writeInternal(src, position);
1120             }
1121         } else {
1122             return writeInternal(src, position);
1123         }
1124     }
1125 
1126     private int writeInternal(ByteBuffer src, long position) throws IOException {
1127         assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
1128         int n = 0;
1129         int ti = -1;
1130         try {
1131             beginBlocking();
1132             ti = threads.add();
1133             if (!isOpen())
1134                 return -1;
1135             do {
1136                 long comp = Blocker.begin();
1137                 try {
1138                     n = IOUtil.write(fd, src, position, direct, alignment, nd);
1139                 } finally {
1140                     Blocker.end(comp);
1141                 }
1142             } while ((n == IOStatus.INTERRUPTED) && isOpen());
1143             return IOStatus.normalize(n);
1144         } finally {
1145             threads.remove(ti);
1146             endBlocking(n > 0);
1147             assert IOStatus.check(n);
1148         }
1149     }
1150 
1151 
1152     // -- Memory-mapped buffers --
1153 
1154     private abstract static sealed class Unmapper
1155         implements Runnable, UnmapperProxy
1156     {
1157         private final long address;
1158         protected final long size;
1159         protected final long cap;
1160         private final FileDescriptor fd;

1345             throw new IllegalArgumentException("Negative position");
1346         if (size < 0L)
1347             throw new IllegalArgumentException("Negative size");
1348         if (position + size < 0)
1349             throw new IllegalArgumentException("Position + size overflow");
1350 
1351         checkMode(mode, prot, isSync);
1352         long addr = -1;
1353         int ti = -1;
1354         try {
1355             beginBlocking();
1356             ti = threads.add();
1357             if (!isOpen())
1358                 return null;
1359 
1360             long mapSize;
1361             int pagePosition;
1362             synchronized (positionLock) {
1363                 long filesize;
1364                 do {
1365                     long comp = Blocker.begin();
1366                     try {
1367                         filesize = nd.size(fd);
1368                     } finally {
1369                         Blocker.end(comp);
1370                     }
1371                 } while ((filesize == IOStatus.INTERRUPTED) && isOpen());
1372                 if (!isOpen())
1373                     return null;
1374 
1375                 if (filesize < position + size) { // Extend file size
1376                     if (!writable) {
1377                         throw new IOException("Channel not open for writing " +
1378                             "- cannot extend file to required size");
1379                     }
1380                     int rv;
1381                     do {
1382                         long comp = Blocker.begin();
1383                         try {
1384                             rv = nd.truncate(fd, position + size);
1385                         } finally {
1386                             Blocker.end(comp);
1387                         }
1388                     } while ((rv == IOStatus.INTERRUPTED) && isOpen());
1389                     if (!isOpen())
1390                         return null;
1391                 }
1392 
1393                 if (size == 0) {
1394                     return null;
1395                 }
1396 
1397                 pagePosition = (int)(position % nd.allocationGranularity());
1398                 long mapPosition = position - pagePosition;
1399                 mapSize = size + pagePosition;
1400                 try {
1401                     // If map did not throw an exception, the address is valid
1402                     addr = nd.map(fd, prot, mapPosition, mapSize, isSync);
1403                 } catch (OutOfMemoryError x) {
1404                     // An OutOfMemoryError may indicate that we've exhausted
1405                     // memory so force gc and re-attempt map
1406                     System.gc();
1407                     try {

1558     {
1559         ensureOpen();
1560         if (shared && !readable)
1561             throw new NonReadableChannelException();
1562         if (!shared && !writable)
1563             throw new NonWritableChannelException();
1564         if (size == 0)
1565             size = Long.MAX_VALUE - Math.max(0, position);
1566         FileLockImpl fli = new FileLockImpl(this, position, size, shared);
1567         FileLockTable flt = fileLockTable();
1568         flt.add(fli);
1569         boolean completed = false;
1570         int ti = -1;
1571         try {
1572             beginBlocking();
1573             ti = threads.add();
1574             if (!isOpen())
1575                 return null;
1576             int n;
1577             do {
1578                 long comp = Blocker.begin();
1579                 try {
1580                     n = nd.lock(fd, true, position, size, shared);
1581                 } finally {
1582                     Blocker.end(comp);
1583                 }
1584             } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
1585             if (isOpen()) {
1586                 if (n == FileDispatcher.RET_EX_LOCK) {
1587                     assert shared;
1588                     FileLockImpl fli2 = new FileLockImpl(this, position, size,
1589                                                          false);
1590                     flt.replace(fli, fli2);
1591                     fli = fli2;
1592                 }
1593                 completed = true;
1594             }
1595         } finally {
1596             if (!completed)
1597                 flt.remove(fli);
1598             threads.remove(ti);
1599             try {
1600                 endBlocking(completed);
1601             } catch (ClosedByInterruptException e) {
1602                 throw new FileLockInterruptionException();

  61 import jdk.internal.ref.CleanerFactory;
  62 
  63 import jdk.internal.access.foreign.UnmapperProxy;
  64 
  65 public class FileChannelImpl
  66     extends FileChannel
  67 {
  68     // Access to FileDescriptor internals
  69     private static final JavaIOFileDescriptorAccess fdAccess =
  70         SharedSecrets.getJavaIOFileDescriptorAccess();
  71 
  72     // Used to make native read and write calls
  73     private static final FileDispatcher nd = new FileDispatcherImpl();
  74 
  75     // File descriptor
  76     private final FileDescriptor fd;
  77 
  78     // File access mode (immutable)
  79     private final boolean writable;
  80     private final boolean readable;
  81     private final boolean sync;  // O_SYNC or O_DSYNC
  82 
  83     // Required to prevent finalization of creating stream (immutable)
  84     private final Closeable parent;
  85 
  86     // The path of the referenced file
  87     // (null if the parent stream is created with a file descriptor)
  88     private final String path;
  89 
  90     // Thread-safe set of IDs of native threads, for signalling
  91     private final NativeThreadSet threads = new NativeThreadSet(2);
  92 
  93     // Lock for operations involving position and size
  94     private final Object positionLock = new Object();
  95 
  96     // blocking operations are not interruptible
  97     private volatile boolean uninterruptible;
  98 
  99     // DirectIO flag
 100     private final boolean direct;
 101 

 106     private final Cleanable closer;
 107 
 108     private static class Closer implements Runnable {
 109         private final FileDescriptor fd;
 110 
 111         Closer(FileDescriptor fd) {
 112             this.fd = fd;
 113         }
 114 
 115         public void run() {
 116             try {
 117                 fdAccess.close(fd);
 118             } catch (IOException ioe) {
 119                 // Rethrow as unchecked so the exception can be propagated as needed
 120                 throw new UncheckedIOException("close", ioe);
 121             }
 122         }
 123     }
 124 
 125     private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
 126                             boolean writable, boolean sync, boolean direct,
 127                             Closeable parent)
 128     {
 129         this.fd = fd;
 130         this.path = path;
 131         this.readable = readable;
 132         this.writable = writable;
 133         this.sync = sync;
 134         this.direct = direct;
 135         this.parent = parent;
 136         if (direct) {
 137             assert path != null;
 138             this.alignment = nd.setDirectIO(fd, path);
 139         } else {
 140             this.alignment = -1;
 141         }
 142 
 143         // Register a cleaning action if and only if there is no parent
 144         // as the parent will take care of closing the file descriptor.
 145         // FileChannel is used by the LambdaMetaFactory so a lambda cannot
 146         // be used here hence we use a nested class instead.
 147         this.closer = parent != null ? null :
 148             CleanerFactory.cleaner().register(this, new Closer(fd));
 149     }
 150 
 151 
 152     // Used by FileInputStream::getChannel, FileOutputStream::getChannel,
 153     // and RandomAccessFile::getChannel
 154     public static FileChannel open(FileDescriptor fd, String path,
 155                                    boolean readable, boolean writable,
 156                                    boolean sync, boolean direct, Closeable parent)
 157     {
 158         return new FileChannelImpl(fd, path, readable, writable, sync, direct, parent);
 159     }
 160 
 161     private void ensureOpen() throws IOException {
 162         if (!isOpen())
 163             throw new ClosedChannelException();
 164     }
 165 
 166     public void setUninterruptible() {
 167         uninterruptible = true;
 168     }
 169 
 170     private void beginBlocking() {
 171         if (!uninterruptible) begin();
 172     }
 173 
 174     private void endBlocking(boolean completed) throws AsynchronousCloseException {
 175         if (!uninterruptible) end(completed);
 176     }
 177 
 178     // -- Standard channel operations --

 216             }
 217         }
 218     }
 219 
 220     @Override
 221     public int read(ByteBuffer dst) throws IOException {
 222         ensureOpen();
 223         if (!readable)
 224             throw new NonReadableChannelException();
 225         synchronized (positionLock) {
 226             if (direct)
 227                 Util.checkChannelPositionAligned(position(), alignment);
 228             int n = 0;
 229             int ti = -1;
 230             try {
 231                 beginBlocking();
 232                 ti = threads.add();
 233                 if (!isOpen())
 234                     return 0;
 235                 do {
 236                     boolean attempted = Blocker.begin(direct);
 237                     try {
 238                         n = IOUtil.read(fd, dst, -1, direct, alignment, nd);
 239                     } finally {
 240                         Blocker.end(attempted);
 241                     }
 242                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 243                 return IOStatus.normalize(n);
 244             } finally {
 245                 threads.remove(ti);
 246                 endBlocking(n > 0);
 247                 assert IOStatus.check(n);
 248             }
 249         }
 250     }
 251 
 252     @Override
 253     public long read(ByteBuffer[] dsts, int offset, int length)
 254         throws IOException
 255     {
 256         Objects.checkFromIndexSize(offset, length, dsts.length);
 257         ensureOpen();
 258         if (!readable)
 259             throw new NonReadableChannelException();
 260         synchronized (positionLock) {
 261             if (direct)
 262                 Util.checkChannelPositionAligned(position(), alignment);
 263             long n = 0;
 264             int ti = -1;
 265             try {
 266                 beginBlocking();
 267                 ti = threads.add();
 268                 if (!isOpen())
 269                     return 0;
 270                 do {
 271                     boolean attempted = Blocker.begin(direct);
 272                     try {
 273                         n = IOUtil.read(fd, dsts, offset, length, direct, alignment, nd);
 274                     } finally {
 275                         Blocker.end(attempted);
 276                     }
 277 
 278                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 279                 return IOStatus.normalize(n);
 280             } finally {
 281                 threads.remove(ti);
 282                 endBlocking(n > 0);
 283                 assert IOStatus.check(n);
 284             }
 285         }
 286     }
 287 
 288     @Override
 289     public int write(ByteBuffer src) throws IOException {
 290         ensureOpen();
 291         if (!writable)
 292             throw new NonWritableChannelException();
 293         synchronized (positionLock) {
 294             if (direct)
 295                 Util.checkChannelPositionAligned(position(), alignment);
 296             int n = 0;
 297             int ti = -1;
 298             try {
 299                 beginBlocking();
 300                 ti = threads.add();
 301                 if (!isOpen())
 302                     return 0;
 303                 do {
 304                     boolean attempted = Blocker.begin(sync | direct);
 305                     try {
 306                         n = IOUtil.write(fd, src, -1, direct, alignment, nd);
 307                     } finally {
 308                         Blocker.end(attempted);
 309                     }
 310 
 311                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 312                 return IOStatus.normalize(n);
 313             } finally {
 314                 threads.remove(ti);
 315                 endBlocking(n > 0);
 316                 assert IOStatus.check(n);
 317             }
 318         }
 319     }
 320 
 321     @Override
 322     public long write(ByteBuffer[] srcs, int offset, int length)
 323         throws IOException
 324     {
 325         Objects.checkFromIndexSize(offset, length, srcs.length);
 326         ensureOpen();
 327         if (!writable)
 328             throw new NonWritableChannelException();
 329         synchronized (positionLock) {
 330             if (direct)
 331                 Util.checkChannelPositionAligned(position(), alignment);
 332             long n = 0;
 333             int ti = -1;
 334             try {
 335                 beginBlocking();
 336                 ti = threads.add();
 337                 if (!isOpen())
 338                     return 0;
 339                 do {
 340                     boolean attempted = Blocker.begin(sync | direct);
 341                     try {
 342                         n = IOUtil.write(fd, srcs, offset, length, direct, alignment, nd);
 343                     } finally {
 344                         Blocker.end(attempted);
 345                     }
 346                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 347                 return IOStatus.normalize(n);
 348             } finally {
 349                 threads.remove(ti);
 350                 endBlocking(n > 0);
 351                 assert IOStatus.check(n);
 352             }
 353         }
 354     }
 355 
 356     // -- Other operations --
 357 
 358     @Override
 359     public long position() throws IOException {
 360         ensureOpen();
 361         synchronized (positionLock) {
 362             long p = -1;
 363             int ti = -1;
 364             try {
 365                 beginBlocking();
 366                 ti = threads.add();
 367                 if (!isOpen())
 368                     return 0;
 369                 boolean append = fdAccess.getAppend(fd);
 370                 do {
 371                     // in append-mode then position is advanced to end before writing
 372                     p = (append) ? nd.size(fd) : nd.seek(fd, -1);





 373                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 374                 return IOStatus.normalize(p);
 375             } finally {
 376                 threads.remove(ti);
 377                 endBlocking(p > -1);
 378                 assert IOStatus.check(p);
 379             }
 380         }
 381     }
 382 
 383     @Override
 384     public FileChannel position(long newPosition) throws IOException {
 385         ensureOpen();
 386         if (newPosition < 0)
 387             throw new IllegalArgumentException();
 388         synchronized (positionLock) {
 389             long p = -1;
 390             int ti = -1;
 391             try {
 392                 beginBlocking();
 393                 ti = threads.add();
 394                 if (!isOpen())
 395                     return null;
 396                 do {
 397                     p = nd.seek(fd, newPosition);





 398                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 399                 return this;
 400             } finally {
 401                 threads.remove(ti);
 402                 endBlocking(p > -1);
 403                 assert IOStatus.check(p);
 404             }
 405         }
 406     }
 407 
 408     @Override
 409     public long size() throws IOException {
 410         ensureOpen();
 411         synchronized (positionLock) {
 412             long s = -1;
 413             int ti = -1;
 414             try {
 415                 beginBlocking();
 416                 ti = threads.add();
 417                 if (!isOpen())
 418                     return -1;
 419                 do {
 420                     s = nd.size(fd);





 421                 } while ((s == IOStatus.INTERRUPTED) && isOpen());
 422                 return IOStatus.normalize(s);
 423             } finally {
 424                 threads.remove(ti);
 425                 endBlocking(s > -1);
 426                 assert IOStatus.check(s);
 427             }
 428         }
 429     }
 430 
 431     @Override
 432     public FileChannel truncate(long newSize) throws IOException {
 433         ensureOpen();
 434         if (newSize < 0)
 435             throw new IllegalArgumentException("Negative size");
 436         if (!writable)
 437             throw new NonWritableChannelException();
 438         synchronized (positionLock) {
 439             int rv = -1;
 440             long p = -1;
 441             int ti = -1;
 442             long rp = -1;
 443             try {
 444                 beginBlocking();
 445                 ti = threads.add();
 446                 if (!isOpen())
 447                     return null;
 448 
 449                 // get current size
 450                 long size;
 451                 do {
 452                     size = nd.size(fd);





 453                 } while ((size == IOStatus.INTERRUPTED) && isOpen());
 454                 if (!isOpen())
 455                     return null;
 456 
 457                 // get current position
 458                 do {
 459                     p = nd.seek(fd, -1);





 460                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
 461                 if (!isOpen())
 462                     return null;
 463                 assert p >= 0;
 464 
 465                 // truncate file if given size is less than the current size
 466                 if (newSize < size) {
 467                     do {
 468                         rv = nd.truncate(fd, newSize);





 469                     } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 470                     if (!isOpen())
 471                         return null;
 472                 }
 473 
 474                 // if position is beyond new size then adjust it
 475                 if (p > newSize)
 476                     p = newSize;
 477                 do {
 478                     rp = nd.seek(fd, p);





 479                 } while ((rp == IOStatus.INTERRUPTED) && isOpen());
 480                 return this;
 481             } finally {
 482                 threads.remove(ti);
 483                 endBlocking(rv > -1);
 484                 assert IOStatus.check(rv);
 485             }
 486         }
 487     }
 488 
 489     @Override
 490     public void force(boolean metaData) throws IOException {
 491         ensureOpen();
 492         int rv = -1;
 493         int ti = -1;
 494         try {
 495             beginBlocking();
 496             ti = threads.add();
 497             if (!isOpen())
 498                 return;
 499             do {
 500                 boolean attempted = Blocker.begin();
 501                 try {
 502                     rv = nd.force(fd, metaData);
 503                 } finally {
 504                     Blocker.end(attempted);
 505                 }
 506             } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 507         } finally {
 508             threads.remove(ti);
 509             endBlocking(rv > -1);
 510             assert IOStatus.check(rv);
 511         }
 512     }
 513 
 514     // Assume at first that the underlying kernel supports sendfile/equivalent;
 515     // set this to true if we find out later that it doesn't
 516     //
 517     private static volatile boolean transferToDirectNotSupported;
 518 
 519     // Assume at first that the underlying kernel supports copy_file_range/equivalent;
 520     // set this to true if we find out later that it doesn't
 521     //
 522     private static volatile boolean transferFromDirectNotSupported;
 523 
 524     /**

 575 
 576         }
 577         // one of the channels was closed during the transfer
 578         if (cce instanceof AsynchronousCloseException ace) {
 579             return ace;
 580         } else {
 581             var ace = new AsynchronousCloseException();
 582             ace.addSuppressed(cce);
 583             return ace;
 584         }
 585     }
 586 
 587     /**
 588      * Transfers bytes from this channel's file to the resource that the given file
 589      * descriptor is connected to.
 590      */
 591     private long transferToFileDescriptor(long position, int count, FileDescriptor targetFD) {
 592         long n;
 593         boolean append = fdAccess.getAppend(targetFD);
 594         do {
 595             n = nd.transferTo(fd, position, count, targetFD, append);





 596         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 597         return n;
 598     }
 599 
 600     /**
 601      * Transfers bytes from this channel's file to the given channel's file.
 602      */
 603     private long transferToFileChannel(long position, int count, FileChannelImpl target)
 604         throws IOException
 605     {
 606         final FileChannelImpl source = this;
 607         boolean completed = false;
 608         try {
 609             beginBlocking();
 610             int sourceIndex = source.beforeTransfer();
 611             try {
 612                 int targetIndex = target.beforeTransfer();
 613                 try {
 614                     long n = transferToFileDescriptor(position, count, target.fd);
 615                     completed = (n >= 0);

 841                 if ((n = transferToTrustedChannel(position, count, target)) >= 0)
 842                     return n;
 843             }
 844 
 845             // fallback to read/write loop
 846             return transferToArbitraryChannel(position, count, target);
 847         } catch (ClosedChannelException e) {
 848             // throw AsynchronousCloseException or ClosedByInterruptException
 849             throw transferFailed(e, target);
 850         }
 851     }
 852 
 853     /**
 854      * Transfers bytes into this channel's file from the resource that the given file
 855      * descriptor is connected to.
 856      */
 857     private long transferFromFileDescriptor(FileDescriptor srcFD, long position, long count) {
 858         long n;
 859         boolean append = fdAccess.getAppend(fd);
 860         do {
 861             n = nd.transferFrom(srcFD, fd, position, count, append);





 862         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 863         return n;
 864     }
 865 
 866     /**
 867      * Transfers bytes into this channel's file from the given channel's file. This
 868      * implementation uses copy_file_range or equivalent.
 869      */
 870     private long transferFromDirect(FileChannelImpl src, long position, long count)
 871         throws IOException
 872     {
 873         if (transferFromDirectNotSupported)
 874             return IOStatus.UNSUPPORTED;
 875 
 876         final FileChannelImpl target = this;
 877         boolean completed = false;
 878         try {
 879             beginBlocking();
 880             int srcIndex = src.beforeTransfer();
 881             try {

1029         if (nd.needsPositionLock()) {
1030             synchronized (positionLock) {
1031                 return readInternal(dst, position);
1032             }
1033         } else {
1034             return readInternal(dst, position);
1035         }
1036     }
1037 
1038     private int readInternal(ByteBuffer dst, long position) throws IOException {
1039         assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
1040         int n = 0;
1041         int ti = -1;
1042 
1043         try {
1044             beginBlocking();
1045             ti = threads.add();
1046             if (!isOpen())
1047                 return -1;
1048             do {
1049                 boolean attempted = Blocker.begin(direct);
1050                 try {
1051                     n = IOUtil.read(fd, dst, position, direct, alignment, nd);
1052                 } finally {
1053                     Blocker.end(attempted);
1054                 }
1055             } while ((n == IOStatus.INTERRUPTED) && isOpen());
1056             return IOStatus.normalize(n);
1057         } finally {
1058             threads.remove(ti);
1059             endBlocking(n > 0);
1060             assert IOStatus.check(n);
1061         }
1062     }
1063 
1064     @Override
1065     public int write(ByteBuffer src, long position) throws IOException {
1066         if (src == null)
1067             throw new NullPointerException();
1068         if (position < 0)
1069             throw new IllegalArgumentException("Negative position");
1070         ensureOpen();
1071         if (!writable)
1072             throw new NonWritableChannelException();
1073         if (direct)
1074             Util.checkChannelPositionAligned(position, alignment);
1075         if (nd.needsPositionLock()) {
1076             synchronized (positionLock) {
1077                 return writeInternal(src, position);
1078             }
1079         } else {
1080             return writeInternal(src, position);
1081         }
1082     }
1083 
1084     private int writeInternal(ByteBuffer src, long position) throws IOException {
1085         assert !nd.needsPositionLock() || Thread.holdsLock(positionLock);
1086         int n = 0;
1087         int ti = -1;
1088         try {
1089             beginBlocking();
1090             ti = threads.add();
1091             if (!isOpen())
1092                 return -1;
1093             do {
1094                 boolean attempted = Blocker.begin(sync | direct);
1095                 try {
1096                     n = IOUtil.write(fd, src, position, direct, alignment, nd);
1097                 } finally {
1098                     Blocker.end(attempted);
1099                 }
1100             } while ((n == IOStatus.INTERRUPTED) && isOpen());
1101             return IOStatus.normalize(n);
1102         } finally {
1103             threads.remove(ti);
1104             endBlocking(n > 0);
1105             assert IOStatus.check(n);
1106         }
1107     }
1108 
1109 
1110     // -- Memory-mapped buffers --
1111 
1112     private abstract static sealed class Unmapper
1113         implements Runnable, UnmapperProxy
1114     {
1115         private final long address;
1116         protected final long size;
1117         protected final long cap;
1118         private final FileDescriptor fd;

1303             throw new IllegalArgumentException("Negative position");
1304         if (size < 0L)
1305             throw new IllegalArgumentException("Negative size");
1306         if (position + size < 0)
1307             throw new IllegalArgumentException("Position + size overflow");
1308 
1309         checkMode(mode, prot, isSync);
1310         long addr = -1;
1311         int ti = -1;
1312         try {
1313             beginBlocking();
1314             ti = threads.add();
1315             if (!isOpen())
1316                 return null;
1317 
1318             long mapSize;
1319             int pagePosition;
1320             synchronized (positionLock) {
1321                 long filesize;
1322                 do {
1323                     filesize = nd.size(fd);





1324                 } while ((filesize == IOStatus.INTERRUPTED) && isOpen());
1325                 if (!isOpen())
1326                     return null;
1327 
1328                 if (filesize < position + size) { // Extend file size
1329                     if (!writable) {
1330                         throw new IOException("Channel not open for writing " +
1331                             "- cannot extend file to required size");
1332                     }
1333                     int rv;
1334                     do {
1335                         rv = nd.truncate(fd, position + size);





1336                     } while ((rv == IOStatus.INTERRUPTED) && isOpen());
1337                     if (!isOpen())
1338                         return null;
1339                 }
1340 
1341                 if (size == 0) {
1342                     return null;
1343                 }
1344 
1345                 pagePosition = (int)(position % nd.allocationGranularity());
1346                 long mapPosition = position - pagePosition;
1347                 mapSize = size + pagePosition;
1348                 try {
1349                     // If map did not throw an exception, the address is valid
1350                     addr = nd.map(fd, prot, mapPosition, mapSize, isSync);
1351                 } catch (OutOfMemoryError x) {
1352                     // An OutOfMemoryError may indicate that we've exhausted
1353                     // memory so force gc and re-attempt map
1354                     System.gc();
1355                     try {

1506     {
1507         ensureOpen();
1508         if (shared && !readable)
1509             throw new NonReadableChannelException();
1510         if (!shared && !writable)
1511             throw new NonWritableChannelException();
1512         if (size == 0)
1513             size = Long.MAX_VALUE - Math.max(0, position);
1514         FileLockImpl fli = new FileLockImpl(this, position, size, shared);
1515         FileLockTable flt = fileLockTable();
1516         flt.add(fli);
1517         boolean completed = false;
1518         int ti = -1;
1519         try {
1520             beginBlocking();
1521             ti = threads.add();
1522             if (!isOpen())
1523                 return null;
1524             int n;
1525             do {
1526                 boolean attempted = Blocker.begin();
1527                 try {
1528                     n = nd.lock(fd, true, position, size, shared);
1529                 } finally {
1530                     Blocker.end(attempted);
1531                 }
1532             } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
1533             if (isOpen()) {
1534                 if (n == FileDispatcher.RET_EX_LOCK) {
1535                     assert shared;
1536                     FileLockImpl fli2 = new FileLockImpl(this, position, size,
1537                                                          false);
1538                     flt.replace(fli, fli2);
1539                     fli = fli2;
1540                 }
1541                 completed = true;
1542             }
1543         } finally {
1544             if (!completed)
1545                 flt.remove(fli);
1546             threads.remove(ti);
1547             try {
1548                 endBlocking(completed);
1549             } catch (ClosedByInterruptException e) {
1550                 throw new FileLockInterruptionException();
< prev index next >