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