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