diff options
| author | Casey Marshall <csm@gnu.org> | 2006-09-17 07:31:39 +0000 |
|---|---|---|
| committer | Casey Marshall <csm@gnu.org> | 2006-09-17 07:31:39 +0000 |
| commit | 133e014be0604b45f8ccede687acf1ea979d4955 (patch) | |
| tree | 03bfec201e509081586497b0e4db7944e633cab7 /gnu/java/nio/KqueueSelectorImpl.java | |
| parent | a344c95abdd44f1c697d0520bf97ac3c8403a3b6 (diff) | |
| download | classpath-133e014be0604b45f8ccede687acf1ea979d4955.tar.gz | |
2006-09-16 Casey Marshall <csm@gnu.org>
* NEWS: updated.
* configure.ac (AC_CHECK_HEADERS): check for `sys/event.h'.
(AC_CHECK_FUNCS): add checks for readv, writev, getifaddrs,
kqueue, and kevent.
(HAVE_INET6): define if IPv6 is supported.
* gnu/java/net/PlainDatagramSocketImpl.java (channel): new field.
(native_fd): removed.
(impl): new field.
(<init>): throw IOException; initialize fields.
(finalize): removed.
(getNativeFD): removed.
(bind): use `PlainSocketImpl.bind.'
(create): use `PlainSocketImpl.initSocket.'
(disconnect): use `PlainSocketImpl.disconnect.'
(getLocalPort): new method.
(send): use `VMChannel.send.'
(receive): use `VMChannel.receive.'
(setOption): use `PlainSocketImpl.setOption.'
(getOption): use `PlainSocketImpl.getOption.'
(close): use `VMChannel.State.close.'
(join): use `PlainSocketImpl.join.'
(leave): use `PlainSocketImpl.leave.'
(joinGroup, leaveGroup): implemented.
* gnu/java/net/PlainSocketImpl.java: make non-final.
(native_fd): removed.
(impl): new field.
(channel): new field.
(<init>): initialize `impl.'
(finalize, getNativeFD): removed.
(setOption): use `PlainSocketImpl.setOption.'
(getOption): use `PlainSocketImpl.getOption.'
(shutdownInput): use `PlainSocketImpl.shutdownInput.'
(shutdownOutput): use `PlainSocketImpl.shutdownOutput.'
(create): create `channel,' initialize `impl's native state.
(connect): use `connect(SocketAddress, int).'
(connect): use `SocketChannelImpl.connect;' initialize `address'
and `port.'
(bind): use `VMPlainSocketImpl.bind.'
(listen): use `VMPlainSocketImpl.listen.'
(accept): use `SocketChannelImpl.accept.'
(available): use `VMChannel.available.'
(close): use `PlainSocketImpl.close.'
(sendUrgentData): use `PlainSocketImpl.sendUrgentData.'
(getVMChannel, getInetAddress, getLocalPort, getLocalAddress,
getPort): new methods.
(SocketInputStream.read): use `VMChannel.read.'
(SocketInputStream.read): use `SocketChannel.read.'
(SocketOutputStream.write): use `VMChannel.write.'
(SocketOutputStream.write): use `SocketChannel.write.'
* gnu/java/nio/DatagramChannelImpl.java: implement VMChannel.
(channel): new field.
(<init>): initialize `channel.'
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(connect): use `VMChannel.connect.'
(disconnect): use `VMChannel.disconnect.'
(isConnected): use `VMChannel.getPeerAddress.'
(write): use `VMChannel.write.'
(write): use `VMChannel.writeGathering.'
(read): use `VMChannel.read.'
(read): use `VMChannel.readScattering.'
(receive): use `VMChannel.receive.'
(send): use `VMChannel.send.'
(getVMChannel): new method.
* gnu/java/nio/DatagramChannelSelectionKey.java (getNativeFD):
access native FD through VMChannel.State.
* gnu/java/nio/FileChannelImpl.java: moved from
gnu/java/nio/channels/FileChannelImpl.java.
* gnu/java/nio/FileLockImpl.java: fix imports.
* gnu/java/nio/KqueueSelectionKeyImpl.java: new file.
* gnu/java/nio/KqueueSelectorImpl.java: new file.
* gnu/java/nio/NIOSocket.java (impl): removed.
(channel): new field.
(<init>): init superclass with a `NIOSocketImpl;' init `channel.'
(getPlainSocketImpl, setChannel): removed.
(isConnected): new method.
* gnu/java/nio/NIOSocketImpl.java: new file.
* gnu/java/nio/PipeImpl.java (SourceChannelImpl): implement
`VMChannelOwner.'
(SourceChannelImpl.native_fd): removed.
(SourceChannelImpl.<init>): init with a `VMChannel.'
(SourceChannelImpl.getNativeFD): removed.
(SourceChannelImpl.getVMChannel): new method.
(SourceChannelImpl.implCloseSelectableChannel): implement.
(SinkChannelImpl): implement `VMChannelOwner.'
(SinkChannelImpl.native_fd): removed.
(SinkChannelImpl.<init>): init with a `VMChannel.'
(SinkChannelImpl.implCloseSelectableChannel): implement.
(SinkChannelImpl.getNativeFD): removed.
(SinkChannelImpl.getVMChannel): new method.
* gnu/java/nio/SelectionKeyImpl.java (getNativeFD): mark
deprecated.
* gnu/java/nio/SelectorProviderImpl.java (SELECTOR_IMPL_KQUEUE,
SELECTOR_IMPL_EPOLL, SELECTOR_IMPL): new constants.
(openSelector): return kqueue selector if available.
* gnu/java/nio/ServerSocketChannelImpl.java: implement
`VMChannelOwner.'
(channel): new field.
(<init>): init `channel.'
(finalizer): check if the `VMChannel.State' is valid.
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(accept): use `VMChannel.accept.'
(getVMChannel): new method.
* gnu/java/nio/ServerSocketChannelSelectionKey.java (getNativeFD):
access native FD through `VMChannel.State.'
* gnu/java/nio/SocketChannelImpl.java: implement `VMChannelOwner.'
(impl): removed.
(channel, connected, connectAddress): new field.
(<init>): new constructors.
(getPlainSocketImpl): removed.
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(connect): use `connect(SocketAddress,int).'
(connect): use `VMChannel.connect.'
(finishConnect): don't use a selector.
(isConnected): use `VMChannel.getPeerAddress.'
(read): use `VMChannel.read.'
(read): use `VMChannel.readScattering.'
(write): use `VMChannel.write.'
(write): use `VMChannel.writeGathering.'
(getVMChannel): new method.
* gnu/java/nio/SocketChannelSelectionKey.java (getNativeFD): get
native FD from `VMChannel.State.'
* gnu/java/nio/SocketChannelSelectionKeyImpl.java (getNativeFD):
get native FD from `VMChannel.State.'
* gnu/java/nio/VMChannelOwner.java: new file.
* gnu/java/nio/channels/FileChannelImpl.java: removed.
* include/Makefile.am: generate `gnu_java_nio_FileChannelImpl.h'
and `gnu_java_nio_KqueueSelectorImpl.h;' don't generate
`gnu_java_nio_channels_FileChannelImpl.h.'
* include/gnu_java_net_VMPlainSocketImpl.h: regenerated.
* include/gnu_java_nio_FileChannelImpl.h: new file.
* include/gnu_java_nio_KqueueSelectorImpl.h: new file.
* include/gnu_java_nio_VMChannel.h: regenerated.
* include/gnu_java_nio_VMPipe.h: regenerated.
* include/java_net_VMNetworkInterface.h: regenerated.
* java/io/FileDescriptor.java: fix imports.
* java/io/FileInputStream.java (<init>): handle exceptions.
(read): wrap the destination arary.
* java/io/FileOutputStream.java (<init>): handle exceptions.
(write): wrap the source array.
* java/io/RandomAccessFile.java (<init>): handle exceptions.
* java/net/DatagramSocket.java (<init>): handle exceptions.
(receive): handle length/port setting.
(connect): bind to any address/port if the argument is null.
* java/net/NetworkInterface.java (name, inetAddress): removed.
(netif): new field.
(<init>): make private.
(getName): return `netif.name.'
(getInetAddresses): access `netif.addresses.'
(getDisplayName): return `netif.name.'
(getByName, getByAddress): handle changes to `VMNetworkInterface.'
(condense): removed.
(getNetworkInterfaces): handle changes to `VMNetworkInterface.'
(equals): compare `netif' fields.
(hashCode): get hash codes from `netif.'
(toString): use a StringBuffer.
* java/net/ServerSocket.java (close): don't set `impl' to null.
(isClosed): use `VMChannel.State.isClosed.'
* java/net/Socket.java (getLocalAddress): don't use `getOption' if
the `SocketImpl' is a `PlainSocketImpl.'
(close): just close the `impl.'
(toString): use `super.toString' in the value we return.
(isConnected): just access `impl,' not `getImpl.'
(isBound): use `PlainSocketImpl' methods if we can.
(isClosed): look at `VMChannel.State.'
* native/jni/classpath/jcl.c (JNI_OnLoad): new function.
(JCL_NewRawDataObject): don't initialize cached fields here; throw
an exception if they were not.
(JCL_GetRawData): throw an exception if cached fields weren't
created.
* native/jni/java-lang/java_lang_VMProcess.c: handle
FileChannelImpl move.
* native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c
(IO_EXCEPTION, SOCKET_EXCEPTION, BIND_EXCEPTION,
THROW_NO_NETWORK): new macros.
(Java_gnu_java_net_VMPlainSocketImpl_bind): reipmlemented.
(Java_gnu_java_net_VMPlainSocketImpl_bind6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_listen): reimplemented.
(java_sockopt): new enum.
(Java_gnu_java_net_VMPlainSocketImpl_setOption): reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_getOption): reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_shutdownInput):
reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput):
reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData): new
function.
(Java_gnu_java_net_VMPlainSocketImpl_join): new function.
(Java_gnu_java_net_VMPlainSocketImpl_join6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_read): removed.
(Java_gnu_java_net_VMPlainSocketImpl_leave): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leave6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_joinGroup): new function.
(Java_gnu_java_net_VMPlainSocketImpl_write): removed.
(Java_gnu_java_net_VMPlainSocketImpl_joinGroup6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leaveGroup): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6): new function.
(getif_address): new function.
(getif_index): new function.
* native/jni/java-net/java_net_VMNetworkInterface.c
(java_net_VMNetworkInterface_init,
java_net_VMNetworkInterface_addAddress): new file-scope globals.
(Java_java_net_VMNetworkInterface_initIds): new function.
(struct netif_entry): new struct.
(free_netif_list): new function.
(Java_java_net_VMNetworkInterface_getInterfaces): removed.
(Java_java_net_VMNetworkInterface_getVMInterfaces): new function.
* native/jni/java-nio/Makefile.am (libjavanio_la_SOURCES): remove
gnu_java_nio_channels_FileChannelImpl.c, add
gnu_java_nio_KqueueSelectorImpl.c.
* native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c: new file.
* native/jni/java-nio/gnu_java_nio_VMChannel.c
(INTERRUPTED_IO_EXCEPTION, SOCKET_TIMEOUT_EXCEPTION, ALIGN_UP,
ALIGN_DOWN): new macros.
(JCL_init_buffer): get the address through GetDirectBufferAddress
if possible.
(Java_gnu_java_nio_VMChannel_stdin_1fd,
Java_gnu_java_nio_VMChannel_stdout_1fd,
Java_gnu_java_nio_VMChannel_stderr_1fd): new functions.
(Java_gnu_java_nio_VMChannel_setBlocking): fix setting blocking
value.
(Java_gnu_java_nio_VMChannel_read): renamed...
(Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2): to
this; handle interrupted IO; add HAVE_READ check.
(Java_gnu_java_nio_VMChannel_write): renamed...
(Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2): to
this; handle zero-length write; add HAVE_WRITE check.
(Java_gnu_java_nio_VMChannel_receive): new function.
(Java_gnu_java_nio_VMChannel_send): new function.
(Java_gnu_java_nio_VMChannel_send6): new function.
(Java_gnu_java_nio_VMChannel_read__I): new function.
(Java_gnu_java_nio_VMChannel_write__II): new function.
(Java_gnu_java_nio_VMChannel_socket): new function.
(Java_gnu_java_nio_VMChannel_connect): new function.
(Java_gnu_java_nio_VMChannel_connect6): new function.
(Java_gnu_java_nio_VMChannel_getsockname): new function.
(Java_gnu_java_nio_VMChannel_getpeername): new function.
(Java_gnu_java_nio_VMChannel_accept): new function.
(Java_gnu_java_nio_VMChannel_disconnect): new function.
(Java_gnu_java_nio_VMChannel_close): new function.
(Java_gnu_java_nio_VMChannel_available): new function.
(FileChannel_mode): new enum.
(Java_gnu_java_nio_VMChannel_open): new function.
(Java_gnu_java_nio_VMChannel_position): new function.
(Java_gnu_java_nio_VMChannel_seek): new function.
(Java_gnu_java_nio_VMChannel_truncate): new funciton.
(Java_gnu_java_nio_VMChannel_lock): new function.
(Java_gnu_java_nio_VMChannel_unlock): new function.
(Java_gnu_java_nio_VMChannel_size): new function.
(Java_gnu_java_nio_VMChannel_map): new function.
(Java_gnu_java_nio_VMChannel_flush): new function.
* native/jni/java-nio/gnu_java_nio_VMPipe.c
(Java_gnu_java_nio_VMPipe_init): removed.
(Java_gnu_java_nio_VMPipe_pipe0): new function.
* native/jni/java-nio/javanio.c: new file.
* native/jni/java-nio/javanio.h: new file.
* native/jni/native-lib/cpnet.c (cpnet_getHostByName): fix for
systems without `gethostbyname_r.'
* vm/reference/gnu/java/net/VMPlainSocketImpl.java (nfd): new
field.
(<init>, <init>): new constructors.
(setOption, getOption): make instance methods; defer to native
implementation.
(connect): removed.
(bind): make an instance method; defer to native methods.
(accept): removed.
(available): removed.
(listen): make an instance method; defer to native method.
(read): removed.
(join, leave): new methods.
(write): removed.
(joinGroup, leaveGroup): new methods.
(shutdownInput, shutdownOutput): make instance methods.
(sendUrgentData): removed.
(State): new class.
* vm/reference/gnu/java/nio/VMChannel.java: make final.
(fd): removed.
(nfd): new field.
(<init>): new, public constructors.
(getVMChannel): methods removed.
(getState, getStdin, getStdout, getStderr, stdin_fd, stdout_fd,
stderr_fd): new methods.
(setBlocking): make an instance method.
(available): new method.
(read): get native fd from `nfd.'
(read): new single-byte read method.
(readScattering): get native fd from `nfd.'
(receive): new method.
(write, writeGathering): get native fd from `nfd.'
(send): new method.
(write): new single-byte write method.
(initSocket): new method.
(connect): new method.
(disconnect): new method.
(getLocalAddress): new method.
(getPeerAddress): new method.
(accept): new method.
(openFile): new method.
(position): new method.
(seek): new method.
(truncate): new method.
(lock): new method.
(unlock): new method.
(size): new method.
(map): new method.
(flush): new method.
(close): new method.
(State): new class.
(Kind): new class.
* vm/reference/gnu/java/nio/VMPipe.java (init): removed.
(pipe, pipe0): new method.
* vm/reference/java/net/VMNetworkInterface.java (name, addresses):
new fields.
(<clinit>): call `initIds.'
(initIds): new method.
(getInterfaces): removed.
(getVMInterfaces): new method.
(addAddress): new method.
* vm/reference/java/nio/channels/VMChannels.java: fix imports.
Diffstat (limited to 'gnu/java/nio/KqueueSelectorImpl.java')
| -rw-r--r-- | gnu/java/nio/KqueueSelectorImpl.java | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/gnu/java/nio/KqueueSelectorImpl.java b/gnu/java/nio/KqueueSelectorImpl.java new file mode 100644 index 000000000..dcb058eb5 --- /dev/null +++ b/gnu/java/nio/KqueueSelectorImpl.java @@ -0,0 +1,434 @@ +/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A {@link Selector} implementation that uses the <code>kqueue</code> + * event notification facility. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectorImpl extends AbstractSelector +{ + private static final int sizeof_struct_kevent; + + static + { + try + { + System.loadLibrary("javanio"); + } + catch (Exception x) + { + x.printStackTrace(); + } + + if (kqueue_supported ()) + sizeof_struct_kevent = sizeof_struct_kevent(); + else + sizeof_struct_kevent = -1; + } + + /** + * Tell if kqueue-based selectors are supported on this system. + * + * @return True if this system has kqueue support, and support for it was + * compiled in to Classpath. + */ + public static native boolean kqueue_supported(); + + /* Our native file descriptor. */ + private int kq; + + private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys; + private HashSet/*<KqueueSelectionKeyImpl>*/ selected; + private HashSet/*<KqueueSelectionKeyImpl>*/ cancelled; + private Thread blockedThread; + + public KqueueSelectorImpl(SelectorProvider provider) throws IOException + { + super(provider); + kq = implOpen(); + keys = new HashMap/*<KqueueSelectionKeyImpl>*/(); + cancelled = new HashSet(); + } + + protected void implCloseSelector() throws IOException + { + implClose(kq); + kq = -1; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout == 0) + timeout = -1; + return doSelect(timeout); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + if (blockedThread != null) + blockedThread.interrupt(); + return this; + } + + synchronized int doSelect(long timeout) throws IOException + { + // FIXME -- I'm unclear on how we should synchronize this; and how to + // handle cancelled keys. + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + updateOps(key, 0, true); + } + int events_size = 0; + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + if ((key.interestOps & SelectionKey.OP_ACCEPT) != 0 + || (key.interestOps & SelectionKey.OP_READ) != 0) + key.readEverEnabled = true; + if ((key.interestOps & SelectionKey.OP_CONNECT) != 0 + || (key.interestOps & SelectionKey.OP_WRITE) != 0) + key.writeEverEnabled = true; + + if (key.readEverEnabled) + events_size += sizeof_struct_kevent; + if (key.writeEverEnabled) + events_size += sizeof_struct_kevent; + } + + // We handle native events a little strangely here; per selection key, + // we allocate enough space for two struct kevents, the first in the + // list will be our EVFILT_READ filter, the second our EVFILT_WRITE + // one. If only one of the two needs enabling, though, we don't want + // to pass the other to kevent, because that would result in spurious + // events. We can break down our handling as follows: + // + // - READ enabled, WRITE never enabled. We pass only the first structure + // to kevent. + // - WRITE enabled, READ never enabled. Likewise, but only pass the + // second structure. + // - READ and WRITE enabled. Pass both. + // - READ enabled, WRITE enabled in the past. Pass both, with the + // first structure's flag set to EV_ADD or EV_ENABLE, and the second + // with EV_DISABLE. It seems OK to keep sending events with the + // EV_DISABLE flag. + // - WRITE enabled, READ enabled in the past. Likewise, but flipped. + // + // We handle these states with the readEverEnabled and writeEverEnabled + // flags of selection keys; they start off as false, and become true + // the first time we select() with READ or WRITE enabled. They never + // become false. + ByteBuffer events = ByteBuffer.allocateDirect(events_size); + + for (Iterator it = keys.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue(); + + if (key.readEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().limit + (sizeof_struct_kevent)); + if (key.writeEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().position + (sizeof_struct_kevent).limit(2 * sizeof_struct_kevent)); + } + events.rewind(); + + //System.out.println("dump of keys to select:"); + //dump_selection_keys(events.duplicate()); + + blockedThread = Thread.currentThread(); + if (blockedThread.isInterrupted()) + timeout = 0; + final int n = kevent(kq, events, events_size / sizeof_struct_kevent, + timeout); + Thread.interrupted(); + + //System.out.println("dump of keys selected:"); + //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * sizeof_struct_kevent)); + + selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n); + int x = 0; + for (int i = 0; i < n; i++) + { + events.position(x).limit(x + sizeof_struct_kevent); + x += sizeof_struct_kevent; + int y = fetch_key(events.slice()); + KqueueSelectionKeyImpl key = + (KqueueSelectionKeyImpl) keys.get(new Integer(y)); + key.readyOps = ready_ops(events.slice(), key.interestOps); + selected.add(key); + } + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + keys.remove(new Integer(key.key)); + it.remove(); + } + + return selected.size(); + } + + protected SelectionKey register(AbstractSelectableChannel channel, + int interestOps, + Object attachment) + { + int native_fd = -1; + try + { + if (channel instanceof VMChannelOwner) + native_fd = ((VMChannelOwner) channel).getVMChannel() + .getState().getNativeFD(); + else + throw new IllegalArgumentException("cannot handle channel type " + + channel.getClass().getName()); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("channel is closed or invalid"); + } + + KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel); + result.interestOps = interestOps; + result.attach(attachment); + int k = System.identityHashCode(result); + while (keys.containsKey(new Integer(k))) + k++; + result.key = k; + keys.put(new Integer(k), result); + result.nstate = ByteBuffer.allocateDirect(2 * sizeof_struct_kevent); + updateOps(result, native_fd, false); + return result; + } + + synchronized void updateOps(KqueueSelectionKeyImpl key) + { + updateOps(key, 0, false); + } + + synchronized void updateOps(KqueueSelectionKeyImpl key, int fd, boolean delete) + { + //System.out.println(">> updating kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + kevent_set(key.nstate, fd, key.interestOps, key.key, delete); + //System.out.println(">> updated kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + } + + synchronized void doCancel(KqueueSelectionKeyImpl key) + { + cancelled.add(key); + } + + private void dump_selection_keys(ByteBuffer keys) + { + // WARNING! This method is not guaranteed to be portable! This works + // on darwin/x86, but the sizeof and offsetof these fields may be + // different on other platforms! + int i = 0; + keys.order(ByteOrder.nativeOrder()); + while (keys.hasRemaining()) + { + System.out.println("struct kevent { ident: " + + Integer.toString(keys.getInt()) + + " filter: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " flags: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " fflags: " + + Integer.toHexString(keys.getInt()) + + " data: " + + Integer.toHexString(keys.getInt()) + + " udata: " + + Integer.toHexString(keys.getInt()) + + " }"); + } + } + + /** + * Return the size of a <code>struct kevent</code> on this system. + * + * @return The size of <code>struct kevent</code>. + */ + private static native int sizeof_struct_kevent(); + + /** + * Opens a kqueue descriptor. + * + * @return The new kqueue descriptor. + * @throws IOException If opening fails. + */ + private static native int implOpen() throws IOException; + + /** + * Closes the kqueue file descriptor. + * + * @param kq The kqueue file descriptor. + * @throws IOException + */ + private static native void implClose(int kq) throws IOException; + + /** + * Initialize the specified native state for the given interest ops. + * + * @param nstate The native state structures; in this buffer should be + * the <code>struct kevent</code>s created for a key. + * @param fd The file descriptor. If 0, the native FD is unmodified. + * @param interestOps The operations to enable. + * @param key A unique key that will reference the associated key later. + * @param delete Set to true if this event should be deleted from the + * kqueue (if false, this event is added/updated). + */ + private static native void kevent_set(ByteBuffer nstate, int fd, int interestOps, + int key, boolean delete); + + /** + * Poll for events. The source events are stored in <code>events</code>, + * which is also where polled events will be placed. + * + * @param events The events to poll. This buffer is also the destination + * for events read from the queue. + * @param nevents The number of events to poll (that is, the number of + * events in the <code>events</code> buffer). + * @param timeout The timeout. A timeout of -1 returns immediately; a timeout + * of 0 waits indefinitely. + * @return The number of events read. + */ + private static native int kevent(int kq, ByteBuffer events, int nevents, + long timeout); + + /** + * Fetch a polled key from a native state buffer. For each kevent key we + * create, we put the native state info (one or more <code>struct + * kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate} + * buffer, and place the pointer of the key in the <code>udata</code> field + * of that structure. This method fetches that pointer from the given + * buffer (assumed to be a <code>struct kqueue</code>) and returns it. + * + * @param nstate The buffer containing the <code>struct kqueue</code> to read. + * @return The key object. + */ + private static native int fetch_key(ByteBuffer nstate); + + /** + * Fetch the ready ops of the associated native state. That is, this + * inspects the first argument as a <code>struct kevent</code>, looking + * at its operation (the input is assumed to have been returned via a + * previous call to <code>kevent</code>), and translating that to the + * appropriate Java bit set, based on the second argument. + * + * @param nstate The native state. + * @param interestOps The enabled operations for the key. + * @return The bit set representing the ready operations. + */ + private static native int ready_ops(ByteBuffer nstate, int interestOps); + + /** + * Check if kevent returned EV_EOF for a selection key. + * + * @param nstate The native state. + * @return True if the kevent call returned EOF. + */ + private static native boolean check_eof(ByteBuffer nstate); +} |
