~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/nio/ch/FileChannelImpl.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2000, 2011, 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 cli.Microsoft.Win32.SafeHandles.SafeFileHandle;
 
29
import cli.System.IntPtr;
 
30
import cli.System.IO.FileStream;
 
31
import cli.System.Runtime.InteropServices.DllImportAttribute;
 
32
import cli.System.Runtime.InteropServices.StructLayoutAttribute;
 
33
import cli.System.Runtime.InteropServices.LayoutKind;
 
34
import java.io.FileDescriptor;
 
35
import java.io.IOException;
 
36
import java.nio.ByteBuffer;
 
37
import java.nio.MappedByteBuffer;
 
38
import java.nio.channels.*;
 
39
import java.util.ArrayList;
 
40
import java.util.List;
 
41
import java.security.AccessController;
 
42
import sun.misc.Cleaner;
 
43
import sun.security.action.GetPropertyAction;
 
44
 
 
45
public class FileChannelImpl
 
46
    extends FileChannel
 
47
{
 
48
    private static final boolean win32 = ikvm.internal.Util.WINDOWS;
 
49
 
 
50
    // Memory allocation size for mapping buffers
 
51
    private static final long allocationGranularity = 64 * 1024;    // HACK we're using a hard coded value here that works on all mainstream platforms
 
52
 
 
53
    // Used to make native read and write calls
 
54
    private final FileDispatcher nd;
 
55
 
 
56
    // File descriptor
 
57
    private final FileDescriptor fd;
 
58
 
 
59
    // File access mode (immutable)
 
60
    private final boolean writable;
 
61
    private final boolean readable;
 
62
    private final boolean append;
 
63
 
 
64
    // Required to prevent finalization of creating stream (immutable)
 
65
    private final Object parent;
 
66
 
 
67
    // Thread-safe set of IDs of native threads, for signalling
 
68
    private final NativeThreadSet threads = new NativeThreadSet(2);
 
69
 
 
70
    // Lock for operations involving position and size
 
71
    private final Object positionLock = new Object();
 
72
 
 
73
    private FileChannelImpl(FileDescriptor fd, boolean readable,
 
74
                            boolean writable, boolean append, Object parent)
 
75
    {
 
76
        this.fd = fd;
 
77
        this.readable = readable;
 
78
        this.writable = writable;
 
79
        this.append = append;
 
80
        this.parent = parent;
 
81
        this.nd = new FileDispatcherImpl(append);
 
82
    }
 
83
 
 
84
    // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
 
85
    public static FileChannel open(FileDescriptor fd,
 
86
                                   boolean readable, boolean writable,
 
87
                                   Object parent)
 
88
    {
 
89
        return new FileChannelImpl(fd, readable, writable, false, parent);
 
90
    }
 
91
 
 
92
    // Used by FileOutputStream.getChannel
 
93
    public static FileChannel open(FileDescriptor fd,
 
94
                                   boolean readable, boolean writable,
 
95
                                   boolean append, Object parent)
 
96
    {
 
97
        return new FileChannelImpl(fd, readable, writable, append, parent);
 
98
    }
 
99
 
 
100
    private void ensureOpen() throws IOException {
 
101
        if (!isOpen())
 
102
            throw new ClosedChannelException();
 
103
    }
 
104
 
 
105
 
 
106
    // -- Standard channel operations --
 
107
 
 
108
    protected void implCloseChannel() throws IOException {
 
109
        // Release and invalidate any locks that we still hold
 
110
        if (fileLockTable != null) {
 
111
            for (FileLock fl: fileLockTable.removeAll()) {
 
112
                synchronized (fl) {
 
113
                    if (fl.isValid()) {
 
114
                        nd.release(fd, fl.position(), fl.size());
 
115
                        ((FileLockImpl)fl).invalidate();
 
116
                    }
 
117
                }
 
118
            }
 
119
        }
 
120
 
 
121
        nd.preClose(fd);
 
122
        threads.signalAndWait();
 
123
 
 
124
        if (parent != null) {
 
125
 
 
126
            // Close the fd via the parent stream's close method.  The parent
 
127
            // will reinvoke our close method, which is defined in the
 
128
            // superclass AbstractInterruptibleChannel, but the isOpen logic in
 
129
            // that method will prevent this method from being reinvoked.
 
130
            //
 
131
            ((java.io.Closeable)parent).close();
 
132
        } else {
 
133
            nd.close(fd);
 
134
        }
 
135
 
 
136
    }
 
137
 
 
138
    public int read(ByteBuffer dst) throws IOException {
 
139
        ensureOpen();
 
140
        if (!readable)
 
141
            throw new NonReadableChannelException();
 
142
        synchronized (positionLock) {
 
143
            int n = 0;
 
144
            int ti = -1;
 
145
            try {
 
146
                begin();
 
147
                ti = threads.add();
 
148
                if (!isOpen())
 
149
                    return 0;
 
150
                do {
 
151
                    n = IOUtil.read(fd, dst, -1, nd, positionLock);
 
152
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
153
                return IOStatus.normalize(n);
 
154
            } finally {
 
155
                threads.remove(ti);
 
156
                end(n > 0);
 
157
                assert IOStatus.check(n);
 
158
            }
 
159
        }
 
160
    }
 
161
 
 
162
    public long read(ByteBuffer[] dsts, int offset, int length)
 
163
        throws IOException
 
164
    {
 
165
        if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
 
166
            throw new IndexOutOfBoundsException();
 
167
        ensureOpen();
 
168
        if (!readable)
 
169
            throw new NonReadableChannelException();
 
170
        synchronized (positionLock) {
 
171
            long n = 0;
 
172
            int ti = -1;
 
173
            try {
 
174
                begin();
 
175
                ti = threads.add();
 
176
                if (!isOpen())
 
177
                    return 0;
 
178
                do {
 
179
                    n = IOUtil.read(fd, dsts, offset, length, nd);
 
180
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
181
                return IOStatus.normalize(n);
 
182
            } finally {
 
183
                threads.remove(ti);
 
184
                end(n > 0);
 
185
                assert IOStatus.check(n);
 
186
            }
 
187
        }
 
188
    }
 
189
 
 
190
    public int write(ByteBuffer src) throws IOException {
 
191
        ensureOpen();
 
192
        if (!writable)
 
193
            throw new NonWritableChannelException();
 
194
        synchronized (positionLock) {
 
195
            int n = 0;
 
196
            int ti = -1;
 
197
            try {
 
198
                begin();
 
199
                ti = threads.add();
 
200
                if (!isOpen())
 
201
                    return 0;
 
202
                do {
 
203
                    n = IOUtil.write(fd, src, -1, nd, positionLock);
 
204
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
205
                return IOStatus.normalize(n);
 
206
            } finally {
 
207
                threads.remove(ti);
 
208
                end(n > 0);
 
209
                assert IOStatus.check(n);
 
210
            }
 
211
        }
 
212
    }
 
213
 
 
214
    public long write(ByteBuffer[] srcs, int offset, int length)
 
215
        throws IOException
 
216
    {
 
217
        if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
 
218
            throw new IndexOutOfBoundsException();
 
219
        ensureOpen();
 
220
        if (!writable)
 
221
            throw new NonWritableChannelException();
 
222
        synchronized (positionLock) {
 
223
            long n = 0;
 
224
            int ti = -1;
 
225
            try {
 
226
                begin();
 
227
                ti = threads.add();
 
228
                if (!isOpen())
 
229
                    return 0;
 
230
                do {
 
231
                    n = IOUtil.write(fd, srcs, offset, length, nd);
 
232
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
233
                return IOStatus.normalize(n);
 
234
            } finally {
 
235
                threads.remove(ti);
 
236
                end(n > 0);
 
237
                assert IOStatus.check(n);
 
238
            }
 
239
        }
 
240
    }
 
241
 
 
242
    // -- Other operations --
 
243
 
 
244
    public long position() throws IOException {
 
245
        ensureOpen();
 
246
        synchronized (positionLock) {
 
247
            long p = -1;
 
248
            int ti = -1;
 
249
            try {
 
250
                begin();
 
251
                ti = threads.add();
 
252
                if (!isOpen())
 
253
                    return 0;
 
254
                do {
 
255
                    // in append-mode then position is advanced to end before writing
 
256
                    p = (append) ? nd.size(fd) : position0(fd, -1);
 
257
                } while ((p == IOStatus.INTERRUPTED) && isOpen());
 
258
                return IOStatus.normalize(p);
 
259
            } finally {
 
260
                threads.remove(ti);
 
261
                end(p > -1);
 
262
                assert IOStatus.check(p);
 
263
            }
 
264
        }
 
265
    }
 
266
 
 
267
    public FileChannel position(long newPosition) throws IOException {
 
268
        ensureOpen();
 
269
        if (newPosition < 0)
 
270
            throw new IllegalArgumentException();
 
271
        synchronized (positionLock) {
 
272
            long p = -1;
 
273
            int ti = -1;
 
274
            try {
 
275
                begin();
 
276
                ti = threads.add();
 
277
                if (!isOpen())
 
278
                    return null;
 
279
                do {
 
280
                    p  = position0(fd, newPosition);
 
281
                } while ((p == IOStatus.INTERRUPTED) && isOpen());
 
282
                return this;
 
283
            } finally {
 
284
                threads.remove(ti);
 
285
                end(p > -1);
 
286
                assert IOStatus.check(p);
 
287
            }
 
288
        }
 
289
    }
 
290
 
 
291
    public long size() throws IOException {
 
292
        ensureOpen();
 
293
        synchronized (positionLock) {
 
294
            long s = -1;
 
295
            int ti = -1;
 
296
            try {
 
297
                begin();
 
298
                ti = threads.add();
 
299
                if (!isOpen())
 
300
                    return -1;
 
301
                do {
 
302
                    s = nd.size(fd);
 
303
                } while ((s == IOStatus.INTERRUPTED) && isOpen());
 
304
                return IOStatus.normalize(s);
 
305
            } finally {
 
306
                threads.remove(ti);
 
307
                end(s > -1);
 
308
                assert IOStatus.check(s);
 
309
            }
 
310
        }
 
311
    }
 
312
 
 
313
    public FileChannel truncate(long size) throws IOException {
 
314
        ensureOpen();
 
315
        if (size < 0)
 
316
            throw new IllegalArgumentException();
 
317
        if (size > size())
 
318
            return this;
 
319
        if (!writable)
 
320
            throw new NonWritableChannelException();
 
321
        synchronized (positionLock) {
 
322
            int rv = -1;
 
323
            long p = -1;
 
324
            int ti = -1;
 
325
            try {
 
326
                begin();
 
327
                ti = threads.add();
 
328
                if (!isOpen())
 
329
                    return null;
 
330
 
 
331
                // get current position
 
332
                do {
 
333
                    p = position0(fd, -1);
 
334
                } while ((p == IOStatus.INTERRUPTED) && isOpen());
 
335
                if (!isOpen())
 
336
                    return null;
 
337
                assert p >= 0;
 
338
 
 
339
                // truncate file
 
340
                do {
 
341
                    rv = nd.truncate(fd, size);
 
342
                } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 
343
                if (!isOpen())
 
344
                    return null;
 
345
 
 
346
                // [IKVM] in append mode we're not allowed to seek backwards, but the atomic append will honor the new file size
 
347
                if (append)
 
348
                    return this;
 
349
 
 
350
                // set position to size if greater than size
 
351
                if (p > size)
 
352
                    p = size;
 
353
                do {
 
354
                    rv = (int)position0(fd, p);
 
355
                } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 
356
                return this;
 
357
            } finally {
 
358
                threads.remove(ti);
 
359
                end(rv > -1);
 
360
                assert IOStatus.check(rv);
 
361
            }
 
362
        }
 
363
    }
 
364
 
 
365
    public void force(boolean metaData) throws IOException {
 
366
        ensureOpen();
 
367
        int rv = -1;
 
368
        int ti = -1;
 
369
        try {
 
370
            begin();
 
371
            ti = threads.add();
 
372
            if (!isOpen())
 
373
                return;
 
374
            do {
 
375
                rv = nd.force(fd, metaData);
 
376
            } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 
377
        } finally {
 
378
            threads.remove(ti);
 
379
            end(rv > -1);
 
380
            assert IOStatus.check(rv);
 
381
        }
 
382
    }
 
383
 
 
384
    private long transferToArbitraryChannel(long position, int icount,
 
385
                                            WritableByteChannel target)
 
386
        throws IOException
 
387
    {
 
388
        // Untrusted target: Use a newly-erased buffer
 
389
        int c = Math.min(icount, TRANSFER_SIZE);
 
390
        ByteBuffer bb = ByteBuffer.allocate(c);
 
391
        long tw = 0;                    // Total bytes written
 
392
        long pos = position;
 
393
        try {
 
394
            while (tw < icount) {
 
395
                bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE));
 
396
                int nr = read(bb, pos);
 
397
                if (nr <= 0)
 
398
                    break;
 
399
                bb.flip();
 
400
                // ## Bug: Will block writing target if this channel
 
401
                // ##      is asynchronously closed
 
402
                int nw = target.write(bb);
 
403
                tw += nw;
 
404
                if (nw != nr)
 
405
                    break;
 
406
                pos += nw;
 
407
                bb.clear();
 
408
            }
 
409
            return tw;
 
410
        } catch (IOException x) {
 
411
            if (tw > 0)
 
412
                return tw;
 
413
            throw x;
 
414
        }
 
415
    }
 
416
 
 
417
    public long transferTo(long position, long count,
 
418
                           WritableByteChannel target)
 
419
        throws IOException
 
420
    {
 
421
        ensureOpen();
 
422
        if (!target.isOpen())
 
423
            throw new ClosedChannelException();
 
424
        if (!readable)
 
425
            throw new NonReadableChannelException();
 
426
        if (target instanceof FileChannelImpl &&
 
427
            !((FileChannelImpl)target).writable)
 
428
            throw new NonWritableChannelException();
 
429
        if ((position < 0) || (count < 0))
 
430
            throw new IllegalArgumentException();
 
431
        long sz = size();
 
432
        if (position > sz)
 
433
            return 0;
 
434
        int icount = (int)Math.min(count, Integer.MAX_VALUE);
 
435
        if ((sz - position) < icount)
 
436
            icount = (int)(sz - position);
 
437
 
 
438
        // Slow path for untrusted targets
 
439
        return transferToArbitraryChannel(position, icount, target);
 
440
    }
 
441
 
 
442
    private long transferFromFileChannel(FileChannelImpl src,
 
443
                                         long position, long count)
 
444
        throws IOException
 
445
    {
 
446
        if (!src.readable)
 
447
            throw new NonReadableChannelException();
 
448
        return transferFromArbitraryChannel(src, position, count);
 
449
    }
 
450
 
 
451
    private static final int TRANSFER_SIZE = 8192;
 
452
 
 
453
    private long transferFromArbitraryChannel(ReadableByteChannel src,
 
454
                                              long position, long count)
 
455
        throws IOException
 
456
    {
 
457
        // Untrusted target: Use a newly-erased buffer
 
458
        int c = (int)Math.min(count, TRANSFER_SIZE);
 
459
        ByteBuffer bb = ByteBuffer.allocate(c);
 
460
        long tw = 0;                    // Total bytes written
 
461
        long pos = position;
 
462
        try {
 
463
            while (tw < count) {
 
464
                bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));
 
465
                // ## Bug: Will block reading src if this channel
 
466
                // ##      is asynchronously closed
 
467
                int nr = src.read(bb);
 
468
                if (nr <= 0)
 
469
                    break;
 
470
                bb.flip();
 
471
                int nw = write(bb, pos);
 
472
                tw += nw;
 
473
                if (nw != nr)
 
474
                    break;
 
475
                pos += nw;
 
476
                bb.clear();
 
477
            }
 
478
            return tw;
 
479
        } catch (IOException x) {
 
480
            if (tw > 0)
 
481
                return tw;
 
482
            throw x;
 
483
        }
 
484
    }
 
485
 
 
486
    public long transferFrom(ReadableByteChannel src,
 
487
                             long position, long count)
 
488
        throws IOException
 
489
    {
 
490
        ensureOpen();
 
491
        if (!src.isOpen())
 
492
            throw new ClosedChannelException();
 
493
        if (!writable)
 
494
            throw new NonWritableChannelException();
 
495
        if ((position < 0) || (count < 0))
 
496
            throw new IllegalArgumentException();
 
497
        if (position > size())
 
498
            return 0;
 
499
        if (src instanceof FileChannelImpl)
 
500
           return transferFromFileChannel((FileChannelImpl)src,
 
501
                                          position, count);
 
502
 
 
503
        return transferFromArbitraryChannel(src, position, count);
 
504
    }
 
505
 
 
506
    public int read(ByteBuffer dst, long position) throws IOException {
 
507
        if (dst == null)
 
508
            throw new NullPointerException();
 
509
        if (position < 0)
 
510
            throw new IllegalArgumentException("Negative position");
 
511
        if (!readable)
 
512
            throw new NonReadableChannelException();
 
513
        ensureOpen();
 
514
        int n = 0;
 
515
        int ti = -1;
 
516
        try {
 
517
            begin();
 
518
            ti = threads.add();
 
519
            if (!isOpen())
 
520
                return -1;
 
521
            do {
 
522
                n = IOUtil.read(fd, dst, position, nd, positionLock);
 
523
            } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
524
            return IOStatus.normalize(n);
 
525
        } finally {
 
526
            threads.remove(ti);
 
527
            end(n > 0);
 
528
            assert IOStatus.check(n);
 
529
        }
 
530
    }
 
531
 
 
532
    public int write(ByteBuffer src, long position) throws IOException {
 
533
        if (src == null)
 
534
            throw new NullPointerException();
 
535
        if (position < 0)
 
536
            throw new IllegalArgumentException("Negative position");
 
537
        if (!writable)
 
538
            throw new NonWritableChannelException();
 
539
        ensureOpen();
 
540
        int n = 0;
 
541
        int ti = -1;
 
542
        try {
 
543
            begin();
 
544
            ti = threads.add();
 
545
            if (!isOpen())
 
546
                return -1;
 
547
            do {
 
548
                n = IOUtil.write(fd, src, position, nd, positionLock);
 
549
            } while ((n == IOStatus.INTERRUPTED) && isOpen());
 
550
            return IOStatus.normalize(n);
 
551
        } finally {
 
552
            threads.remove(ti);
 
553
            end(n > 0);
 
554
            assert IOStatus.check(n);
 
555
        }
 
556
    }
 
557
 
 
558
 
 
559
    // -- Memory-mapped buffers --
 
560
 
 
561
    private static class Unmapper
 
562
        implements Runnable
 
563
    {
 
564
        // may be required to close file
 
565
        private static final NativeDispatcher nd = new FileDispatcherImpl();
 
566
 
 
567
        // keep track of mapped buffer usage
 
568
        static volatile int count;
 
569
        static volatile long totalSize;
 
570
        static volatile long totalCapacity;
 
571
 
 
572
        private volatile long address;
 
573
        private final long size;
 
574
        private final int cap;
 
575
        private final FileDescriptor fd;
 
576
 
 
577
        private Unmapper(long address, long size, int cap,
 
578
                         FileDescriptor fd)
 
579
        {
 
580
            assert (address != 0);
 
581
            this.address = address;
 
582
            this.size = size;
 
583
            this.cap = cap;
 
584
            this.fd = fd;
 
585
 
 
586
            synchronized (Unmapper.class) {
 
587
                count++;
 
588
                totalSize += size;
 
589
                totalCapacity += cap;
 
590
            }
 
591
        }
 
592
 
 
593
        public void run() {
 
594
            if (address == 0)
 
595
                return;
 
596
            unmap0(address, size);
 
597
            address = 0;
 
598
 
 
599
            // if this mapping has a valid file descriptor then we close it
 
600
            if (fd.valid()) {
 
601
                try {
 
602
                    nd.close(fd);
 
603
                } catch (IOException ignore) {
 
604
                    // nothing we can do
 
605
                }
 
606
            }
 
607
 
 
608
            synchronized (Unmapper.class) {
 
609
                count--;
 
610
                totalSize -= size;
 
611
                totalCapacity -= cap;
 
612
            }
 
613
        }
 
614
    }
 
615
 
 
616
    private static void unmap(MappedByteBuffer bb) {
 
617
        Cleaner cl = ((DirectBuffer)bb).cleaner();
 
618
        if (cl != null)
 
619
            cl.clean();
 
620
    }
 
621
 
 
622
    private static final int MAP_RO = 0;
 
623
    private static final int MAP_RW = 1;
 
624
    private static final int MAP_PV = 2;
 
625
 
 
626
    public MappedByteBuffer map(MapMode mode, long position, long size)
 
627
        throws IOException
 
628
    {
 
629
        ensureOpen();
 
630
        if (position < 0L)
 
631
            throw new IllegalArgumentException("Negative position");
 
632
        if (size < 0L)
 
633
            throw new IllegalArgumentException("Negative size");
 
634
        if (position + size < 0)
 
635
            throw new IllegalArgumentException("Position + size overflow");
 
636
        if (size > Integer.MAX_VALUE)
 
637
            throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
 
638
        int imode = -1;
 
639
        if (mode == MapMode.READ_ONLY)
 
640
            imode = MAP_RO;
 
641
        else if (mode == MapMode.READ_WRITE)
 
642
            imode = MAP_RW;
 
643
        else if (mode == MapMode.PRIVATE)
 
644
            imode = MAP_PV;
 
645
        assert (imode >= 0);
 
646
        if ((mode != MapMode.READ_ONLY) && !writable)
 
647
            throw new NonWritableChannelException();
 
648
        if (!readable)
 
649
            throw new NonReadableChannelException();
 
650
 
 
651
        long addr = -1;
 
652
        int ti = -1;
 
653
        try {
 
654
            begin();
 
655
            ti = threads.add();
 
656
            if (!isOpen())
 
657
                return null;
 
658
            if (size() < position + size) { // Extend file size
 
659
                if (!writable) {
 
660
                    throw new IOException("Channel not open for writing " +
 
661
                        "- cannot extend file to required size");
 
662
                }
 
663
                int rv;
 
664
                do {
 
665
                    rv = nd.truncate(fd, position + size);
 
666
                } while ((rv == IOStatus.INTERRUPTED) && isOpen());
 
667
            }
 
668
            if (size == 0) {
 
669
                addr = 0;
 
670
                // a valid file descriptor is not required
 
671
                FileDescriptor dummy = new FileDescriptor();
 
672
                if ((!writable) || (imode == MAP_RO))
 
673
                    return Util.newMappedByteBufferR(0, 0, dummy, null);
 
674
                else
 
675
                    return Util.newMappedByteBuffer(0, 0, dummy, null);
 
676
            }
 
677
 
 
678
            int pagePosition = (int)(position % allocationGranularity);
 
679
            long mapPosition = position - pagePosition;
 
680
            long mapSize = size + pagePosition;
 
681
            try {
 
682
                // If no exception was thrown from map0, the address is valid
 
683
                addr = map0(imode, mapPosition, mapSize);
 
684
            } catch (OutOfMemoryError x) {
 
685
                // An OutOfMemoryError may indicate that we've exhausted memory
 
686
                // so force gc and re-attempt map
 
687
                System.gc();
 
688
                try {
 
689
                    Thread.sleep(100);
 
690
                } catch (InterruptedException y) {
 
691
                    Thread.currentThread().interrupt();
 
692
                }
 
693
                try {
 
694
                    addr = map0(imode, mapPosition, mapSize);
 
695
                } catch (OutOfMemoryError y) {
 
696
                    // After a second OOME, fail
 
697
                    throw new IOException("Map failed", y);
 
698
                }
 
699
            }
 
700
 
 
701
            // On Windows, and potentially other platforms, we need an open
 
702
            // file descriptor for some mapping operations.
 
703
            FileDescriptor mfd;
 
704
            try {
 
705
                mfd = nd.duplicateForMapping(fd);
 
706
            } catch (IOException ioe) {
 
707
                unmap0(addr, mapSize);
 
708
                throw ioe;
 
709
            }
 
710
 
 
711
            assert (IOStatus.checkAll(addr));
 
712
            assert (addr % allocationGranularity == 0);
 
713
            int isize = (int)size;
 
714
            Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
 
715
            if ((!writable) || (imode == MAP_RO)) {
 
716
                return Util.newMappedByteBufferR(isize,
 
717
                                                 addr + pagePosition,
 
718
                                                 mfd,
 
719
                                                 um);
 
720
            } else {
 
721
                return Util.newMappedByteBuffer(isize,
 
722
                                                addr + pagePosition,
 
723
                                                mfd,
 
724
                                                um);
 
725
            }
 
726
        } finally {
 
727
            threads.remove(ti);
 
728
            end(IOStatus.checkAll(addr));
 
729
        }
 
730
    }
 
731
 
 
732
    /**
 
733
     * Invoked by sun.management.ManagementFactoryHelper to create the management
 
734
     * interface for mapped buffers.
 
735
     */
 
736
    public static sun.misc.JavaNioAccess.BufferPool getMappedBufferPool() {
 
737
        return new sun.misc.JavaNioAccess.BufferPool() {
 
738
            @Override
 
739
            public String getName() {
 
740
                return "mapped";
 
741
            }
 
742
            @Override
 
743
            public long getCount() {
 
744
                return Unmapper.count;
 
745
            }
 
746
            @Override
 
747
            public long getTotalCapacity() {
 
748
                return Unmapper.totalCapacity;
 
749
            }
 
750
            @Override
 
751
            public long getMemoryUsed() {
 
752
                return Unmapper.totalSize;
 
753
            }
 
754
        };
 
755
    }
 
756
 
 
757
    // -- Locks --
 
758
 
 
759
 
 
760
 
 
761
    // keeps track of locks on this file
 
762
    private volatile FileLockTable fileLockTable;
 
763
 
 
764
    // indicates if file locks are maintained system-wide (as per spec)
 
765
    private static boolean isSharedFileLockTable;
 
766
 
 
767
    // indicates if the disableSystemWideOverlappingFileLockCheck property
 
768
    // has been checked
 
769
    private static volatile boolean propertyChecked;
 
770
 
 
771
    // The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so
 
772
    // the overlap check wasn't system wide when there were multiple channels to
 
773
    // the same file. This property is used to get 1.4/5.0 behavior if desired.
 
774
    private static boolean isSharedFileLockTable() {
 
775
        if (!propertyChecked) {
 
776
            synchronized (FileChannelImpl.class) {
 
777
                if (!propertyChecked) {
 
778
                    String value = AccessController.doPrivileged(
 
779
                        new GetPropertyAction(
 
780
                            "sun.nio.ch.disableSystemWideOverlappingFileLockCheck"));
 
781
                    isSharedFileLockTable = ((value == null) || value.equals("false"));
 
782
                    propertyChecked = true;
 
783
                }
 
784
            }
 
785
        }
 
786
        return isSharedFileLockTable;
 
787
    }
 
788
 
 
789
    private FileLockTable fileLockTable() throws IOException {
 
790
        if (fileLockTable == null) {
 
791
            synchronized (this) {
 
792
                if (fileLockTable == null) {
 
793
                    if (isSharedFileLockTable()) {
 
794
                        int ti = threads.add();
 
795
                        try {
 
796
                            ensureOpen();
 
797
                            fileLockTable = FileLockTable.newSharedFileLockTable(this, fd);
 
798
                        } finally {
 
799
                            threads.remove(ti);
 
800
                        }
 
801
                    } else {
 
802
                        fileLockTable = new SimpleFileLockTable();
 
803
                    }
 
804
                }
 
805
            }
 
806
        }
 
807
        return fileLockTable;
 
808
    }
 
809
 
 
810
    public FileLock lock(long position, long size, boolean shared)
 
811
        throws IOException
 
812
    {
 
813
        ensureOpen();
 
814
        if (shared && !readable)
 
815
            throw new NonReadableChannelException();
 
816
        if (!shared && !writable)
 
817
            throw new NonWritableChannelException();
 
818
        FileLockImpl fli = new FileLockImpl(this, position, size, shared);
 
819
        FileLockTable flt = fileLockTable();
 
820
        flt.add(fli);
 
821
        boolean completed = false;
 
822
        int ti = -1;
 
823
        try {
 
824
            begin();
 
825
            ti = threads.add();
 
826
            if (!isOpen())
 
827
                return null;
 
828
            int n;
 
829
            do {
 
830
                n = nd.lock(fd, true, position, size, shared);
 
831
            } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
 
832
            if (isOpen()) {
 
833
                if (n == FileDispatcher.RET_EX_LOCK) {
 
834
                    assert shared;
 
835
                    FileLockImpl fli2 = new FileLockImpl(this, position, size,
 
836
                                                         false);
 
837
                    flt.replace(fli, fli2);
 
838
                    fli = fli2;
 
839
                }
 
840
                completed = true;
 
841
            }
 
842
        } finally {
 
843
            if (!completed)
 
844
                flt.remove(fli);
 
845
            threads.remove(ti);
 
846
            try {
 
847
                end(completed);
 
848
            } catch (ClosedByInterruptException e) {
 
849
                throw new FileLockInterruptionException();
 
850
            }
 
851
        }
 
852
        return fli;
 
853
    }
 
854
 
 
855
    public FileLock tryLock(long position, long size, boolean shared)
 
856
        throws IOException
 
857
    {
 
858
        ensureOpen();
 
859
        if (shared && !readable)
 
860
            throw new NonReadableChannelException();
 
861
        if (!shared && !writable)
 
862
            throw new NonWritableChannelException();
 
863
        FileLockImpl fli = new FileLockImpl(this, position, size, shared);
 
864
        FileLockTable flt = fileLockTable();
 
865
        flt.add(fli);
 
866
        int result;
 
867
 
 
868
        int ti = threads.add();
 
869
        try {
 
870
            try {
 
871
                ensureOpen();
 
872
                result = nd.lock(fd, false, position, size, shared);
 
873
            } catch (IOException e) {
 
874
                flt.remove(fli);
 
875
                throw e;
 
876
            }
 
877
            if (result == FileDispatcher.NO_LOCK) {
 
878
                flt.remove(fli);
 
879
                return null;
 
880
            }
 
881
            if (result == FileDispatcher.RET_EX_LOCK) {
 
882
                assert shared;
 
883
                FileLockImpl fli2 = new FileLockImpl(this, position, size,
 
884
                                                     false);
 
885
                flt.replace(fli, fli2);
 
886
                return fli2;
 
887
            }
 
888
            return fli;
 
889
        } finally {
 
890
            threads.remove(ti);
 
891
        }
 
892
    }
 
893
 
 
894
    void release(FileLockImpl fli) throws IOException {
 
895
        int ti = threads.add();
 
896
        try {
 
897
            ensureOpen();
 
898
            nd.release(fd, fli.position(), fli.size());
 
899
        } finally {
 
900
            threads.remove(ti);
 
901
        }
 
902
        assert fileLockTable != null;
 
903
        fileLockTable.remove(fli);
 
904
    }
 
905
 
 
906
    // -- File lock support --
 
907
 
 
908
    /**
 
909
     * A simple file lock table that maintains a list of FileLocks obtained by a
 
910
     * FileChannel. Use to get 1.4/5.0 behaviour.
 
911
     */
 
912
    private static class SimpleFileLockTable extends FileLockTable {
 
913
        // synchronize on list for access
 
914
        private final List<FileLock> lockList = new ArrayList<FileLock>(2);
 
915
 
 
916
        public SimpleFileLockTable() {
 
917
        }
 
918
 
 
919
        private void checkList(long position, long size)
 
920
            throws OverlappingFileLockException
 
921
        {
 
922
            assert Thread.holdsLock(lockList);
 
923
            for (FileLock fl: lockList) {
 
924
                if (fl.overlaps(position, size)) {
 
925
                    throw new OverlappingFileLockException();
 
926
                }
 
927
            }
 
928
        }
 
929
 
 
930
        public void add(FileLock fl) throws OverlappingFileLockException {
 
931
            synchronized (lockList) {
 
932
                checkList(fl.position(), fl.size());
 
933
                lockList.add(fl);
 
934
            }
 
935
        }
 
936
 
 
937
        public void remove(FileLock fl) {
 
938
            synchronized (lockList) {
 
939
                lockList.remove(fl);
 
940
            }
 
941
        }
 
942
 
 
943
        public List<FileLock> removeAll() {
 
944
            synchronized(lockList) {
 
945
                List<FileLock> result = new ArrayList<FileLock>(lockList);
 
946
                lockList.clear();
 
947
                return result;
 
948
            }
 
949
        }
 
950
 
 
951
        public void replace(FileLock fl1, FileLock fl2) {
 
952
            synchronized (lockList) {
 
953
                lockList.remove(fl1);
 
954
                lockList.add(fl2);
 
955
            }
 
956
        }
 
957
    }
 
958
 
 
959
    // -- Native methods --
 
960
 
 
961
    // Creates a new mapping
 
962
    private long map0(int prot, long position, long length) throws IOException
 
963
    {
 
964
        FileStream fs = (FileStream)fd.getStream();
 
965
        if (win32)
 
966
            return mapViewOfFileWin32(fs, prot, position, length);
 
967
        else
 
968
            return mapViewOfFilePosix(fs, prot, position, length);
 
969
    }
 
970
 
 
971
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
972
    private static long mapViewOfFileWin32(FileStream fs, int prot, long position, long length) throws IOException
 
973
    {
 
974
        try
 
975
        {
 
976
            int PAGE_READONLY = 2;
 
977
            int PAGE_READWRITE = 4;
 
978
            int PAGE_WRITECOPY = 8;
 
979
            
 
980
            int FILE_MAP_WRITE = 2;
 
981
            int FILE_MAP_READ = 4;
 
982
            int FILE_MAP_COPY = 1;
 
983
 
 
984
            int fileProtect;
 
985
            int mapAccess;
 
986
 
 
987
            switch (prot)
 
988
            {
 
989
                case MAP_RO:
 
990
                    fileProtect = PAGE_READONLY;
 
991
                    mapAccess = FILE_MAP_READ;
 
992
                    break;
 
993
                case MAP_RW:
 
994
                    fileProtect = PAGE_READWRITE;
 
995
                    mapAccess = FILE_MAP_WRITE;
 
996
                    break;
 
997
                case MAP_PV:
 
998
                    fileProtect = PAGE_WRITECOPY;
 
999
                    mapAccess = FILE_MAP_COPY;
 
1000
                    break;
 
1001
                default:
 
1002
                    throw new Error();
 
1003
            }
 
1004
 
 
1005
            long maxSize = length + position;
 
1006
            SafeFileHandle hFileMapping = CreateFileMapping(fs.get_SafeFileHandle(), IntPtr.Zero, fileProtect, (int)(maxSize >> 32), (int)maxSize, null);
 
1007
            int err = cli.System.Runtime.InteropServices.Marshal.GetLastWin32Error();
 
1008
            if (hFileMapping.get_IsInvalid())
 
1009
            {
 
1010
                throw new IOException("Win32 error " + err);
 
1011
            }
 
1012
            IntPtr p = MapViewOfFile(hFileMapping, mapAccess, (int)(position >> 32), (int)position, IntPtr.op_Explicit(length));
 
1013
            err = cli.System.Runtime.InteropServices.Marshal.GetLastWin32Error();
 
1014
            hFileMapping.Close();
 
1015
            if (p.Equals(IntPtr.Zero))
 
1016
            {
 
1017
                if (err == 8 /*ERROR_NOT_ENOUGH_MEMORY*/)
 
1018
                {
 
1019
                    throw new OutOfMemoryError("Map failed");
 
1020
                }
 
1021
                throw new IOException("Win32 error " + err);
 
1022
            }
 
1023
            cli.System.GC.AddMemoryPressure(length);
 
1024
            return p.ToInt64();
 
1025
        }
 
1026
        finally
 
1027
        {
 
1028
            cli.System.GC.KeepAlive(fs);
 
1029
        }
 
1030
    }
 
1031
 
 
1032
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
1033
    private static long mapViewOfFilePosix(FileStream fs, int prot, long position, long length) throws IOException
 
1034
    {
 
1035
        byte writeable = prot != MAP_RO ? (byte)1 : (byte)0;
 
1036
        byte copy_on_write = prot == MAP_PV ? (byte)1 : (byte)0;
 
1037
        IntPtr p = ikvm_mmap(fs.get_SafeFileHandle(), writeable, copy_on_write, position, (int)length);
 
1038
        cli.System.GC.KeepAlive(fs);
 
1039
        // HACK ikvm_mmap should really be changed to return a null pointer on failure,
 
1040
        // instead of whatever MAP_FAILED is defined to on the particular system we're running on,
 
1041
        // common values for MAP_FAILED are 0 and -1, so we test for these.
 
1042
        if (p.Equals(IntPtr.Zero) || p.Equals(new IntPtr(-1)))
 
1043
        {
 
1044
            throw new IOException("file mapping failed");
 
1045
        }
 
1046
        cli.System.GC.AddMemoryPressure(length);
 
1047
        return p.ToInt64();
 
1048
    }
 
1049
 
 
1050
    @DllImportAttribute.Annotation(value="kernel32", SetLastError=true)
 
1051
    private static native SafeFileHandle CreateFileMapping(SafeFileHandle hFile, IntPtr lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, String lpName);
 
1052
 
 
1053
    @DllImportAttribute.Annotation(value="kernel32", SetLastError=true)
 
1054
    private static native IntPtr MapViewOfFile(SafeFileHandle hFileMapping, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, IntPtr dwNumberOfBytesToMap);
 
1055
 
 
1056
    @DllImportAttribute.Annotation("kernel32")
 
1057
    private static native int UnmapViewOfFile(IntPtr lpBaseAddress);
 
1058
 
 
1059
    @DllImportAttribute.Annotation("ikvm-native")
 
1060
    private static native int ikvm_munmap(IntPtr address, int size);
 
1061
 
 
1062
    @DllImportAttribute.Annotation("ikvm-native")
 
1063
    private static native IntPtr ikvm_mmap(SafeFileHandle handle, byte writeable, byte copy_on_write, long position, int size);
 
1064
 
 
1065
    // Removes an existing mapping
 
1066
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
1067
    static int unmap0(long address, long length)
 
1068
    {
 
1069
        if (win32)
 
1070
            UnmapViewOfFile(IntPtr.op_Explicit(address));
 
1071
        else
 
1072
            ikvm_munmap(IntPtr.op_Explicit(address), (int)length);
 
1073
        cli.System.GC.RemoveMemoryPressure(length);
 
1074
        return 0;
 
1075
    }
 
1076
 
 
1077
    // Sets or reports this file's position
 
1078
    // If offset is -1, the current position is returned
 
1079
    // otherwise the position is set to offset
 
1080
    private static long position0(FileDescriptor fd, long offset) throws IOException
 
1081
    {
 
1082
        if (offset == -1)
 
1083
        {
 
1084
            return fd.getFilePointer();
 
1085
        }
 
1086
        fd.seek(offset);
 
1087
        return offset;
 
1088
    }
 
1089
}