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