1 /* SelectorImpl.java --
2 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
41 import java
.io
.IOException
;
42 import java
.nio
.channels
.ClosedSelectorException
;
43 import java
.nio
.channels
.SelectableChannel
;
44 import java
.nio
.channels
.SelectionKey
;
45 import java
.nio
.channels
.Selector
;
46 import java
.nio
.channels
.spi
.AbstractSelectableChannel
;
47 import java
.nio
.channels
.spi
.AbstractSelector
;
48 import java
.nio
.channels
.spi
.SelectorProvider
;
49 import java
.util
.Collections
;
50 import java
.util
.HashSet
;
51 import java
.util
.Iterator
;
54 public class SelectorImpl
extends AbstractSelector
60 * A dummy object whose monitor regulates access to both our
61 * selectThread and unhandledWakeup fields.
63 private Object selectThreadMutex
= new Object ();
66 * Any thread that's currently blocked in a select operation.
68 private Thread selectThread
;
71 * Indicates whether we have an unhandled wakeup call. This can
72 * be due to either wakeup() triggering a thread interruption while
73 * a thread was blocked in a select operation (in which case we need
74 * to reset this thread's interrupt status after interrupting the
75 * select), or else that no thread was on a select operation at the
76 * time that wakeup() was called, in which case the following select()
77 * operation should return immediately with nothing selected.
79 private boolean unhandledWakeup
;
81 public SelectorImpl (SelectorProvider provider
)
85 keys
= new HashSet ();
86 selected
= new HashSet ();
89 protected void finalize() throws Throwable
94 protected final void implCloseSelector()
97 // Cancel any pending select operation.
102 synchronized (selected
)
104 synchronized (cancelledKeys ())
106 // FIXME: Release resources here.
112 public final Set
keys()
115 throw new ClosedSelectorException();
117 return Collections
.unmodifiableSet (keys
);
120 public final int selectNow()
123 // FIXME: We're simulating an immediate select
124 // via a select with a timeout of one millisecond.
128 public final int select()
134 private final int[] getFDsAsArray (int ops
)
138 Iterator it
= keys
.iterator ();
140 // Count the number of file descriptors needed
141 while (it
.hasNext ())
143 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
145 if ((key
.interestOps () & ops
) != 0)
151 result
= new int[counter
];
154 it
= keys
.iterator ();
156 // Fill the array with the file descriptors
157 while (it
.hasNext ())
159 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
161 if ((key
.interestOps () & ops
) != 0)
163 result
[counter
] = key
.getNativeFD();
171 public synchronized int select (long timeout
)
175 throw new ClosedSelectorException();
179 synchronized (selected
)
181 deregisterCancelledKeys();
183 // Set only keys with the needed interest ops into the arrays.
184 int[] read
= getFDsAsArray (SelectionKey
.OP_READ
185 | SelectionKey
.OP_ACCEPT
);
186 int[] write
= getFDsAsArray (SelectionKey
.OP_WRITE
187 | SelectionKey
.OP_CONNECT
);
189 // FIXME: We dont need to check this yet
190 int[] except
= new int [0];
192 // Test to see if we've got an unhandled wakeup call,
193 // in which case we return immediately. Otherwise,
194 // remember our current thread and jump into the select.
195 // The monitor for dummy object selectThreadMutex regulates
196 // access to these fields.
198 // FIXME: Not sure from the spec at what point we should
199 // return "immediately". Is it here or immediately upon
200 // entry to this function?
202 // NOTE: There's a possibility of another thread calling
203 // wakeup() immediately after our thread releases
204 // selectThreadMutex's monitor here, in which case we'll
205 // do the select anyway. Since calls to wakeup() and select()
206 // among different threads happen in non-deterministic order,
207 // I don't think this is an issue.
208 synchronized (selectThreadMutex
)
212 unhandledWakeup
= false;
217 selectThread
= Thread
.currentThread ();
221 // Call the native select() on all file descriptors.
226 result
= VMSelector
.select (read
, write
, except
, timeout
);
233 // If our unhandled wakeup flag is set at this point,
234 // reset our thread's interrupt flag because we were
235 // awakened by wakeup() instead of an external thread
238 // NOTE: If we were blocked in a select() and one thread
239 // called Thread.interrupt() on the blocked thread followed
240 // by another thread calling Selector.wakeup(), then race
241 // conditions could make it so that the thread's interrupt
242 // flag is reset even though the Thread.interrupt() call
243 // "was there first". I don't think we need to care about
245 synchronized (selectThreadMutex
)
249 unhandledWakeup
= false;
250 Thread
.interrupted ();
255 Iterator it
= keys
.iterator ();
257 while (it
.hasNext ())
260 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
262 // If key is already selected retrieve old ready ops.
263 if (selected
.contains (key
))
265 ops
= key
.readyOps ();
268 // Set new ready read/accept ops
269 for (int i
= 0; i
< read
.length
; i
++)
271 if (key
.getNativeFD() == read
[i
])
273 if (key
.channel () instanceof ServerSocketChannelImpl
)
275 ops
= ops
| SelectionKey
.OP_ACCEPT
;
279 ops
= ops
| SelectionKey
.OP_READ
;
284 // Set new ready write ops
285 for (int i
= 0; i
< write
.length
; i
++)
287 if (key
.getNativeFD() == write
[i
])
289 ops
= ops
| SelectionKey
.OP_WRITE
;
291 // if (key.channel ().isConnected ())
293 // ops = ops | SelectionKey.OP_WRITE;
297 // ops = ops | SelectionKey.OP_CONNECT;
302 // FIXME: We dont handle exceptional file descriptors yet.
304 // If key is not yet selected add it.
305 if (!selected
.contains (key
))
311 key
.readyOps (key
.interestOps () & ops
);
313 deregisterCancelledKeys();
320 public final Set
selectedKeys()
323 throw new ClosedSelectorException();
328 public final Selector
wakeup()
330 // IMPLEMENTATION NOTE: Whereas the specification says that
331 // thread interruption should trigger a call to wakeup, we
332 // do the reverse under the covers: wakeup triggers a thread
333 // interrupt followed by a subsequent reset of the thread's
334 // interrupt status within select().
336 // First, acquire the monitor of the object regulating
337 // access to our selectThread and unhandledWakeup fields.
338 synchronized (selectThreadMutex
)
340 unhandledWakeup
= true;
342 // Interrupt any thread which is currently blocked in
343 // a select operation.
344 if (selectThread
!= null)
345 selectThread
.interrupt ();
351 private final void deregisterCancelledKeys()
353 Set ckeys
= cancelledKeys ();
356 Iterator it
= ckeys
.iterator();
358 while (it
.hasNext ())
360 keys
.remove ((SelectionKeyImpl
) it
.next ());
366 protected SelectionKey
register (SelectableChannel ch
, int ops
, Object att
)
368 return register ((AbstractSelectableChannel
) ch
, ops
, att
);
371 protected final SelectionKey
register (AbstractSelectableChannel ch
, int ops
,
374 SelectionKeyImpl result
;
376 if (ch
instanceof SocketChannelImpl
)
377 result
= new SocketChannelSelectionKey (ch
, this);
378 else if (ch
instanceof DatagramChannelImpl
)
379 result
= new DatagramChannelSelectionKey (ch
, this);
380 else if (ch
instanceof ServerSocketChannelImpl
)
381 result
= new ServerSocketChannelSelectionKey (ch
, this);
383 throw new InternalError ("No known channel type");
390 result
.interestOps (ops
);