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 // Android-added: Throw NPE if null ByteBuffer passed to read(). 160 if (dst == null) { 161 throw new NullPointerException(); 162 } 163 ensureOpen(); 164 synchronized (lock) { 165 int n = 0; 166 try { 167 begin(); 168 if (!isOpen()) 169 return 0; 170 thread = NativeThread.current(); 171 do { 172 n = IOUtil.read(fd, dst, -1, nd); 173 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 174 return IOStatus.normalize(n); 175 } finally { 176 thread = 0; 177 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 178 assert IOStatus.check(n); 179 } 180 } 181 } 182 read(ByteBuffer[] dsts, int offset, int length)183 public long read(ByteBuffer[] dsts, int offset, int length) 184 throws IOException 185 { 186 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 187 throw new IndexOutOfBoundsException(); 188 return read(Util.subsequence(dsts, offset, length)); 189 } 190 read(ByteBuffer[] dsts)191 public long read(ByteBuffer[] dsts) throws IOException { 192 if (dsts == null) 193 throw new NullPointerException(); 194 ensureOpen(); 195 synchronized (lock) { 196 long n = 0; 197 try { 198 begin(); 199 if (!isOpen()) 200 return 0; 201 thread = NativeThread.current(); 202 do { 203 n = IOUtil.read(fd, dsts, nd); 204 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 205 return IOStatus.normalize(n); 206 } finally { 207 thread = 0; 208 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 209 assert IOStatus.check(n); 210 } 211 } 212 } 213 } 214