Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package sun.nio.ch;
     28 
     29 import java.io.*;
     30 import java.nio.ByteBuffer;
     31 import java.nio.channels.*;
     32 import java.nio.channels.spi.*;
     33 
     34 
     35 class SourceChannelImpl
     36     extends Pipe.SourceChannel
     37     implements SelChImpl
     38 {
     39 
     40     // Used to make native read and write calls
     41     private static final NativeDispatcher nd = new FileDispatcherImpl();
     42 
     43     // The file descriptor associated with this channel
     44     FileDescriptor fd;
     45 
     46     // fd value needed for dev/poll. This value will remain valid
     47     // even after the value in the file descriptor object has been set to -1
     48     int fdVal;
     49 
     50     // ID of native thread doing read, for signalling
     51     private volatile long thread = 0;
     52 
     53     // Lock held by current reading thread
     54     private final Object lock = new Object();
     55 
     56     // Lock held by any thread that modifies the state fields declared below
     57     // DO NOT invoke a blocking I/O operation while holding this lock!
     58     private final Object stateLock = new Object();
     59 
     60     // -- The following fields are protected by stateLock
     61 
     62     // Channel state
     63     private static final int ST_UNINITIALIZED = -1;
     64     private static final int ST_INUSE = 0;
     65     private static final int ST_KILLED = 1;
     66     private volatile int state = ST_UNINITIALIZED;
     67 
     68     // -- End of fields protected by stateLock
     69 
     70 
     71     public FileDescriptor getFD() {
     72         return fd;
     73     }
     74 
     75     public int getFDVal() {
     76         return fdVal;
     77     }
     78 
     79     SourceChannelImpl(SelectorProvider sp, FileDescriptor fd) {
     80         super(sp);
     81         this.fd = fd;
     82         this.fdVal = IOUtil.fdVal(fd);
     83         this.state = ST_INUSE;
     84     }
     85 
     86     protected void implCloseSelectableChannel() throws IOException {
     87         synchronized (stateLock) {
     88             if (state != ST_KILLED)
     89                 nd.preClose(fd);
     90             long th = thread;
     91             if (th != 0)
     92                 NativeThread.signal(th);
     93             if (!isRegistered())
     94                 kill();
     95         }
     96     }
     97 
     98     public void kill() throws IOException {
     99         synchronized (stateLock) {
    100             if (state == ST_KILLED)
    101                 return;
    102             if (state == ST_UNINITIALIZED) {
    103                 state = ST_KILLED;
    104                 return;
    105             }
    106             assert !isOpen() && !isRegistered();
    107             nd.close(fd);
    108             state = ST_KILLED;
    109         }
    110     }
    111 
    112     protected void implConfigureBlocking(boolean block) throws IOException {
    113         IOUtil.configureBlocking(fd, block);
    114     }
    115 
    116     public boolean translateReadyOps(int ops, int initialOps,
    117                                      SelectionKeyImpl sk) {
    118         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
    119         int oldOps = sk.nioReadyOps();
    120         int newOps = initialOps;
    121 
    122         if ((ops & Net.POLLNVAL) != 0)
    123             throw new Error("POLLNVAL detected");
    124 
    125         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
    126             newOps = intOps;
    127             sk.nioReadyOps(newOps);
    128             return (newOps & ~oldOps) != 0;
    129         }
    130 
    131         if (((ops & Net.POLLIN) != 0) &&
    132             ((intOps & SelectionKey.OP_READ) != 0))
    133             newOps |= SelectionKey.OP_READ;
    134 
    135         sk.nioReadyOps(newOps);
    136         return (newOps & ~oldOps) != 0;
    137     }
    138 
    139     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
    140         return translateReadyOps(ops, sk.nioReadyOps(), sk);
    141     }
    142 
    143     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
    144         return translateReadyOps(ops, 0, sk);
    145     }
    146 
    147     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
    148         if (ops == SelectionKey.OP_READ)
    149             ops = Net.POLLIN;
    150         sk.selector.putEventOps(sk, ops);
    151     }
    152 
    153     private void ensureOpen() throws IOException {
    154         if (!isOpen())
    155             throw new ClosedChannelException();
    156     }
    157 
    158     public int read(ByteBuffer dst) throws IOException {
    159         if (dst == null) {
    160             throw new NullPointerException();
    161         }
    162         ensureOpen();
    163         synchronized (lock) {
    164             int n = 0;
    165             try {
    166                 begin();
    167                 if (!isOpen())
    168                     return 0;
    169                 thread = NativeThread.current();
    170                 do {
    171                     n = IOUtil.read(fd, dst, -1, nd);
    172                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    173                 return IOStatus.normalize(n);
    174             } finally {
    175                 thread = 0;
    176                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    177                 assert IOStatus.check(n);
    178             }
    179         }
    180     }
    181 
    182     public long read(ByteBuffer[] dsts, int offset, int length)
    183         throws IOException
    184     {
    185         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
    186            throw new IndexOutOfBoundsException();
    187         return read(Util.subsequence(dsts, offset, length));
    188     }
    189 
    190     public long read(ByteBuffer[] dsts) throws IOException {
    191         if (dsts == null)
    192             throw new NullPointerException();
    193         ensureOpen();
    194         synchronized (lock) {
    195             long n = 0;
    196             try {
    197                 begin();
    198                 if (!isOpen())
    199                     return 0;
    200                 thread = NativeThread.current();
    201                 do {
    202                     n = IOUtil.read(fd, dsts, nd);
    203                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    204                 return IOStatus.normalize(n);
    205             } finally {
    206                 thread = 0;
    207                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    208                 assert IOStatus.check(n);
    209             }
    210         }
    211     }
    212 }
    213