1 /*
2  * Copyright (c) 2000, 2013, 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 final NativeDispatcher nd = new FileDispatcherImpl();
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 
getFD()70     public FileDescriptor getFD() {
71         return fd;
72     }
73 
getFDVal()74     public int getFDVal() {
75         return fdVal;
76     }
77 
SinkChannelImpl(SelectorProvider sp, FileDescriptor fd)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 
implCloseSelectableChannel()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 
kill()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 
implConfigureBlocking(boolean block)111     protected void implConfigureBlocking(boolean block) throws IOException {
112         IOUtil.configureBlocking(fd, block);
113     }
114 
translateReadyOps(int ops, int initialOps, SelectionKeyImpl sk)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 & Net.POLLNVAL) != 0)
122             throw new Error("POLLNVAL detected");
123 
124         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
125             newOps = intOps;
126             sk.nioReadyOps(newOps);
127             return (newOps & ~oldOps) != 0;
128         }
129 
130         if (((ops & Net.POLLOUT) != 0) &&
131             ((intOps & SelectionKey.OP_WRITE) != 0))
132             newOps |= SelectionKey.OP_WRITE;
133 
134         sk.nioReadyOps(newOps);
135         return (newOps & ~oldOps) != 0;
136     }
137 
translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk)138     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
139         return translateReadyOps(ops, sk.nioReadyOps(), sk);
140     }
141 
translateAndSetReadyOps(int ops, SelectionKeyImpl sk)142     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
143         return translateReadyOps(ops, 0, sk);
144     }
145 
translateAndSetInterestOps(int ops, SelectionKeyImpl sk)146     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
147         if (ops == SelectionKey.OP_WRITE)
148             ops = Net.POLLOUT;
149         sk.selector.putEventOps(sk, ops);
150     }
151 
ensureOpen()152     private void ensureOpen() throws IOException {
153         if (!isOpen())
154             throw new ClosedChannelException();
155     }
156 
write(ByteBuffer src)157     public int write(ByteBuffer src) throws IOException {
158         ensureOpen();
159         synchronized (lock) {
160             int n = 0;
161             try {
162                 begin();
163                 if (!isOpen())
164                     return 0;
165                 thread = NativeThread.current();
166                 do {
167                     n = IOUtil.write(fd, src, -1, nd);
168                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
169                 return IOStatus.normalize(n);
170             } finally {
171                 thread = 0;
172                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
173                 assert IOStatus.check(n);
174             }
175         }
176     }
177 
write(ByteBuffer[] srcs)178     public long write(ByteBuffer[] srcs) throws IOException {
179         if (srcs == null)
180             throw new NullPointerException();
181         ensureOpen();
182         synchronized (lock) {
183             long n = 0;
184             try {
185                 begin();
186                 if (!isOpen())
187                     return 0;
188                 thread = NativeThread.current();
189                 do {
190                     n = IOUtil.write(fd, srcs, nd);
191                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
192                 return IOStatus.normalize(n);
193             } finally {
194                 thread = 0;
195                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
196                 assert IOStatus.check(n);
197             }
198         }
199     }
200 
write(ByteBuffer[] srcs, int offset, int length)201     public long write(ByteBuffer[] srcs, int offset, int length)
202         throws IOException
203     {
204         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
205            throw new IndexOutOfBoundsException();
206         return write(Util.subsequence(srcs, offset, length));
207     }
208 }
209