1 /* 2 * Copyright (c) 2000, 2019, 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 java.nio.channels.spi; 27 28 import java.io.IOException; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.VarHandle; 31 import java.nio.channels.SelectionKey; 32 import java.nio.channels.Selector; 33 import java.util.HashSet; 34 import java.util.Set; 35 import sun.nio.ch.Interruptible; 36 import sun.nio.ch.SelectorImpl; 37 38 39 /** 40 * Base implementation class for selectors. 41 * 42 * <p> This class encapsulates the low-level machinery required to implement 43 * the interruption of selection operations. A concrete selector class must 44 * invoke the {@link #begin begin} and {@link #end end} methods before and 45 * after, respectively, invoking an I/O operation that might block 46 * indefinitely. In order to ensure that the {@link #end end} method is always 47 * invoked, these methods should be used within a 48 * {@code try} ... {@code finally} block: 49 * 50 * <blockquote><pre id="be"> 51 * try { 52 * begin(); 53 * // Perform blocking I/O operation here 54 * ... 55 * } finally { 56 * end(); 57 * }</pre></blockquote> 58 * 59 * <p> This class also defines methods for maintaining a selector's 60 * cancelled-key set and for removing a key from its channel's key set, and 61 * declares the abstract {@link #register register} method that is invoked by a 62 * selectable channel's {@link AbstractSelectableChannel#register register} 63 * method in order to perform the actual work of registering a channel. </p> 64 * 65 * 66 * @author Mark Reinhold 67 * @author JSR-51 Expert Group 68 * @since 1.4 69 */ 70 71 public abstract class AbstractSelector 72 extends Selector 73 { 74 private static final VarHandle CLOSED; 75 static { 76 try { 77 MethodHandles.Lookup l = MethodHandles.lookup(); 78 CLOSED = l.findVarHandle(AbstractSelector.class, "closed", boolean.class); 79 } catch (Exception e) { 80 throw new InternalError(e); 81 } 82 } 83 private volatile boolean closed; 84 85 // The provider that created this selector 86 private final SelectorProvider provider; 87 88 // cancelled-key, not used by the JDK Selector implementations 89 private final Set<SelectionKey> cancelledKeys; 90 91 /** 92 * Initializes a new instance of this class. 93 * 94 * @param provider 95 * The provider that created this selector 96 */ AbstractSelector(SelectorProvider provider)97 protected AbstractSelector(SelectorProvider provider) { 98 this.provider = provider; 99 if (this instanceof SelectorImpl) { 100 // not used in JDK Selector implementations 101 this.cancelledKeys = Set.of(); 102 } else { 103 this.cancelledKeys = new HashSet<>(); 104 } 105 } 106 cancel(SelectionKey k)107 void cancel(SelectionKey k) { // package-private 108 synchronized (cancelledKeys) { 109 cancelledKeys.add(k); 110 } 111 } 112 113 /** 114 * Closes this selector. 115 * 116 * <p> If the selector has already been closed then this method returns 117 * immediately. Otherwise it marks the selector as closed and then invokes 118 * the {@link #implCloseSelector implCloseSelector} method in order to 119 * complete the close operation. </p> 120 * 121 * @throws IOException 122 * If an I/O error occurs 123 */ close()124 public final void close() throws IOException { 125 boolean changed = (boolean) CLOSED.compareAndSet(this, false, true); 126 if (changed) { 127 implCloseSelector(); 128 } 129 } 130 131 /** 132 * Closes this selector. 133 * 134 * <p> This method is invoked by the {@link #close close} method in order 135 * to perform the actual work of closing the selector. This method is only 136 * invoked if the selector has not yet been closed, and it is never invoked 137 * more than once. 138 * 139 * <p> An implementation of this method must arrange for any other thread 140 * that is blocked in a selection operation upon this selector to return 141 * immediately as if by invoking the {@link 142 * java.nio.channels.Selector#wakeup wakeup} method. </p> 143 * 144 * @throws IOException 145 * If an I/O error occurs while closing the selector 146 */ implCloseSelector()147 protected abstract void implCloseSelector() throws IOException; 148 isOpen()149 public final boolean isOpen() { 150 return !closed; 151 } 152 153 /** 154 * Returns the provider that created this channel. 155 * 156 * @return The provider that created this channel 157 */ provider()158 public final SelectorProvider provider() { 159 return provider; 160 } 161 162 /** 163 * Retrieves this selector's cancelled-key set. 164 * 165 * <p> This set should only be used while synchronized upon it. </p> 166 * 167 * @return The cancelled-key set 168 */ cancelledKeys()169 protected final Set<SelectionKey> cancelledKeys() { 170 return cancelledKeys; 171 } 172 173 /** 174 * Registers the given channel with this selector. 175 * 176 * <p> This method is invoked by a channel's {@link 177 * AbstractSelectableChannel#register register} method in order to perform 178 * the actual work of registering the channel with this selector. </p> 179 * 180 * @param ch 181 * The channel to be registered 182 * 183 * @param ops 184 * The initial interest set, which must be valid 185 * 186 * @param att 187 * The initial attachment for the resulting key 188 * 189 * @return A new key representing the registration of the given channel 190 * with this selector 191 */ register(AbstractSelectableChannel ch, int ops, Object att)192 protected abstract SelectionKey register(AbstractSelectableChannel ch, 193 int ops, Object att); 194 195 /** 196 * Removes the given key from its channel's key set. 197 * 198 * <p> This method must be invoked by the selector for each channel that it 199 * deregisters. </p> 200 * 201 * @param key 202 * The selection key to be removed 203 */ deregister(AbstractSelectionKey key)204 protected final void deregister(AbstractSelectionKey key) { 205 ((AbstractSelectableChannel)key.channel()).removeKey(key); 206 } 207 208 209 // -- Interruption machinery -- 210 211 private Interruptible interruptor = null; 212 213 /** 214 * Marks the beginning of an I/O operation that might block indefinitely. 215 * 216 * <p> This method should be invoked in tandem with the {@link #end end} 217 * method, using a {@code try} ... {@code finally} block as 218 * shown <a href="#be">above</a>, in order to implement interruption for 219 * this selector. 220 * 221 * <p> Invoking this method arranges for the selector's {@link 222 * Selector#wakeup wakeup} method to be invoked if a thread's {@link 223 * Thread#interrupt interrupt} method is invoked while the thread is 224 * blocked in an I/O operation upon the selector. </p> 225 */ begin()226 protected final void begin() { 227 if (interruptor == null) { 228 interruptor = new Interruptible() { 229 public void interrupt(Thread ignore) { 230 AbstractSelector.this.wakeup(); 231 }}; 232 } 233 AbstractInterruptibleChannel.blockedOn(interruptor); 234 Thread me = Thread.currentThread(); 235 if (me.isInterrupted()) 236 interruptor.interrupt(me); 237 } 238 239 /** 240 * Marks the end of an I/O operation that might block indefinitely. 241 * 242 * <p> This method should be invoked in tandem with the {@link #begin begin} 243 * method, using a {@code try} ... {@code finally} block as 244 * shown <a href="#be">above</a>, in order to implement interruption for 245 * this selector. </p> 246 */ end()247 protected final void end() { 248 AbstractInterruptibleChannel.blockedOn(null); 249 } 250 251 } 252