2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / gnu / java / nio / SelectorImpl.java
blobf26e0808074f9450002e85776ca6aa947eb2be94
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)
9 any later version.
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
19 02111-1307 USA.
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.
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. */
38 package gnu.java.nio;
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;
54 public class SelectorImpl extends AbstractSelector
56 static
58 // load the shared library needed for native methods.
59 if (Configuration.INIT_LOAD_LIBRARY)
61 System.loadLibrary ("javanio");
65 private Set keys;
66 private Set selected;
68 /**
69 * A dummy object whose monitor regulates access to both our
70 * selectThread and unhandledWakeup fields.
72 private Object selectThreadMutex = new Object ();
74 /**
75 * Any thread that's currently blocked in a select operation.
77 private Thread selectThread;
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.
88 private boolean unhandledWakeup;
90 public SelectorImpl (SelectorProvider provider)
92 super (provider);
94 keys = new HashSet ();
95 selected = new HashSet ();
98 protected void finalize() throws Throwable
100 close();
103 protected final void implCloseSelector()
104 throws IOException
106 // Cancel any pending select operation.
107 wakeup();
109 synchronized (keys)
111 synchronized (selected)
113 synchronized (cancelledKeys ())
115 // FIXME: Release resources here.
121 public final Set keys()
123 if (!isOpen())
124 throw new ClosedSelectorException();
126 return Collections.unmodifiableSet (keys);
129 public final int selectNow()
130 throws IOException
132 // FIXME: We're simulating an immediate select
133 // via a select with a timeout of one millisecond.
134 return select (1);
137 public final int select()
138 throws IOException
140 return select (0);
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;
148 private final int[] getFDsAsArray (int ops)
150 int[] result;
151 int counter = 0;
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)
161 counter++;
165 result = new int[counter];
167 counter = 0;
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();
178 counter++;
182 return result;
185 public synchronized int select (long timeout)
186 throws IOException
188 if (!isOpen())
189 throw new ClosedSelectorException();
191 synchronized (keys)
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)
224 if (unhandledWakeup)
226 unhandledWakeup = false;
227 return 0;
229 else
231 selectThread = Thread.currentThread ();
235 // Call the native select() on all file descriptors.
236 int result = 0;
239 begin();
240 result = implSelect (read, write, except, timeout);
242 finally
244 end();
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.
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)
261 if (unhandledWakeup)
263 unhandledWakeup = false;
264 selectThread.interrupted ();
266 selectThread = null;
269 Iterator it = keys.iterator ();
271 while (it.hasNext ())
273 int ops = 0;
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;
291 else
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 ())
306 // {
307 // ops = ops | SelectionKey.OP_WRITE;
308 // }
309 // else
310 // {
311 // ops = ops | SelectionKey.OP_CONNECT;
312 // }
316 // FIXME: We dont handle exceptional file descriptors yet.
318 // If key is not yet selected add it.
319 if (!selected.contains (key))
321 selected.add (key);
324 // Set new ready ops
325 key.readyOps (key.interestOps () & ops);
327 deregisterCancelledKeys();
329 return result;
334 public final Set selectedKeys()
336 if (!isOpen())
337 throw new ClosedSelectorException();
339 return selected;
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 ();
362 return this;
365 private final void deregisterCancelledKeys()
367 Set ckeys = cancelledKeys ();
368 synchronized (ckeys)
370 Iterator it = ckeys.iterator();
372 while (it.hasNext ())
374 keys.remove ((SelectionKeyImpl) it.next ());
375 it.remove ();
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,
386 Object att)
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);
405 else
407 throw new InternalError ("No known channel type");
410 synchronized (keys)
412 keys.add (result);
415 result.interestOps (ops);
416 result.attach (att);
417 return result;