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

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/nio/ch/WindowsAsynchronousFileChannelImpl.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) 2008, 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 java.nio.channels.*;
 
29
import java.util.concurrent.*;
 
30
import java.nio.ByteBuffer;
 
31
import java.nio.BufferOverflowException;
 
32
import java.io.IOException;
 
33
import java.io.FileDescriptor;
 
34
import cli.System.AsyncCallback;
 
35
import cli.System.IAsyncResult;
 
36
import cli.System.IO.FileStream;
 
37
import cli.System.IO.SeekOrigin;
 
38
 
 
39
/**
 
40
 * Windows implementation of AsynchronousFileChannel using overlapped I/O.
 
41
 */
 
42
 
 
43
public class WindowsAsynchronousFileChannelImpl
 
44
    extends AsynchronousFileChannelImpl
 
45
    implements Groupable
 
46
{
 
47
    // error when EOF is detected asynchronously.
 
48
    private static final int ERROR_HANDLE_EOF = 38;
 
49
 
 
50
    // Lazy initialization of default I/O completion port
 
51
    private static class DefaultIocpHolder {
 
52
        static final Iocp defaultIocp = defaultIocp();
 
53
        private static Iocp defaultIocp() {
 
54
            try {
 
55
                return new Iocp(null, ThreadPool.createDefault()).start();
 
56
            } catch (IOException ioe) {
 
57
                InternalError e = new InternalError();
 
58
                e.initCause(ioe);
 
59
                throw e;
 
60
            }
 
61
        }
 
62
    }
 
63
 
 
64
    // Used for force/truncate/size methods
 
65
    private static final FileDispatcher nd = new FileDispatcherImpl();
 
66
 
 
67
    // I/O completion port (group)
 
68
    private final Iocp iocp;
 
69
 
 
70
    private final boolean isDefaultIocp;
 
71
 
 
72
 
 
73
    private WindowsAsynchronousFileChannelImpl(FileDescriptor fdObj,
 
74
                                               boolean reading,
 
75
                                               boolean writing,
 
76
                                               Iocp iocp,
 
77
                                               boolean isDefaultIocp)
 
78
        throws IOException
 
79
    {
 
80
        super(fdObj, reading, writing, iocp.executor());
 
81
        this.iocp = iocp;
 
82
        this.isDefaultIocp = isDefaultIocp;
 
83
    }
 
84
 
 
85
    public static AsynchronousFileChannel open(FileDescriptor fdo,
 
86
                                               boolean reading,
 
87
                                               boolean writing,
 
88
                                               ThreadPool pool)
 
89
        throws IOException
 
90
    {
 
91
        Iocp iocp;
 
92
        boolean isDefaultIocp;
 
93
        if (pool == null) {
 
94
            iocp = DefaultIocpHolder.defaultIocp;
 
95
            isDefaultIocp = true;
 
96
        } else {
 
97
            iocp = new Iocp(null, pool).start();
 
98
            isDefaultIocp = false;
 
99
        }
 
100
        try {
 
101
            return new
 
102
                WindowsAsynchronousFileChannelImpl(fdo, reading, writing, iocp, isDefaultIocp);
 
103
        } catch (IOException x) {
 
104
            // error binding to port so need to close it (if created for this channel)
 
105
            if (!isDefaultIocp)
 
106
                iocp.implClose();
 
107
            throw x;
 
108
        }
 
109
    }
 
110
 
 
111
    @Override
 
112
    public void close() throws IOException {
 
113
        closeLock.writeLock().lock();
 
114
        try {
 
115
            if (closed)
 
116
                return;     // already closed
 
117
            closed = true;
 
118
        } finally {
 
119
            closeLock.writeLock().unlock();
 
120
        }
 
121
 
 
122
        // invalidate all locks held for this channel
 
123
        invalidateAllLocks();
 
124
 
 
125
        // close the file
 
126
        fdObj.close();
 
127
 
 
128
        // for the non-default group close the port
 
129
        if (!isDefaultIocp)
 
130
            iocp.detachFromThreadPool();
 
131
    }
 
132
 
 
133
    @Override
 
134
    public AsynchronousChannelGroupImpl group() {
 
135
        return iocp;
 
136
    }
 
137
 
 
138
    /**
 
139
     * Translates Throwable to IOException
 
140
     */
 
141
    private static IOException toIOException(Throwable x) {
 
142
        if (x instanceof cli.System.ArgumentException) {
 
143
            return new IOException(x.getMessage());
 
144
        }
 
145
        if (x instanceof cli.System.IO.IOException) {
 
146
            return new IOException(x.getMessage());
 
147
        }
 
148
        if (x instanceof IOException) {
 
149
            if (x instanceof ClosedChannelException)
 
150
                x = new AsynchronousCloseException();
 
151
            return (IOException)x;
 
152
        }
 
153
        return new IOException(x);
 
154
    }
 
155
 
 
156
    @Override
 
157
    public long size() throws IOException {
 
158
        try {
 
159
            begin();
 
160
            return nd.size(fdObj);
 
161
        } finally {
 
162
            end();
 
163
        }
 
164
    }
 
165
 
 
166
    @Override
 
167
    public AsynchronousFileChannel truncate(long size) throws IOException {
 
168
        if (size < 0)
 
169
            throw new IllegalArgumentException("Negative size");
 
170
        if (!writing)
 
171
            throw new NonWritableChannelException();
 
172
        try {
 
173
            begin();
 
174
            if (size > nd.size(fdObj))
 
175
                return this;
 
176
            nd.truncate(fdObj, size);
 
177
        } finally {
 
178
            end();
 
179
        }
 
180
        return this;
 
181
    }
 
182
 
 
183
    @Override
 
184
    public void force(boolean metaData) throws IOException {
 
185
        try {
 
186
            begin();
 
187
            nd.force(fdObj, metaData);
 
188
        } finally {
 
189
            end();
 
190
        }
 
191
    }
 
192
 
 
193
    // -- file locking --
 
194
 
 
195
    /**
 
196
     * Task that initiates locking operation and handles completion result.
 
197
     */
 
198
    private class LockTask<A> implements Runnable, Iocp.ResultHandler {
 
199
        private final long position;
 
200
        private final FileLockImpl fli;
 
201
        private final PendingFuture<FileLock,A> result;
 
202
 
 
203
        LockTask(long position,
 
204
                 FileLockImpl fli,
 
205
                 PendingFuture<FileLock,A> result)
 
206
        {
 
207
            this.position = position;
 
208
            this.fli = fli;
 
209
            this.result = result;
 
210
        }
 
211
 
 
212
        @Override
 
213
        public void run() {
 
214
            FileStream fs = (FileStream)fdObj.getStream();
 
215
            for (;;) {
 
216
                try {
 
217
                    begin();
 
218
 
 
219
                    try {
 
220
                        if (false) throw new cli.System.IO.IOException();
 
221
                        fs.Lock(position, fli.size());
 
222
                        result.setResult(fli);
 
223
                        break;
 
224
                    } catch (cli.System.IO.IOException _) {
 
225
                        // we failed to acquire the lock, try again next iteration
 
226
                    }
 
227
                } catch (Throwable x) {
 
228
                    // lock failed or channel closed
 
229
                    removeFromFileLockTable(fli);
 
230
                    result.setFailure(toIOException(x));
 
231
                } finally {
 
232
                    end();
 
233
                }
 
234
                cli.System.Threading.Thread.Sleep(100);
 
235
            }
 
236
 
 
237
            // invoke completion handler
 
238
            Invoker.invoke(result);
 
239
        }
 
240
 
 
241
        @Override
 
242
        public void completed(int bytesTransferred, boolean canInvokeDirect) {
 
243
            // release waiters and invoke completion handler
 
244
            result.setResult(fli);
 
245
            if (canInvokeDirect) {
 
246
                Invoker.invokeUnchecked(result);
 
247
            } else {
 
248
                Invoker.invoke(result);
 
249
            }
 
250
        }
 
251
 
 
252
        @Override
 
253
        public void failed(int error, IOException x) {
 
254
            // lock not acquired so remove from lock table
 
255
            removeFromFileLockTable(fli);
 
256
 
 
257
            // release waiters
 
258
            if (isOpen()) {
 
259
                result.setFailure(x);
 
260
            } else {
 
261
                result.setFailure(new AsynchronousCloseException());
 
262
            }
 
263
            Invoker.invoke(result);
 
264
        }
 
265
    }
 
266
 
 
267
    @Override
 
268
    <A> Future<FileLock> implLock(final long position,
 
269
                                  final long size,
 
270
                                  final boolean shared,
 
271
                                  A attachment,
 
272
                                  final CompletionHandler<FileLock,? super A> handler)
 
273
    {
 
274
        if (shared && !reading)
 
275
            throw new NonReadableChannelException();
 
276
        if (!shared && !writing)
 
277
            throw new NonWritableChannelException();
 
278
 
 
279
        // add to lock table
 
280
        FileLockImpl fli = addToFileLockTable(position, size, shared);
 
281
        if (fli == null) {
 
282
            Throwable exc = new ClosedChannelException();
 
283
            if (handler == null)
 
284
                return CompletedFuture.withFailure(exc);
 
285
            Invoker.invoke(this, handler, attachment, null, exc);
 
286
            return null;
 
287
        }
 
288
 
 
289
        // create Future and task that will be invoked to acquire lock
 
290
        PendingFuture<FileLock,A> result =
 
291
            new PendingFuture<FileLock,A>(this, handler, attachment);
 
292
        LockTask lockTask = new LockTask<A>(position, fli, result);
 
293
        result.setContext(lockTask);
 
294
 
 
295
        // initiate I/O
 
296
        if (false) {
 
297
            lockTask.run();
 
298
        } else {
 
299
            boolean executed = false;
 
300
            try {
 
301
                Invoker.invokeOnThreadInThreadPool(this, lockTask);
 
302
                executed = true;
 
303
            } finally {
 
304
                if (!executed) {
 
305
                    // rollback
 
306
                    removeFromFileLockTable(fli);
 
307
                }
 
308
            }
 
309
        }
 
310
        return result;
 
311
    }
 
312
 
 
313
    static final int NO_LOCK = -1;       // Failed to lock
 
314
    static final int LOCKED = 0;         // Obtained requested lock
 
315
 
 
316
    @Override
 
317
    public FileLock tryLock(long position, long size, boolean shared)
 
318
        throws IOException
 
319
    {
 
320
        if (shared && !reading)
 
321
            throw new NonReadableChannelException();
 
322
        if (!shared && !writing)
 
323
            throw new NonWritableChannelException();
 
324
 
 
325
        // add to lock table
 
326
        final FileLockImpl fli = addToFileLockTable(position, size, shared);
 
327
        if (fli == null)
 
328
            throw new ClosedChannelException();
 
329
 
 
330
        boolean gotLock = false;
 
331
        try {
 
332
            begin();
 
333
            // try to acquire the lock
 
334
            int res;
 
335
            try {
 
336
                if (false) throw new cli.System.IO.IOException();
 
337
                FileStream fs = (FileStream)fdObj.getStream();
 
338
                fs.Lock(position, size);
 
339
                res = LOCKED;
 
340
            } catch (cli.System.IO.IOException _) {
 
341
                res = NO_LOCK;
 
342
            }
 
343
            if (res == NO_LOCK)
 
344
                return null;
 
345
            gotLock = true;
 
346
            return fli;
 
347
        } finally {
 
348
            if (!gotLock)
 
349
                removeFromFileLockTable(fli);
 
350
            end();
 
351
        }
 
352
    }
 
353
 
 
354
    @Override
 
355
    protected void implRelease(FileLockImpl fli) throws IOException {
 
356
        try {
 
357
            if (false) throw new cli.System.IO.IOException();
 
358
            FileStream fs = (FileStream)fdObj.getStream();
 
359
            fs.Unlock(fli.position(), fli.size());
 
360
        } catch (cli.System.IO.IOException x) {
 
361
            if (!FileDispatcherImpl.NotLockedHack.isErrorNotLocked(x)) {
 
362
                throw new IOException(x.getMessage());
 
363
            }
 
364
        }
 
365
    }
 
366
 
 
367
    /**
 
368
     * Task that initiates read operation and handles completion result.
 
369
     */
 
370
    private class ReadTask<A> implements Runnable, Iocp.ResultHandler, AsyncCallback.Method {
 
371
        private final ByteBuffer dst;
 
372
        private final int pos, rem;     // buffer position/remaining
 
373
        private final long position;    // file position
 
374
        private final PendingFuture<Integer,A> result;
 
375
 
 
376
        // set to dst if direct; otherwise set to substituted direct buffer
 
377
        private volatile ByteBuffer buf;
 
378
 
 
379
        ReadTask(ByteBuffer dst,
 
380
                 int pos,
 
381
                 int rem,
 
382
                 long position,
 
383
                 PendingFuture<Integer,A> result)
 
384
        {
 
385
            this.dst = dst;
 
386
            this.pos = pos;
 
387
            this.rem = rem;
 
388
            this.position = position;
 
389
            this.result = result;
 
390
        }
 
391
 
 
392
        void updatePosition(int bytesTransferred) {
 
393
            // if the I/O succeeded then adjust buffer position
 
394
            if (bytesTransferred > 0) {
 
395
                if (buf == dst) {
 
396
                    try {
 
397
                        dst.position(pos + bytesTransferred);
 
398
                    } catch (IllegalArgumentException x) {
 
399
                        // someone has changed the position; ignore
 
400
                    }
 
401
                } else {
 
402
                    // had to substitute direct buffer
 
403
                    buf.position(bytesTransferred).flip();
 
404
                    try {
 
405
                        dst.put(buf);
 
406
                    } catch (BufferOverflowException x) {
 
407
                        // someone has changed the position; ignore
 
408
                    }
 
409
                }
 
410
            }
 
411
        }
 
412
 
 
413
        @Override
 
414
        public void run() {
 
415
            // Substitute an array backed buffer if not
 
416
            if (dst.hasArray()) {
 
417
                buf = dst;
 
418
            } else {
 
419
                buf = ByteBuffer.allocate(rem);
 
420
            }
 
421
 
 
422
            try {
 
423
                begin();
 
424
 
 
425
                // initiate read
 
426
                FileStream fs = (FileStream)fdObj.getStream();
 
427
                fs.Seek(position, SeekOrigin.wrap(SeekOrigin.Begin));
 
428
                fs.BeginRead(buf.array(), buf.arrayOffset() + pos, rem, new AsyncCallback(this), null);
 
429
                return;
 
430
 
 
431
            } catch (Throwable x) {
 
432
                // failed to initiate read
 
433
                result.setFailure(toIOException(x));
 
434
            } finally {
 
435
                end();
 
436
            }
 
437
 
 
438
            // invoke completion handler
 
439
            Invoker.invoke(result);
 
440
        }
 
441
 
 
442
        public void Invoke(IAsyncResult ar) {
 
443
            try {
 
444
                FileStream fs = (FileStream)fdObj.getStream();
 
445
                completed(fs.EndRead(ar), false);
 
446
            } catch (Throwable x) {
 
447
                failed(0, toIOException(x));
 
448
            }
 
449
        }
 
450
 
 
451
        /**
 
452
         * Executed when the I/O has completed
 
453
         */
 
454
        @Override
 
455
        public void completed(int bytesTransferred, boolean canInvokeDirect) {
 
456
            updatePosition(bytesTransferred);
 
457
 
 
458
            // release waiters and invoke completion handler
 
459
            result.setResult(bytesTransferred);
 
460
            if (canInvokeDirect) {
 
461
                Invoker.invokeUnchecked(result);
 
462
            } else {
 
463
                Invoker.invoke(result);
 
464
            }
 
465
        }
 
466
 
 
467
        @Override
 
468
        public void failed(int error, IOException x) {
 
469
            // if EOF detected asynchronously then it is reported as error
 
470
            if (error == ERROR_HANDLE_EOF) {
 
471
                completed(-1, false);
 
472
            } else {
 
473
                // release waiters
 
474
                if (isOpen()) {
 
475
                    result.setFailure(x);
 
476
                } else {
 
477
                    result.setFailure(new AsynchronousCloseException());
 
478
                }
 
479
                Invoker.invoke(result);
 
480
            }
 
481
        }
 
482
    }
 
483
 
 
484
    @Override
 
485
    <A> Future<Integer> implRead(ByteBuffer dst,
 
486
                                 long position,
 
487
                                 A attachment,
 
488
                                 CompletionHandler<Integer,? super A> handler)
 
489
    {
 
490
        if (!reading)
 
491
            throw new NonReadableChannelException();
 
492
        if (position < 0)
 
493
            throw new IllegalArgumentException("Negative position");
 
494
        if (dst.isReadOnly())
 
495
            throw new IllegalArgumentException("Read-only buffer");
 
496
 
 
497
        // check if channel is closed
 
498
        if (!isOpen()) {
 
499
            Throwable exc = new ClosedChannelException();
 
500
            if (handler == null)
 
501
                return CompletedFuture.withFailure(exc);
 
502
            Invoker.invoke(this, handler, attachment, null, exc);
 
503
            return null;
 
504
        }
 
505
 
 
506
        int pos = dst.position();
 
507
        int lim = dst.limit();
 
508
        assert (pos <= lim);
 
509
        int rem = (pos <= lim ? lim - pos : 0);
 
510
 
 
511
        // no space remaining
 
512
        if (rem == 0) {
 
513
            if (handler == null)
 
514
                return CompletedFuture.withResult(0);
 
515
            Invoker.invoke(this, handler, attachment, 0, null);
 
516
            return null;
 
517
        }
 
518
 
 
519
        // create Future and task that initiates read
 
520
        PendingFuture<Integer,A> result =
 
521
            new PendingFuture<Integer,A>(this, handler, attachment);
 
522
        ReadTask readTask = new ReadTask<A>(dst, pos, rem, position, result);
 
523
        result.setContext(readTask);
 
524
 
 
525
        // initiate I/O
 
526
        if (Iocp.supportsThreadAgnosticIo()) {
 
527
            readTask.run();
 
528
        } else {
 
529
            Invoker.invokeOnThreadInThreadPool(this, readTask);
 
530
        }
 
531
        return result;
 
532
    }
 
533
 
 
534
    /**
 
535
     * Task that initiates write operation and handles completion result.
 
536
     */
 
537
    private class WriteTask<A> implements Runnable, Iocp.ResultHandler, AsyncCallback.Method {
 
538
        private final ByteBuffer src;
 
539
        private final int pos, rem;     // buffer position/remaining
 
540
        private final long position;    // file position
 
541
        private final PendingFuture<Integer,A> result;
 
542
 
 
543
        // set to src if direct; otherwise set to substituted direct buffer
 
544
        private volatile ByteBuffer buf;
 
545
 
 
546
        WriteTask(ByteBuffer src,
 
547
                  int pos,
 
548
                  int rem,
 
549
                  long position,
 
550
                  PendingFuture<Integer,A> result)
 
551
        {
 
552
            this.src = src;
 
553
            this.pos = pos;
 
554
            this.rem = rem;
 
555
            this.position = position;
 
556
            this.result = result;
 
557
        }
 
558
 
 
559
        void updatePosition(int bytesTransferred) {
 
560
            // if the I/O succeeded then adjust buffer position
 
561
            if (bytesTransferred > 0) {
 
562
                try {
 
563
                    src.position(pos + bytesTransferred);
 
564
                } catch (IllegalArgumentException x) {
 
565
                    // someone has changed the position
 
566
                }
 
567
            }
 
568
        }
 
569
 
 
570
        @Override
 
571
        public void run() {
 
572
            // Substitute an array backed buffer if not
 
573
            if (src.hasArray()) {
 
574
                buf = src;
 
575
            } else {
 
576
                buf = ByteBuffer.allocate(rem);
 
577
                buf.put(src);
 
578
                buf.flip();
 
579
                // temporarily restore position as we don't know how many bytes
 
580
                // will be written
 
581
                src.position(pos);
 
582
            }
 
583
 
 
584
            try {
 
585
                begin();
 
586
 
 
587
                // initiate the write
 
588
                FileStream fs = (FileStream)fdObj.getStream();
 
589
                fs.Seek(position, SeekOrigin.wrap(SeekOrigin.Begin));
 
590
                fs.BeginWrite(buf.array(), buf.arrayOffset() + pos, rem, new AsyncCallback(this), null);
 
591
                return;
 
592
 
 
593
            } catch (Throwable x) {
 
594
                // failed to initiate read:
 
595
                result.setFailure(toIOException(x));
 
596
 
 
597
            } finally {
 
598
                end();
 
599
            }
 
600
 
 
601
            // invoke completion handler
 
602
            Invoker.invoke(result);
 
603
        }
 
604
 
 
605
        public void Invoke(IAsyncResult ar) {
 
606
            try {
 
607
                FileStream fs = (FileStream)fdObj.getStream();
 
608
                fs.EndWrite(ar);
 
609
                completed(rem, false);
 
610
            } catch (Throwable x) {
 
611
                failed(0, toIOException(x));
 
612
            }
 
613
        }
 
614
 
 
615
        /**
 
616
         * Executed when the I/O has completed
 
617
         */
 
618
        @Override
 
619
        public void completed(int bytesTransferred, boolean canInvokeDirect) {
 
620
            updatePosition(bytesTransferred);
 
621
 
 
622
            // release waiters and invoke completion handler
 
623
            result.setResult(bytesTransferred);
 
624
            if (canInvokeDirect) {
 
625
                Invoker.invokeUnchecked(result);
 
626
            } else {
 
627
                Invoker.invoke(result);
 
628
            }
 
629
        }
 
630
 
 
631
        @Override
 
632
        public void failed(int error, IOException x) {
 
633
            // release waiters and invoker completion handler
 
634
            if (isOpen()) {
 
635
                result.setFailure(x);
 
636
            } else {
 
637
                result.setFailure(new AsynchronousCloseException());
 
638
            }
 
639
            Invoker.invoke(result);
 
640
        }
 
641
    }
 
642
 
 
643
    <A> Future<Integer> implWrite(ByteBuffer src,
 
644
                                  long position,
 
645
                                  A attachment,
 
646
                                  CompletionHandler<Integer,? super A> handler)
 
647
    {
 
648
        if (!writing)
 
649
            throw new NonWritableChannelException();
 
650
        if (position < 0)
 
651
            throw new IllegalArgumentException("Negative position");
 
652
 
 
653
        // check if channel is closed
 
654
        if (!isOpen()) {
 
655
           Throwable exc = new ClosedChannelException();
 
656
            if (handler == null)
 
657
                return CompletedFuture.withFailure(exc);
 
658
            Invoker.invoke(this, handler, attachment, null, exc);
 
659
            return null;
 
660
        }
 
661
 
 
662
        int pos = src.position();
 
663
        int lim = src.limit();
 
664
        assert (pos <= lim);
 
665
        int rem = (pos <= lim ? lim - pos : 0);
 
666
 
 
667
        // nothing to write
 
668
        if (rem == 0) {
 
669
            if (handler == null)
 
670
                return CompletedFuture.withResult(0);
 
671
            Invoker.invoke(this, handler, attachment, 0, null);
 
672
            return null;
 
673
        }
 
674
 
 
675
        // create Future and task to initiate write
 
676
        PendingFuture<Integer,A> result =
 
677
            new PendingFuture<Integer,A>(this, handler, attachment);
 
678
        WriteTask writeTask = new WriteTask<A>(src, pos, rem, position, result);
 
679
        result.setContext(writeTask);
 
680
 
 
681
        // initiate I/O
 
682
        if (Iocp.supportsThreadAgnosticIo()) {
 
683
            writeTask.run();
 
684
        } else {
 
685
            Invoker.invokeOnThreadInThreadPool(this, writeTask);
 
686
        }
 
687
        return result;
 
688
    }
 
689
}