|
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 */ |
|
84 protected AbstractSelector(SelectorProvider provider) { |
|
85 this.provider = provider; |
|
86 } |
|
87 |
|
88 private final Set<SelectionKey> cancelledKeys = new HashSet<SelectionKey>(); |
|
89 |
|
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 */ |
|
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 */ |
|
130 protected abstract void implCloseSelector() throws IOException; |
|
131 |
|
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 */ |
|
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 */ |
|
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 */ |
|
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 */ |
|
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 */ |
|
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 */ |
|
230 protected final void end() { |
|
231 AbstractInterruptibleChannel.blockedOn(null); |
|
232 } |
|
233 |
|
234 } |