1 /* 2 * Copyright (c) 2005, 2010, 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 sun.misc.*; 33 34 /** 35 * An implementation of Selector for Linux 2.6+ kernels that uses 36 * the epoll event notification facility. 37 */ 38 class EPollSelectorImpl 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 EPollArrayWrapper 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 volatile 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 EPollSelectorImpl(SelectorProvider sp) { 64 super(sp); 65 long pipeFds = IOUtil.makePipe(false); 66 fd0 = (int) (pipeFds >>> 32); 67 fd1 = (int) pipeFds; 68 pollWrapper = new EPollArrayWrapper(); 69 pollWrapper.initInterrupt(fd0, fd1); 70 fdToKey = new HashMap<Integer,SelectionKeyImpl>(); 71 } 72 73 protected int doSelect(long timeout) 74 throws IOException 75 { 76 if (closed) 77 throw new ClosedSelectorException(); 78 processDeregisterQueue(); 79 try { 80 begin(); 81 pollWrapper.poll(timeout); 82 } finally { 83 end(); 84 } 85 processDeregisterQueue(); 86 int numKeysUpdated = updateSelectedKeys(); 87 if (pollWrapper.interrupted()) { 88 // Clear the wakeup pipe 89 pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); 90 synchronized (interruptLock) { 91 pollWrapper.clearInterrupted(); 92 IOUtil.drain(fd0); 93 interruptTriggered = false; 94 } 95 } 96 return numKeysUpdated; 97 } 98 99 /** 100 * Update the keys whose fd's have been selected by the epoll. 101 * Add the ready keys to the ready queue. 102 */ 103 private int updateSelectedKeys() { 104 int entries = pollWrapper.updated; 105 int numKeysUpdated = 0; 106 for (int i=0; i<entries; i++) { 107 int nextFD = pollWrapper.getDescriptor(i); 108 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD)); 109 // ski is null in the case of an interrupt 110 if (ski != null) { 111 int rOps = pollWrapper.getEventOps(i); 112 if (selectedKeys.contains(ski)) { 113 if (ski.channel.translateAndSetReadyOps(rOps, ski)) { 114 numKeysUpdated++; 115 } 116 } else { 117 ski.channel.translateAndSetReadyOps(rOps, ski); 118 if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { 119 selectedKeys.add(ski); 120 numKeysUpdated++; 121 } 122 } 123 } 124 } 125 return numKeysUpdated; 126 } 127 128 protected void implClose() throws IOException { 129 if (closed) 130 return; 131 closed = true; 132 133 // prevent further wakeup 134 synchronized (interruptLock) { 135 interruptTriggered = true; 136 } 137 138 FileDispatcherImpl.closeIntFD(fd0); 139 FileDispatcherImpl.closeIntFD(fd1); 140 141 pollWrapper.closeEPollFD(); 142 // it is possible 143 selectedKeys = null; 144 145 // Deregister channels 146 Iterator<SelectionKey> i = keys.iterator(); 147 while (i.hasNext()) { 148 SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); 149 deregister(ski); 150 SelectableChannel selch = ski.channel(); 151 if (!selch.isOpen() && !selch.isRegistered()) 152 ((SelChImpl)selch).kill(); 153 i.remove(); 154 } 155 156 fd0 = -1; 157 fd1 = -1; 158 } 159 160 protected void implRegister(SelectionKeyImpl ski) { 161 if (closed) 162 throw new ClosedSelectorException(); 163 SelChImpl ch = ski.channel; 164 fdToKey.put(Integer.valueOf(ch.getFDVal()), ski); 165 pollWrapper.add(ch); 166 keys.add(ski); 167 } 168 169 protected void implDereg(SelectionKeyImpl ski) throws IOException { 170 assert (ski.getIndex() >= 0); 171 SelChImpl ch = ski.channel; 172 int fd = ch.getFDVal(); 173 fdToKey.remove(Integer.valueOf(fd)); 174 pollWrapper.release(ch); 175 ski.setIndex(-1); 176 keys.remove(ski); 177 selectedKeys.remove(ski); 178 deregister((AbstractSelectionKey)ski); 179 SelectableChannel selch = ski.channel(); 180 if (!selch.isOpen() && !selch.isRegistered()) 181 ((SelChImpl)selch).kill(); 182 } 183 184 void putEventOps(SelectionKeyImpl sk, int ops) { 185 if (closed) 186 throw new ClosedSelectorException(); 187 pollWrapper.setInterest(sk.channel, ops); 188 } 189 190 public Selector wakeup() { 191 synchronized (interruptLock) { 192 if (!interruptTriggered) { 193 pollWrapper.interrupt(); 194 interruptTriggered = true; 195 } 196 } 197 return this; 198 } 199 200 static { 201 Util.load(); 202 } 203 204 }