]> gcc.gnu.org Git - gcc.git/blob - libjava/gnu/java/nio/SelectorImpl.java
239a5f8efa99296c2a44f0aa2930f5bda7eda922
[gcc.git] / libjava / gnu / java / nio / SelectorImpl.java
1 /* SelectorImpl.java --
2 Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package gnu.java.nio;
39
40 import java.io.IOException;
41 import java.nio.channels.ClosedSelectorException;
42 import java.nio.channels.SelectableChannel;
43 import java.nio.channels.SelectionKey;
44 import java.nio.channels.Selector;
45 import java.nio.channels.spi.AbstractSelectableChannel;
46 import java.nio.channels.spi.AbstractSelector;
47 import java.nio.channels.spi.SelectorProvider;
48 import java.util.Collections;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.Set;
52 import gnu.classpath.Configuration;
53
54 public class SelectorImpl extends AbstractSelector
55 {
56 static
57 {
58 // load the shared library needed for native methods.
59 if (Configuration.INIT_LOAD_LIBRARY)
60 {
61 System.loadLibrary ("javanio");
62 }
63 }
64
65 private Set keys;
66 private Set selected;
67
68 /**
69 * A dummy object whose monitor regulates access to both our
70 * selectThread and unhandledWakeup fields.
71 */
72 private Object selectThreadMutex = new Object ();
73
74 /**
75 * Any thread that's currently blocked in a select operation.
76 */
77 private Thread selectThread;
78
79 /**
80 * Indicates whether we have an unhandled wakeup call. This can
81 * be due to either wakeup() triggering a thread interruption while
82 * a thread was blocked in a select operation (in which case we need
83 * to reset this thread's interrupt status after interrupting the
84 * select), or else that no thread was on a select operation at the
85 * time that wakeup() was called, in which case the following select()
86 * operation should return immediately with nothing selected.
87 */
88 private boolean unhandledWakeup;
89
90 public SelectorImpl (SelectorProvider provider)
91 {
92 super (provider);
93
94 keys = new HashSet ();
95 selected = new HashSet ();
96 }
97
98 protected void finalize() throws Throwable
99 {
100 close();
101 }
102
103 protected final void implCloseSelector()
104 throws IOException
105 {
106 // Cancel any pending select operation.
107 wakeup();
108
109 synchronized (keys)
110 {
111 synchronized (selected)
112 {
113 synchronized (cancelledKeys ())
114 {
115 // FIXME: Release resources here.
116 }
117 }
118 }
119 }
120
121 public final Set keys()
122 {
123 if (!isOpen())
124 throw new ClosedSelectorException();
125
126 return Collections.unmodifiableSet (keys);
127 }
128
129 public final int selectNow()
130 throws IOException
131 {
132 // FIXME: We're simulating an immediate select
133 // via a select with a timeout of one millisecond.
134 return select (1);
135 }
136
137 public final int select()
138 throws IOException
139 {
140 return select (0);
141 }
142
143 // A timeout value of 0 means block forever.
144 private static native int implSelect (int[] read, int[] write,
145 int[] except, long timeout)
146 throws IOException;
147
148 private final int[] getFDsAsArray (int ops)
149 {
150 int[] result;
151 int counter = 0;
152 Iterator it = keys.iterator ();
153
154 // Count the number of file descriptors needed
155 while (it.hasNext ())
156 {
157 SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
158
159 if ((key.interestOps () & ops) != 0)
160 {
161 counter++;
162 }
163 }
164
165 result = new int[counter];
166
167 counter = 0;
168 it = keys.iterator ();
169
170 // Fill the array with the file descriptors
171 while (it.hasNext ())
172 {
173 SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
174
175 if ((key.interestOps () & ops) != 0)
176 {
177 result[counter] = key.getNativeFD();
178 counter++;
179 }
180 }
181
182 return result;
183 }
184
185 public synchronized int select (long timeout)
186 throws IOException
187 {
188 if (!isOpen())
189 throw new ClosedSelectorException();
190
191 synchronized (keys)
192 {
193 synchronized (selected)
194 {
195 deregisterCancelledKeys();
196
197 // Set only keys with the needed interest ops into the arrays.
198 int[] read = getFDsAsArray (SelectionKey.OP_READ
199 | SelectionKey.OP_ACCEPT);
200 int[] write = getFDsAsArray (SelectionKey.OP_WRITE
201 | SelectionKey.OP_CONNECT);
202
203 // FIXME: We dont need to check this yet
204 int[] except = new int [0];
205
206 // Test to see if we've got an unhandled wakeup call,
207 // in which case we return immediately. Otherwise,
208 // remember our current thread and jump into the select.
209 // The monitor for dummy object selectThreadMutex regulates
210 // access to these fields.
211
212 // FIXME: Not sure from the spec at what point we should
213 // return "immediately". Is it here or immediately upon
214 // entry to this function?
215
216 // NOTE: There's a possibility of another thread calling
217 // wakeup() immediately after our thread releases
218 // selectThreadMutex's monitor here, in which case we'll
219 // do the select anyway. Since calls to wakeup() and select()
220 // among different threads happen in non-deterministic order,
221 // I don't think this is an issue.
222 synchronized (selectThreadMutex)
223 {
224 if (unhandledWakeup)
225 {
226 unhandledWakeup = false;
227 return 0;
228 }
229 else
230 {
231 selectThread = Thread.currentThread ();
232 }
233 }
234
235 // Call the native select() on all file descriptors.
236 int result = 0;
237 try
238 {
239 begin();
240 result = implSelect (read, write, except, timeout);
241 }
242 finally
243 {
244 end();
245 }
246
247 // If our unhandled wakeup flag is set at this point,
248 // reset our thread's interrupt flag because we were
249 // awakened by wakeup() instead of an external thread
250 // interruption.
251 //
252 // NOTE: If we were blocked in a select() and one thread
253 // called Thread.interrupt() on the blocked thread followed
254 // by another thread calling Selector.wakeup(), then race
255 // conditions could make it so that the thread's interrupt
256 // flag is reset even though the Thread.interrupt() call
257 // "was there first". I don't think we need to care about
258 // this scenario.
259 synchronized (selectThreadMutex)
260 {
261 if (unhandledWakeup)
262 {
263 unhandledWakeup = false;
264 Thread.interrupted ();
265 }
266 selectThread = null;
267 }
268
269 Iterator it = keys.iterator ();
270
271 while (it.hasNext ())
272 {
273 int ops = 0;
274 SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
275
276 // If key is already selected retrieve old ready ops.
277 if (selected.contains (key))
278 {
279 ops = key.readyOps ();
280 }
281
282 // Set new ready read/accept ops
283 for (int i = 0; i < read.length; i++)
284 {
285 if (key.getNativeFD() == read[i])
286 {
287 if (key.channel () instanceof ServerSocketChannelImpl)
288 {
289 ops = ops | SelectionKey.OP_ACCEPT;
290 }
291 else
292 {
293 ops = ops | SelectionKey.OP_READ;
294 }
295 }
296 }
297
298 // Set new ready write ops
299 for (int i = 0; i < write.length; i++)
300 {
301 if (key.getNativeFD() == write[i])
302 {
303 ops = ops | SelectionKey.OP_WRITE;
304
305 // if (key.channel ().isConnected ())
306 // {
307 // ops = ops | SelectionKey.OP_WRITE;
308 // }
309 // else
310 // {
311 // ops = ops | SelectionKey.OP_CONNECT;
312 // }
313 }
314 }
315
316 // FIXME: We dont handle exceptional file descriptors yet.
317
318 // If key is not yet selected add it.
319 if (!selected.contains (key))
320 {
321 selected.add (key);
322 }
323
324 // Set new ready ops
325 key.readyOps (key.interestOps () & ops);
326 }
327 deregisterCancelledKeys();
328
329 return result;
330 }
331 }
332 }
333
334 public final Set selectedKeys()
335 {
336 if (!isOpen())
337 throw new ClosedSelectorException();
338
339 return selected;
340 }
341
342 public final Selector wakeup()
343 {
344 // IMPLEMENTATION NOTE: Whereas the specification says that
345 // thread interruption should trigger a call to wakeup, we
346 // do the reverse under the covers: wakeup triggers a thread
347 // interrupt followed by a subsequent reset of the thread's
348 // interrupt status within select().
349
350 // First, acquire the monitor of the object regulating
351 // access to our selectThread and unhandledWakeup fields.
352 synchronized (selectThreadMutex)
353 {
354 unhandledWakeup = true;
355
356 // Interrupt any thread which is currently blocked in
357 // a select operation.
358 if (selectThread != null)
359 selectThread.interrupt ();
360 }
361
362 return this;
363 }
364
365 private final void deregisterCancelledKeys()
366 {
367 Set ckeys = cancelledKeys ();
368 synchronized (ckeys)
369 {
370 Iterator it = ckeys.iterator();
371
372 while (it.hasNext ())
373 {
374 keys.remove ((SelectionKeyImpl) it.next ());
375 it.remove ();
376 }
377 }
378 }
379
380 protected SelectionKey register (SelectableChannel ch, int ops, Object att)
381 {
382 return register ((AbstractSelectableChannel) ch, ops, att);
383 }
384
385 protected final SelectionKey register (AbstractSelectableChannel ch, int ops,
386 Object att)
387 {
388 SelectionKeyImpl result;
389
390 if (ch instanceof SocketChannelImpl)
391 {
392 SocketChannelImpl sc = (SocketChannelImpl) ch;
393 result = new SocketChannelSelectionKey (ch, this);
394 }
395 else if (ch instanceof DatagramChannelImpl)
396 {
397 DatagramChannelImpl dc = (DatagramChannelImpl) ch;
398 result = new DatagramChannelSelectionKey (ch, this);
399 }
400 else if (ch instanceof ServerSocketChannelImpl)
401 {
402 ServerSocketChannelImpl ssc = (ServerSocketChannelImpl) ch;
403 result = new ServerSocketChannelSelectionKey (ch, this);
404 }
405 else
406 {
407 throw new InternalError ("No known channel type");
408 }
409
410 synchronized (keys)
411 {
412 keys.add (result);
413 }
414
415 result.interestOps (ops);
416 result.attach (att);
417 return result;
418 }
419 }
This page took 0.058179 seconds and 4 git commands to generate.