1/* 2 * Copyright (c) 2000, 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 26package java.nio.channels.spi; 27 28import java.io.IOException; 29import java.nio.channels.SelectionKey; 30import java.nio.channels.Selector; 31import java.util.HashSet; 32import java.util.Set; 33import sun.nio.ch.Interruptible; 34import 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: <a name="be"> 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 69public 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. </p> 80 */ 81 protected AbstractSelector(SelectorProvider provider) { 82 this.provider = provider; 83 } 84 85 private final Set<SelectionKey> cancelledKeys = new HashSet<SelectionKey>(); 86 87 void cancel(SelectionKey k) { // package-private 88 synchronized (cancelledKeys) { 89 cancelledKeys.add(k); 90 } 91 } 92 93 /** 94 * Closes this selector. 95 * 96 * <p> If the selector has already been closed then this method returns 97 * immediately. Otherwise it marks the selector as closed and then invokes 98 * the {@link #implCloseSelector implCloseSelector} method in order to 99 * complete the close operation. </p> 100 * 101 * @throws IOException 102 * If an I/O error occurs 103 */ 104 public final void close() throws IOException { 105 boolean open = selectorOpen.getAndSet(false); 106 if (!open) 107 return; 108 implCloseSelector(); 109 } 110 111 /** 112 * Closes this selector. 113 * 114 * <p> This method is invoked by the {@link #close close} method in order 115 * to perform the actual work of closing the selector. This method is only 116 * invoked if the selector has not yet been closed, and it is never invoked 117 * more than once. 118 * 119 * <p> An implementation of this method must arrange for any other thread 120 * that is blocked in a selection operation upon this selector to return 121 * immediately as if by invoking the {@link 122 * java.nio.channels.Selector#wakeup wakeup} method. </p> 123 * 124 * @throws IOException 125 * If an I/O error occurs while closing the selector 126 */ 127 protected abstract void implCloseSelector() throws IOException; 128 129 public final boolean isOpen() { 130 return selectorOpen.get(); 131 } 132 133 /** 134 * Returns the provider that created this channel. 135 * 136 * @return The provider that created this channel 137 */ 138 public final SelectorProvider provider() { 139 return provider; 140 } 141 142 /** 143 * Retrieves this selector's cancelled-key set. 144 * 145 * <p> This set should only be used while synchronized upon it. </p> 146 * 147 * @return The cancelled-key set 148 */ 149 protected final Set<SelectionKey> cancelledKeys() { 150 return cancelledKeys; 151 } 152 153 /** 154 * Registers the given channel with this selector. 155 * 156 * <p> This method is invoked by a channel's {@link 157 * AbstractSelectableChannel#register register} method in order to perform 158 * the actual work of registering the channel with this selector. </p> 159 * 160 * @param ch 161 * The channel to be registered 162 * 163 * @param ops 164 * The initial interest set, which must be valid 165 * 166 * @param att 167 * The initial attachment for the resulting key 168 * 169 * @return A new key representing the registration of the given channel 170 * with this selector 171 */ 172 protected abstract SelectionKey register(AbstractSelectableChannel ch, 173 int ops, Object att); 174 175 /** 176 * Removes the given key from its channel's key set. 177 * 178 * <p> This method must be invoked by the selector for each channel that it 179 * deregisters. </p> 180 * 181 * @param key 182 * The selection key to be removed 183 */ 184 protected final void deregister(AbstractSelectionKey key) { 185 ((AbstractSelectableChannel)key.channel()).removeKey(key); 186 } 187 188 189 // -- Interruption machinery -- 190 191 private Interruptible interruptor = null; 192 193 /** 194 * Marks the beginning of an I/O operation that might block indefinitely. 195 * 196 * <p> This method should be invoked in tandem with the {@link #end end} 197 * method, using a <tt>try</tt> ... <tt>finally</tt> block as 198 * shown <a href="#be">above</a>, in order to implement interruption for 199 * this selector. 200 * 201 * <p> Invoking this method arranges for the selector's {@link 202 * Selector#wakeup wakeup} method to be invoked if a thread's {@link 203 * Thread#interrupt interrupt} method is invoked while the thread is 204 * blocked in an I/O operation upon the selector. </p> 205 */ 206 protected final void begin() { 207 if (interruptor == null) { 208 interruptor = new Interruptible() { 209 public void interrupt(Thread ignore) { 210 AbstractSelector.this.wakeup(); 211 }}; 212 } 213 AbstractInterruptibleChannel.blockedOn(interruptor); 214 Thread me = Thread.currentThread(); 215 if (me.isInterrupted()) 216 interruptor.interrupt(me); 217 } 218 219 /** 220 * Marks the end of an I/O operation that might block indefinitely. 221 * 222 * <p> This method should be invoked in tandem with the {@link #begin begin} 223 * method, using a <tt>try</tt> ... <tt>finally</tt> block as 224 * shown <a href="#be">above</a>, in order to implement interruption for 225 * this selector. </p> 226 */ 227 protected final void end() { 228 AbstractInterruptibleChannel.blockedOn(null); 229 } 230 231} 232