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