001 /*
002 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.nio.channels.spi;
027
028 import java.io.IOException;
029 import java.nio.channels.SelectionKey;
030 import java.nio.channels.Selector;
031 import java.util.HashSet;
032 import java.util.Set;
033 import sun.nio.ch.Interruptible;
034 import java.util.concurrent.atomic.AtomicBoolean;
035
036 /**
037 * Base implementation class for selectors.
038 *
039 * <p> This class encapsulates the low-level machinery required to implement
040 * the interruption of selection operations. A concrete selector class must
041 * invoke the {@link #begin begin} and {@link #end end} methods before and
042 * after, respectively, invoking an I/O operation that might block
043 * indefinitely. In order to ensure that the {@link #end end} method is always
044 * invoked, these methods should be used within a
045 * <tt>try</tt> ... <tt>finally</tt> block: <a name="be">
046 *
047 * <blockquote><pre>
048 * try {
049 * begin();
050 * // Perform blocking I/O operation here
051 * ...
052 * } finally {
053 * end();
054 * }</pre></blockquote>
055 *
056 * <p> This class also defines methods for maintaining a selector's
057 * cancelled-key set and for removing a key from its channel's key set, and
058 * declares the abstract {@link #register register} method that is invoked by a
059 * selectable channel's {@link AbstractSelectableChannel#register register}
060 * method in order to perform the actual work of registering a channel. </p>
061 *
062 *
063 * @author Mark Reinhold
064 * @author JSR-51 Expert Group
065 * @version 1.27, 07/05/05
066 * @since 1.4
067 */
068
069 public abstract class AbstractSelector extends Selector {
070
071 private AtomicBoolean selectorOpen = new AtomicBoolean(true);
072
073 // The provider that created this selector
074 private final SelectorProvider provider;
075
076 /**
077 * Initializes a new instance of this class. </p>
078 */
079 protected AbstractSelector(SelectorProvider provider) {
080 this .provider = provider;
081 }
082
083 private final Set cancelledKeys = new HashSet();
084
085 void cancel(SelectionKey k) { // package-private
086 synchronized (cancelledKeys) {
087 cancelledKeys.add(k);
088 }
089 }
090
091 /**
092 * Closes this selector.
093 *
094 * <p> If the selector has already been closed then this method returns
095 * immediately. Otherwise it marks the selector as closed and then invokes
096 * the {@link #implCloseSelector implCloseSelector} method in order to
097 * complete the close operation. </p>
098 *
099 * @throws IOException
100 * If an I/O error occurs
101 */
102 public final void close() throws IOException {
103 boolean open = selectorOpen.getAndSet(false);
104 if (!open)
105 return;
106 implCloseSelector();
107 }
108
109 /**
110 * Closes this selector.
111 *
112 * <p> This method is invoked by the {@link #close close} method in order
113 * to perform the actual work of closing the selector. This method is only
114 * invoked if the selector has not yet been closed, and it is never invoked
115 * more than once.
116 *
117 * <p> An implementation of this method must arrange for any other thread
118 * that is blocked in a selection operation upon this selector to return
119 * immediately as if by invoking the {@link
120 * java.nio.channels.Selector#wakeup wakeup} method. </p>
121 *
122 * @throws IOException
123 * If an I/O error occurs while closing the selector
124 */
125 protected abstract void implCloseSelector() throws IOException;
126
127 public final boolean isOpen() {
128 return selectorOpen.get();
129 }
130
131 /**
132 * Returns the provider that created this channel.
133 *
134 * @return The provider that created this channel
135 */
136 public final SelectorProvider provider() {
137 return provider;
138 }
139
140 /**
141 * Retrieves this selector's cancelled-key set.
142 *
143 * <p> This set should only be used while synchronized upon it. </p>
144 *
145 * @return The cancelled-key set
146 */
147 protected final Set<SelectionKey> cancelledKeys() {
148 return cancelledKeys;
149 }
150
151 /**
152 * Registers the given channel with this selector.
153 *
154 * <p> This method is invoked by a channel's {@link
155 * AbstractSelectableChannel#register register} method in order to perform
156 * the actual work of registering the channel with this selector. </p>
157 *
158 * @param ch
159 * The channel to be registered
160 *
161 * @param ops
162 * The initial interest set, which must be valid
163 *
164 * @param att
165 * The initial attachment for the resulting key
166 *
167 * @return A new key representing the registration of the given channel
168 * with this selector
169 */
170 protected abstract SelectionKey register(
171 AbstractSelectableChannel ch, int ops, Object att);
172
173 /**
174 * Removes the given key from its channel's key set.
175 *
176 * <p> This method must be invoked by the selector for each channel that it
177 * deregisters. </p>
178 *
179 * @param key
180 * The selection key to be removed
181 */
182 protected final void deregister(AbstractSelectionKey key) {
183 ((AbstractSelectableChannel) key.channel()).removeKey(key);
184 }
185
186 // -- Interruption machinery --
187
188 private Interruptible interruptor = null;
189
190 /**
191 * Marks the beginning of an I/O operation that might block indefinitely.
192 *
193 * <p> This method should be invoked in tandem with the {@link #end end}
194 * method, using a <tt>try</tt> ... <tt>finally</tt> block as
195 * shown <a href="#be">above</a>, in order to implement interruption for
196 * this selector.
197 *
198 * <p> Invoking this method arranges for the selector's {@link
199 * Selector#wakeup wakeup} method to be invoked if a thread's {@link
200 * Thread#interrupt interrupt} method is invoked while the thread is
201 * blocked in an I/O operation upon the selector. </p>
202 */
203 protected final void begin() {
204 if (interruptor == null) {
205 interruptor = new Interruptible() {
206 public void interrupt() {
207 AbstractSelector.this .wakeup();
208 }
209 };
210 }
211 AbstractInterruptibleChannel.blockedOn(interruptor);
212 if (Thread.currentThread().isInterrupted())
213 interruptor.interrupt();
214 }
215
216 /**
217 * Marks the end of an I/O operation that might block indefinitely.
218 *
219 * <p> This method should be invoked in tandem with the {@link #begin begin}
220 * method, using a <tt>try</tt> ... <tt>finally</tt> block as
221 * shown <a href="#be">above</a>, in order to implement interruption for
222 * this selector. </p>
223 */
224 protected final void end() {
225 AbstractInterruptibleChannel.blockedOn(null);
226 }
227
228 }
|