1 /* 2 * Copyright (c) 2001, 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.IOException; 29 import java.nio.channels.*; 30 import java.nio.channels.spi.*; 31 import java.util.*; 32 import java.util.function.Consumer; 33 34 35 /** 36 * An implementation of Selector for Solaris. 37 */ 38 class DevPollSelectorImpl 39 extends SelectorImpl 40 { 41 42 // File descriptors used for interrupt 43 protected int fd0; 44 protected int fd1; 45 46 // The poll object 47 DevPollArrayWrapper pollWrapper; 48 49 // Maps from file descriptors to keys 50 private Map<Integer,SelectionKeyImpl> fdToKey; 51 52 // True if this Selector has been closed 53 private boolean closed = false; 54 55 // Lock for interrupt triggering and clearing 56 private Object interruptLock = new Object(); 57 private boolean interruptTriggered = false; 58 59 /** 60 * Package private constructor called by factory method in 61 * the abstract superclass Selector. 62 */ 63 DevPollSelectorImpl(SelectorProvider sp) { 64 super(sp); 65 long pipeFds = IOUtil.makePipe(false); 66 fd0 = (int) (pipeFds >>> 32); 67 fd1 = (int) pipeFds; 68 pollWrapper = new DevPollArrayWrapper(); 69 pollWrapper.initInterrupt(fd0, fd1); 70 fdToKey = new HashMap<>(); 71 } 72 73 @Override 74 protected int doSelect(long timeout) throws IOException { 75 pollDevPollWrapper(timeout); 76 try { 77 return updateSelectedKeys(); 78 } finally { 79 clearWakeupPipeIfInterrupted(); 80 } 81 } 82 83 @Override 84 protected int doSelect(Consumer<SelectionKey> handler, long timeout) throws IOException { 85 pollDevPollWrapper(timeout); 86 try { 87 int entries = pollWrapper.updated; 88 int numKeysUpdated = 0; 89 for (int i=0; i<entries; i++) { 90 int nextFD = pollWrapper.getDescriptor(i); 91 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); 92 // ski is null in the case of an interrupt 93 if (ski != null) { 94 int rOps = pollWrapper.getReventOps(i); 95 ski.channel.translateAndSetReadyOps(rOps, ski); 96 if (ski.hasOps()) { 97 handler.accept(ski); 98 numKeysUpdated++; 99 } 100 } 101 } 102 return numKeysUpdated; 103 } finally { 104 clearWakeupPipeIfInterrupted(); 105 } 106 } 107 108 private void clearWakeupPipeIfInterrupted() throws IOException { 109 if (pollWrapper.interrupted()) { 110 // Clear the wakeup pipe 111 pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0); 112 synchronized (interruptLock) { 113 pollWrapper.clearInterrupted(); 114 IOUtil.drain(fd0); 115 interruptTriggered = false; 116 } 117 } 118 } 119 120 private void pollDevPollWrapper(long timeout) throws ClosedSelectorException, IOException { 121 if (closed) 122 throw new ClosedSelectorException(); 123 processDeregisterQueue(); 124 try { 125 begin(); 126 pollWrapper.poll(timeout); 127 } finally { 128 end(); 129 } 130 processDeregisterQueue(); 131 } 132 133 /** 134 * Update the keys whose fd's have been selected by the devpoll 135 * driver. Add the ready keys to the ready queue. 136 */ 137 private int updateSelectedKeys() { 138 int entries = pollWrapper.updated; 139 int numKeysUpdated = 0; 140 for (int i=0; i<entries; i++) { 141 int nextFD = pollWrapper.getDescriptor(i); 142 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); 143 // ski is null in the case of an interrupt 144 if (ski != null) { 145 int rOps = pollWrapper.getReventOps(i); 146 if (selectedKeys.contains(ski)) { 147 if (ski.channel.translateAndSetReadyOps(rOps, ski)) { 148 numKeysUpdated++; 149 } 150 } else { 151 ski.channel.translateAndSetReadyOps(rOps, ski); 152 if (ski.hasOps()) { 153 selectedKeys.add(ski); 154 numKeysUpdated++; 155 } 156 } 157 } 158 } 159 return numKeysUpdated; 160 } 161 162 protected void implClose() throws IOException { 163 if (closed) 164 return; 165 closed = true; 166 167 // prevent further wakeup 168 synchronized (interruptLock) { 169 interruptTriggered = true; 170 } 171 172 FileDispatcherImpl.closeIntFD(fd0); 173 FileDispatcherImpl.closeIntFD(fd1); 174 175 pollWrapper.release(fd0); 176 pollWrapper.closeDevPollFD(); 177 selectedKeys = null; 178 179 // Deregister channels 180 Iterator<SelectionKey> i = keys.iterator(); 181 while (i.hasNext()) { 182 SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); 183 deregister(ski); 184 SelectableChannel selch = ski.channel(); 185 if (!selch.isOpen() && !selch.isRegistered()) 186 ((SelChImpl)selch).kill(); 187 i.remove(); 188 } 189 fd0 = -1; 190 fd1 = -1; 191 } 192 193 protected void implRegister(SelectionKeyImpl ski) { 194 int fd = IOUtil.fdVal(ski.channel.getFD()); 195 fdToKey.put(Integer.valueOf(fd), ski); 196 keys.add(ski); 197 } 198 199 protected void implDereg(SelectionKeyImpl ski) throws IOException { 200 int i = ski.getIndex(); 201 assert (i >= 0); 202 int fd = ski.channel.getFDVal(); 203 fdToKey.remove(Integer.valueOf(fd)); 204 pollWrapper.release(fd); 205 ski.setIndex(-1); 206 keys.remove(ski); 207 selectedKeys.remove(ski); 208 deregister((AbstractSelectionKey)ski); 209 SelectableChannel selch = ski.channel(); 210 if (!selch.isOpen() && !selch.isRegistered()) 211 ((SelChImpl)selch).kill(); 212 } 213 214 public void putEventOps(SelectionKeyImpl sk, int ops) { 215 if (closed) 216 throw new ClosedSelectorException(); 217 int fd = IOUtil.fdVal(sk.channel.getFD()); 218 pollWrapper.setInterest(fd, ops); 219 } 220 221 public Selector wakeup() { 222 synchronized (interruptLock) { 223 if (!interruptTriggered) { 224 pollWrapper.interrupt(); 225 interruptTriggered = true; 226 } 227 } 228 return this; 229 } 230 }