1 /* SelectorImpl.java --
2 Copyright (C) 2002, 2003 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. */
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
;
52 import gnu
.classpath
.Configuration
;
54 public class SelectorImpl
extends AbstractSelector
58 // load the shared library needed for native methods.
59 if (Configuration
.INIT_LOAD_LIBRARY
)
61 System
.loadLibrary ("javanio");
69 * A dummy object whose monitor regulates access to both our
70 * selectThread and unhandledWakeup fields.
72 private Object selectThreadMutex
= new Object ();
75 * Any thread that's currently blocked in a select operation.
77 private Thread selectThread
;
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.
88 private boolean unhandledWakeup
;
90 public SelectorImpl (SelectorProvider provider
)
94 keys
= new HashSet ();
95 selected
= new HashSet ();
98 protected void finalize() throws Throwable
103 protected final void implCloseSelector()
106 // Cancel any pending select operation.
111 synchronized (selected
)
113 synchronized (cancelledKeys ())
115 // FIXME: Release resources here.
121 public final Set
keys()
124 throw new ClosedSelectorException();
126 return Collections
.unmodifiableSet (keys
);
129 public final int selectNow()
132 // FIXME: We're simulating an immediate select
133 // via a select with a timeout of one millisecond.
137 public final int select()
143 // A timeout value of 0 means block forever.
144 private static native int implSelect (int[] read
, int[] write
,
145 int[] except
, long timeout
)
148 private final int[] getFDsAsArray (int ops
)
152 Iterator it
= keys
.iterator ();
154 // Count the number of file descriptors needed
155 while (it
.hasNext ())
157 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
159 if ((key
.interestOps () & ops
) != 0)
165 result
= new int[counter
];
168 it
= keys
.iterator ();
170 // Fill the array with the file descriptors
171 while (it
.hasNext ())
173 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
175 if ((key
.interestOps () & ops
) != 0)
177 result
[counter
] = key
.getNativeFD();
185 public synchronized int select (long timeout
)
189 throw new ClosedSelectorException();
193 synchronized (selected
)
195 deregisterCancelledKeys();
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
);
203 // FIXME: We dont need to check this yet
204 int[] except
= new int [0];
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.
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?
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
)
226 unhandledWakeup
= false;
231 selectThread
= Thread
.currentThread ();
235 // Call the native select() on all file descriptors.
240 result
= implSelect (read
, write
, except
, timeout
);
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
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
259 synchronized (selectThreadMutex
)
263 unhandledWakeup
= false;
264 selectThread
.interrupted ();
269 Iterator it
= keys
.iterator ();
271 while (it
.hasNext ())
274 SelectionKeyImpl key
= (SelectionKeyImpl
) it
.next ();
276 // If key is already selected retrieve old ready ops.
277 if (selected
.contains (key
))
279 ops
= key
.readyOps ();
282 // Set new ready read/accept ops
283 for (int i
= 0; i
< read
.length
; i
++)
285 if (key
.getNativeFD() == read
[i
])
287 if (key
.channel () instanceof ServerSocketChannelImpl
)
289 ops
= ops
| SelectionKey
.OP_ACCEPT
;
293 ops
= ops
| SelectionKey
.OP_READ
;
298 // Set new ready write ops
299 for (int i
= 0; i
< write
.length
; i
++)
301 if (key
.getNativeFD() == write
[i
])
303 ops
= ops
| SelectionKey
.OP_WRITE
;
305 // if (key.channel ().isConnected ())
307 // ops = ops | SelectionKey.OP_WRITE;
311 // ops = ops | SelectionKey.OP_CONNECT;
316 // FIXME: We dont handle exceptional file descriptors yet.
318 // If key is not yet selected add it.
319 if (!selected
.contains (key
))
325 key
.readyOps (key
.interestOps () & ops
);
327 deregisterCancelledKeys();
334 public final Set
selectedKeys()
337 throw new ClosedSelectorException();
342 public final Selector
wakeup()
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().
350 // First, acquire the monitor of the object regulating
351 // access to our selectThread and unhandledWakeup fields.
352 synchronized (selectThreadMutex
)
354 unhandledWakeup
= true;
356 // Interrupt any thread which is currently blocked in
357 // a select operation.
358 if (selectThread
!= null)
359 selectThread
.interrupt ();
365 private final void deregisterCancelledKeys()
367 Set ckeys
= cancelledKeys ();
370 Iterator it
= ckeys
.iterator();
372 while (it
.hasNext ())
374 keys
.remove ((SelectionKeyImpl
) it
.next ());
380 protected SelectionKey
register (SelectableChannel ch
, int ops
, Object att
)
382 return register ((AbstractSelectableChannel
) ch
, ops
, att
);
385 protected final SelectionKey
register (AbstractSelectableChannel ch
, int ops
,
388 SelectionKeyImpl result
;
390 if (ch
instanceof SocketChannelImpl
)
392 SocketChannelImpl sc
= (SocketChannelImpl
) ch
;
393 result
= new SocketChannelSelectionKey (ch
, this);
395 else if (ch
instanceof DatagramChannelImpl
)
397 DatagramChannelImpl dc
= (DatagramChannelImpl
) ch
;
398 result
= new DatagramChannelSelectionKey (ch
, this);
400 else if (ch
instanceof ServerSocketChannelImpl
)
402 ServerSocketChannelImpl ssc
= (ServerSocketChannelImpl
) ch
;
403 result
= new ServerSocketChannelSelectionKey (ch
, this);
407 throw new InternalError ("No known channel type");
415 result
.interestOps (ops
);