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