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