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