Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2000, 2012, 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.*;
     29 import java.nio.ByteBuffer;
     30 import java.nio.channels.*;
     31 import java.nio.channels.spi.*;
     32 
     33 
     34 class SinkChannelImpl
     35     extends Pipe.SinkChannel
     36     implements SelChImpl
     37 {
     38 
     39     // Used to make native read and write calls
     40     private static NativeDispatcher nd;
     41 
     42     // The file descriptor associated with this channel
     43     FileDescriptor fd;
     44 
     45     // fd value needed for dev/poll. This value will remain valid
     46     // even after the value in the file descriptor object has been set to -1
     47     int fdVal;
     48 
     49     // ID of native thread doing write, for signalling
     50     private volatile long thread = 0;
     51 
     52     // Lock held by current reading thread
     53     private final Object lock = new Object();
     54 
     55     // Lock held by any thread that modifies the state fields declared below
     56     // DO NOT invoke a blocking I/O operation while holding this lock!
     57     private final Object stateLock = new Object();
     58 
     59     // -- The following fields are protected by stateLock
     60 
     61     // Channel state
     62     private static final int ST_UNINITIALIZED = -1;
     63     private static final int ST_INUSE = 0;
     64     private static final int ST_KILLED = 1;
     65     private volatile int state = ST_UNINITIALIZED;
     66 
     67     // -- End of fields protected by stateLock
     68 
     69 
     70     public FileDescriptor getFD() {
     71         return fd;
     72     }
     73 
     74     public int getFDVal() {
     75         return fdVal;
     76     }
     77 
     78     SinkChannelImpl(SelectorProvider sp, FileDescriptor fd) {
     79         super(sp);
     80         this.fd = fd;
     81         this.fdVal = IOUtil.fdVal(fd);
     82         this.state = ST_INUSE;
     83     }
     84 
     85     protected void implCloseSelectableChannel() throws IOException {
     86         synchronized (stateLock) {
     87             if (state != ST_KILLED)
     88                 nd.preClose(fd);
     89             long th = thread;
     90             if (th != 0)
     91                 NativeThread.signal(th);
     92             if (!isRegistered())
     93                 kill();
     94         }
     95     }
     96 
     97     public void kill() throws IOException {
     98         synchronized (stateLock) {
     99             if (state == ST_KILLED)
    100                 return;
    101             if (state == ST_UNINITIALIZED) {
    102                 state = ST_KILLED;
    103                 return;
    104             }
    105             assert !isOpen() && !isRegistered();
    106             nd.close(fd);
    107             state = ST_KILLED;
    108         }
    109     }
    110 
    111     protected void implConfigureBlocking(boolean block) throws IOException {
    112         IOUtil.configureBlocking(fd, block);
    113     }
    114 
    115     public boolean translateReadyOps(int ops, int initialOps,
    116                                      SelectionKeyImpl sk) {
    117         int intOps = sk.nioInterestOps();// Do this just once, it synchronizes
    118         int oldOps = sk.nioReadyOps();
    119         int newOps = initialOps;
    120 
    121         if ((ops & PollArrayWrapper.POLLNVAL) != 0)
    122             throw new Error("POLLNVAL detected");
    123 
    124         if ((ops & (PollArrayWrapper.POLLERR
    125                     | PollArrayWrapper.POLLHUP)) != 0) {
    126             newOps = intOps;
    127             sk.nioReadyOps(newOps);
    128             return (newOps & ~oldOps) != 0;
    129         }
    130 
    131         if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
    132             ((intOps & SelectionKey.OP_WRITE) != 0))
    133             newOps |= SelectionKey.OP_WRITE;
    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_WRITE)
    149             ops = PollArrayWrapper.POLLOUT;
    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 write(ByteBuffer src) throws IOException {
    159         ensureOpen();
    160         synchronized (lock) {
    161             int n = 0;
    162             try {
    163                 begin();
    164                 if (!isOpen())
    165                     return 0;
    166                 thread = NativeThread.current();
    167                 do {
    168                     n = IOUtil.write(fd, src, -1, nd);
    169                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    170                 return IOStatus.normalize(n);
    171             } finally {
    172                 thread = 0;
    173                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    174                 assert IOStatus.check(n);
    175             }
    176         }
    177     }
    178 
    179     public long write(ByteBuffer[] srcs) throws IOException {
    180         if (srcs == null)
    181             throw new NullPointerException();
    182         ensureOpen();
    183         synchronized (lock) {
    184             long n = 0;
    185             try {
    186                 begin();
    187                 if (!isOpen())
    188                     return 0;
    189                 thread = NativeThread.current();
    190                 do {
    191                     n = IOUtil.write(fd, srcs, nd);
    192                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    193                 return IOStatus.normalize(n);
    194             } finally {
    195                 thread = 0;
    196                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    197                 assert IOStatus.check(n);
    198             }
    199         }
    200     }
    201 
    202     public long write(ByteBuffer[] srcs, int offset, int length)
    203         throws IOException
    204     {
    205         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
    206            throw new IndexOutOfBoundsException();
    207         return write(Util.subsequence(srcs, offset, length));
    208     }
    209 
    210     static {
    211         nd = new FileDispatcherImpl();
    212     }
    213 
    214 }
    215