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