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 
getFD()71     public FileDescriptor getFD() {
72         return fd;
73     }
74 
getFDVal()75     public int getFDVal() {
76         return fdVal;
77     }
78 
SourceChannelImpl(SelectorProvider sp, FileDescriptor fd)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 
implCloseSelectableChannel()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 
kill()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 
implConfigureBlocking(boolean block)112     protected void implConfigureBlocking(boolean block) throws IOException {
113         IOUtil.configureBlocking(fd, block);
114     }
115 
translateReadyOps(int ops, int initialOps, SelectionKeyImpl sk)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 
translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk)139     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
140         return translateReadyOps(ops, sk.nioReadyOps(), sk);
141     }
142 
translateAndSetReadyOps(int ops, SelectionKeyImpl sk)143     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
144         return translateReadyOps(ops, 0, sk);
145     }
146 
translateAndSetInterestOps(int ops, SelectionKeyImpl sk)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 
ensureOpen()153     private void ensureOpen() throws IOException {
154         if (!isOpen())
155             throw new ClosedChannelException();
156     }
157 
read(ByteBuffer dst)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 
read(ByteBuffer[] dsts, int offset, int length)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 
read(ByteBuffer[] dsts)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