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