I'd like to backport the KQueue based NIO selector Alex Strange recently
committed to the MacOS X port

http://hg.openjdk.java.net/macosx-port/macosx-port/jdk/rev/cb5ebc902d33

The attached patch compiles on FreeBSD and should work fine on MacOS X
(since I just pulled the code in from the MacOS X port :).  Can someone
test on OpenBSD and/or NetBSD?

-- 
Greg Lewis                          Email   : gle...@eyesbeyond.com
Eyes Beyond                         Web     : http://www.eyesbeyond.com
Information Technology              FreeBSD : gle...@freebsd.org
diff -r 0870207843e2 make/java/nio/Makefile
--- a/make/java/nio/Makefile	Sun Sep 11 10:51:01 2011 -0700
+++ b/make/java/nio/Makefile	Thu Sep 22 23:15:12 2011 -0700
@@ -264,6 +264,9 @@
 FILES_java += \
         sun/nio/ch/AbstractPollSelectorImpl.java \
 	sun/nio/ch/InheritedChannel.java \
+	sun/nio/ch/KQueueArrayWrapper.java \
+	sun/nio/ch/KQueueSelectorImpl.java \
+	sun/nio/ch/KQueueSelectorProvider.java \
         sun/nio/ch/PollSelectorProvider.java \
         sun/nio/ch/PollSelectorImpl.java \
 	sun/nio/ch/Port.java \
@@ -298,6 +301,7 @@
 
 FILES_c += \
 	InheritedChannel.c \
+	KQueueArrayWrapper.c \
 	NativeThread.c \
         PollArrayWrapper.c \
 	UnixAsynchronousServerSocketChannelImpl.c \
@@ -318,7 +322,7 @@
 	sun/nio/fs/BsdNativeDispatcher.java \
 	sun/nio/fs/UnixCopyFile.java \
 	sun/nio/fs/UnixNativeDispatcher.java
-	
+
 FILES_gen += \
 	sun/nio/fs/UnixConstants.java
 endif # PLATFORM = bsd
diff -r 0870207843e2 src/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java
--- a/src/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	Sun Sep 11 10:51:01 2011 -0700
+++ b/src/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	Thu Sep 22 23:15:12 2011 -0700
@@ -69,6 +69,10 @@
             }
         }
 
+        if (osname.contains("BSD") || osname.contains("Mac OS X")) {
+            return new sun.nio.ch.KQueueSelectorProvider();
+        }
+
         return new sun.nio.ch.PollSelectorProvider();
     }
 
diff -r 0870207843e2 src/solaris/classes/sun/nio/ch/KQueueArrayWrapper.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/KQueueArrayWrapper.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * KQueueArrayWrapper.java
+ * Implementation of Selector using FreeBSD / Mac OS X kqueues
+ * Derived from Sun's DevPollArrayWrapper
+ */
+
+package sun.nio.ch;
+
+import sun.misc.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+
+
+/*
+ * struct kevent {           // 32-bit    64-bit
+ *     uintptr_t ident;      //   4         8
+ *     short     filter;     //   2         2
+ *     u_short   flags;      //   2         2
+ *     u_int     fflags;     //   4         4
+ *     intptr_t  data;       //   4         8
+ *     void      *udata;     //   4         8
+ * }                  // Total:  20        32
+ *
+ * The implementation works in 32-bit and 64-bit world. We do this by calling a
+ * native function that actually sets the sizes and offsets of the fields based
+ * on which mode we're in.
+ */
+
+class KQueueArrayWrapper {
+    // Event masks
+    static final short POLLIN       = AbstractPollArrayWrapper.POLLIN;
+    static final short POLLOUT      = AbstractPollArrayWrapper.POLLOUT;
+
+    // kevent filters
+    static short EVFILT_READ;
+    static short EVFILT_WRITE;
+
+    // kevent struct
+    // These fields are now set by initStructSizes in the static initializer.
+    static short SIZEOF_KEVENT;
+    static short FD_OFFSET;
+    static short FILTER_OFFSET;
+
+    // kevent array size (just under 1K bytes)
+    static final int NUM_KEVENTS = 50;
+
+    // Are we in a 64-bit VM?
+    static boolean is64bit = false;
+
+    // The kevent array (used for outcoming events only)
+    private AllocatedNativeObject keventArray = null;
+    private long keventArrayAddress;
+
+    // The kqueue fd
+    private int kq = -1;
+
+    // The fd of the interrupt line going out
+    private int outgoingInterruptFD;
+
+    // The fd of the interrupt line coming in
+    private int incomingInterruptFD;
+
+    static {
+        initStructSizes();
+        String datamodel = (String) java.security.AccessController.doPrivileged(
+        new sun.security.action.GetPropertyAction("sun.arch.data.model"));
+        is64bit = datamodel.equals("64");
+    }
+
+    KQueueArrayWrapper() {
+        int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
+        keventArray = new AllocatedNativeObject(allocationSize, true);
+        keventArrayAddress = keventArray.address();
+        kq = init();
+    }
+
+    void initInterrupt(int fd0, int fd1) {
+        outgoingInterruptFD = fd1;
+        incomingInterruptFD = fd0;
+        register0(kq, fd0, 1, 0);
+    }
+
+    int getReventOps(int index) {
+        int result = 0;
+        int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
+        short filter = keventArray.getShort(offset);
+
+        // This is all that's necessary based on inspection of usage: 
+        //   SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl, 
+        //   ServerSocketChannelImpl, SocketChannelImpl
+        if (filter == EVFILT_READ) {
+            result |= POLLIN;
+        } else if (filter == EVFILT_WRITE) {
+            result |= POLLOUT;
+        }
+
+        return result;
+    }
+
+    int getDescriptor(int index) {
+        int offset = SIZEOF_KEVENT*index + FD_OFFSET;
+        /* The ident field is 8 bytes in 64-bit world, however the API wants us
+         * to return an int. Hence read the 8 bytes but return as an int.
+         */
+        if (is64bit) {
+          long fd = keventArray.getLong(offset);
+          assert fd <= Integer.MAX_VALUE;
+          return (int) fd;
+        } else {
+          return keventArray.getInt(offset);
+        }
+    }
+
+    void setInterest(int fd, int events) {
+        register0(kq, fd, events & POLLIN, events & POLLOUT);
+    }
+
+    void release(int fd) {
+        register0(kq, fd, 0, 0);
+    }
+
+    void close() throws IOException {
+        if (keventArray != null) {
+            keventArray.free();
+            keventArray = null;
+        }
+        if (kq >= 0) {
+            FileDispatcherImpl.closeIntFD(kq);
+            kq = -1;
+        }
+    }
+
+    int poll(long timeout) {
+        int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
+        return updated;
+    }
+
+    void interrupt() {
+        interrupt(outgoingInterruptFD);
+    }
+
+    private native int init();
+    private static native void initStructSizes();
+
+    private native void register0(int kq, int fd, int read, int write);
+    private native int kevent0(int kq, long keventAddress, int keventCount, 
+                               long timeout);
+    private static native void interrupt(int fd);
+}
+
diff -r 0870207843e2 src/solaris/classes/sun/nio/ch/KQueueSelectorImpl.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/KQueueSelectorImpl.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * KQueueSelectorImpl.java
+ * Implementation of Selector using FreeBSD / Mac OS X kqueues
+ * Derived from Sun's DevPollSelectorImpl
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+import java.util.*;
+import sun.misc.*;
+
+class KQueueSelectorImpl
+    extends SelectorImpl
+{
+    // File descriptors used for interrupt
+    protected int fd0;
+    protected int fd1;
+    
+    // The kqueue manipulator
+    KQueueArrayWrapper kqueueWrapper;
+
+    // Count of registered descriptors (including interrupt)
+    private int totalChannels;
+
+    // Map from file descriptors to selection keys
+    private HashMap fdToKey;
+
+    // True if this Selector has been closed
+    private boolean closed = false;
+
+    // Lock for interrupt triggering and clearing
+    private Object interruptLock = new Object();
+    private boolean interruptTriggered = false;
+
+    /**
+     * Package private constructor called by factory method in
+     * the abstract superclass Selector.
+     */
+    KQueueSelectorImpl(SelectorProvider sp) {
+        super(sp);
+        long fds = IOUtil.makePipe(false);
+        fd0 = (int)(fds >>> 32);
+        fd1 = (int)fds;
+        kqueueWrapper = new KQueueArrayWrapper();
+        kqueueWrapper.initInterrupt(fd0, fd1);
+        fdToKey = new HashMap();
+        totalChannels = 1;
+    }
+
+
+    protected int doSelect(long timeout)
+        throws IOException
+    {
+        int entries = 0;
+        if (closed) 
+            throw new ClosedSelectorException();
+        processDeregisterQueue();
+        if (timeout == 0  &&  totalChannels == 1) 
+            return 0;
+        try {
+            begin();
+            entries = kqueueWrapper.poll(timeout);
+        } finally {
+            end();
+        }
+        processDeregisterQueue();
+        return updateSelectedKeys(entries);
+    }
+
+
+    /**
+     * Update the keys whose fd's have been selected by the devpoll
+     * driver. Add the ready keys to the ready queue.
+     * If the interrupt fd has been selected, drain it and clear the interrupt.
+     */
+    private int updateSelectedKeys(int entries) 
+        throws IOException
+    {
+        int numKeysUpdated = 0;
+        boolean interrupted = false;
+
+        for (int i = 0; i < entries; i++) {
+            int nextFD = kqueueWrapper.getDescriptor(i);
+            if (nextFD == fd0) {
+                interrupted = true;
+            } else {
+                SelectionKeyImpl ski = 
+                    (SelectionKeyImpl) fdToKey.get(new Integer(nextFD));
+                // ski is null in the case of an interrupt
+                if (ski != null) {
+                    int rOps = kqueueWrapper.getReventOps(i);
+                    if (selectedKeys.contains(ski)) {
+                        if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                            numKeysUpdated++;
+                        }
+                    } else {
+                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        if ((ski.readyOps() & ski.interestOps()) != 0) {
+                            selectedKeys.add(ski);
+                            numKeysUpdated++;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (interrupted) {
+            // Clear the wakeup pipe
+            synchronized (interruptLock) {
+                IOUtil.drain(fd0);
+                interruptTriggered = false;
+            }
+        }
+
+        return numKeysUpdated;
+    }
+
+
+    protected void implClose() throws IOException {
+        if (!closed) {
+            closed = true;
+            FileDispatcherImpl.closeIntFD(fd0);
+            FileDispatcherImpl.closeIntFD(fd1);
+            if (kqueueWrapper != null) {
+                kqueueWrapper.release(fd0);
+                kqueueWrapper.close();
+                kqueueWrapper = null;
+                selectedKeys = null;
+
+                // Deregister channels
+                Iterator i = keys.iterator();
+                while (i.hasNext()) {
+                    SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
+                    deregister(ski);
+                    SelectableChannel selch = ski.channel();
+                    if (!selch.isOpen() && !selch.isRegistered())
+                        ((SelChImpl)selch).kill();
+                    i.remove();
+                }
+                totalChannels = 0;
+            }
+            fd0 = -1;
+            fd1 = -1;
+        }
+    }
+
+
+    protected void implRegister(SelectionKeyImpl ski) {
+        int fd = IOUtil.fdVal(ski.channel.getFD());
+        fdToKey.put(new Integer(fd), ski);
+        totalChannels++;
+        keys.add(ski);
+    }
+    
+
+    protected void implDereg(SelectionKeyImpl ski) throws IOException {
+        int fd = ski.channel.getFDVal();
+        fdToKey.remove(new Integer(fd));
+        kqueueWrapper.release(fd);
+        totalChannels--;
+        keys.remove(ski);
+        selectedKeys.remove(ski);
+        deregister((AbstractSelectionKey)ski);
+        SelectableChannel selch = ski.channel();
+        if (!selch.isOpen() && !selch.isRegistered())
+            ((SelChImpl)selch).kill();
+    }
+
+
+    void putEventOps(SelectionKeyImpl ski, int ops) {
+        int fd = IOUtil.fdVal(ski.channel.getFD());
+        kqueueWrapper.setInterest(fd, ops);
+    }
+
+
+    public Selector wakeup() {
+        synchronized (interruptLock) {
+            if (!interruptTriggered) {
+                kqueueWrapper.interrupt();
+                interruptTriggered = true;
+            }
+        }
+        return this;
+    }
+
+
+    static {
+        Util.load();
+    }    
+}
+
diff -r 0870207843e2 src/solaris/classes/sun/nio/ch/KQueueSelectorProvider.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/KQueueSelectorProvider.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * KQueueSelectorProvider.java
+ * Implementation of Selector using FreeBSD / Mac OS X kqueues
+ * Derived from Sun's DevPollSelectorProvider
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+
+public class KQueueSelectorProvider
+extends SelectorProviderImpl
+{
+    public AbstractSelector openSelector() throws IOException {
+        return new KQueueSelectorImpl(this);
+    }
+}
diff -r 0870207843e2 src/solaris/native/sun/nio/ch/KQueueArrayWrapper.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/native/sun/nio/ch/KQueueArrayWrapper.c	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * KQueueArrayWrapper.c
+ * Implementation of Selector using FreeBSD / Mac OS X kqueues
+ * Derived from Sun's DevPollArrayWrapper
+ */
+
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz)
+{
+#define CHECK_EXCEPTION() { \
+    if ((*env)->ExceptionCheck(env)) { \
+        goto exceptionOccurred; \
+    } \
+}
+
+#define CHECK_ERROR_AND_EXCEPTION(_field) { \
+    if (_field == NULL) { \
+        goto badField; \
+    } \
+    CHECK_EXCEPTION(); \
+}
+
+
+    jfieldID field;
+
+    field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S");
+    CHECK_ERROR_AND_EXCEPTION(field);
+    (*env)->SetStaticShortField(env, clazz, field, EVFILT_READ);
+    CHECK_EXCEPTION();
+
+    field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S");
+    CHECK_ERROR_AND_EXCEPTION(field);
+    (*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE);
+    CHECK_EXCEPTION();
+
+    field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S");
+    CHECK_ERROR_AND_EXCEPTION(field);
+    (*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent));
+    CHECK_EXCEPTION();
+
+    field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S");
+    CHECK_ERROR_AND_EXCEPTION(field);
+    (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident));
+    CHECK_EXCEPTION();
+
+    field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S");
+    CHECK_ERROR_AND_EXCEPTION(field);
+    (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter));
+    CHECK_EXCEPTION();
+    return;
+
+badField:
+    return;
+
+exceptionOccurred:
+    return;
+
+#undef CHECK_EXCEPTION
+#undef CHECK_ERROR_AND_EXCEPTION
+}
+
+JNIEXPORT jint JNICALL 
+Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this)
+{
+    int kq = kqueue();
+    if (kq < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed");
+    }
+    return kq;
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this, 
+                                             jint kq, jint fd, jint r, jint w)
+{
+    struct kevent changes[2];
+    struct kevent errors[2];
+    struct timespec dontBlock = {0, 0};
+
+    // if (r) then { register for read } else { unregister for read }
+    // if (w) then { register for write } else { unregister for write }
+    // Ignore errors - they're probably complaints about deleting non-
+    //   added filters - but provide an error array anyway because 
+    //   kqueue behaves erratically if some of its registrations fail.
+    EV_SET(&changes[0], fd, EVFILT_READ,  r ? EV_ADD : EV_DELETE, 0, 0, 0);
+    EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0);
+    kevent(kq, changes, 2, errors, 2, &dontBlock);
+}
+
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq, 
+                                           jlong kevAddr, jint kevCount, 
+                                           jlong timeout)
+{
+    struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr);
+    struct timespec ts;
+    struct timespec *tsp;
+    int result;
+
+    // Java timeout is in milliseconds. Convert to struct timespec.
+    // Java timeout == -1 : wait forever : timespec timeout of NULL
+    // Java timeout == 0  : return immediately : timespec timeout of zero
+    if (timeout >= 0) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec
+        tsp = &ts;
+    } else {
+        tsp = NULL;
+    }
+
+    result = kevent(kq, NULL, 0, kevs, kevCount, tsp);
+
+    if (result < 0) {
+        if (errno == EINTR) {
+            // ignore EINTR, pretend nothing was selected
+            result = 0;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue failed");
+        }
+    }
+    
+    return result;
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd)
+{
+    char c = 1;
+    if (1 != write(fd, &c, 1)) {
+        JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed");
+    }
+}
+                                           
diff -r 0870207843e2 test/java/nio/channels/FileChannel/FileChannel_transferFrom.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/FileChannel/FileChannel_transferFrom.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ @test
+ @summary Test of java.nio.Channel.
+ @summary com.apple.junit.java.nio.channels
+ @run main FileChannel_transferFrom
+ */
+
+import junit.framework.*;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+
+public class FileChannel_transferFrom extends TestCase
+{
+    public static Test suite() {
+        return new TestSuite( FileChannel_transferFrom.class);
+    }
+    
+    public static void main( String[] args ) {
+        junit.textui.TestRunner.run( suite() );
+    }
+    
+    private static final String src = System.getProperty("harness.runner.home") +
+    File.separator + "data" + File.separator + "nio" + File.separator + "Franklin.txt";
+    private String dst;
+    
+    public void testTransfer() throws Exception {
+        File f1 = new File(src);
+        assertNotNull(f1);
+        assertTrue("File not found:" +  src, f1.exists());
+        
+        File f2 = File.createTempFile("Ben", ".txt");
+        assertNotNull(f2);
+        f2.deleteOnExit();
+        dst = f2.getCanonicalPath();
+        
+        // Create channel on the source
+        FileChannel srcChannel = new FileInputStream(src).getChannel();
+        
+        // Create channel on the destination
+        FileChannel dstChannel = new FileOutputStream(dst).getChannel();
+        
+        // Copy file contents from source to destination
+        dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
+        
+        // Close the channels
+        srcChannel.close();
+        dstChannel.close();
+        
+        assertTrue("Expected files to have same contents", contentsMatch() );
+    }
+    
+    public boolean contentsMatch() throws Exception {
+        int data1, data2;
+        
+		FileInputStream original = new FileInputStream(src);
+		assertNotNull("Original file could not be opened", original);
+		
+		FileInputStream copy = new FileInputStream(dst);
+		assertNotNull("Copy file could not be opened", copy);
+		
+		do {
+			data1 = original.read();
+			data2 = copy.read();
+			if(data1 != data2) {
+				original.close();
+				copy.close();
+				return false;
+			}
+		} while(data1 != -1);
+        
+        return true;
+    }
+}
diff -r 0870207843e2 test/java/nio/channels/Selector/Kqueues64bitTest_R4258155.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/Selector/Kqueues64bitTest_R4258155.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ @test
+ @summary Test to make sure kqueues work in 64-bit. We create two socket channels and write to them. 
+ @summary We then use a Selector on those two channels and make sure select() returns us a non-zero value.
+ @summary com.apple.junit.java.nio.Selector
+ @run main Kqueues64bitTest_R4258155
+ */
+
+import junit.framework.*;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.channels.*;
+import java.util.Set;
+
+public class Kqueues64bitTest_R4258155 extends TestCase
+{
+	public static Test suite() {
+		return new TestSuite( Kqueues64bitTest_R4258155.class);
+	}
+    
+	public static void main( String[] args ) {
+		junit.textui.TestRunner.run( suite() );
+	}
+    
+	public static final int PORT = 10000;
+    
+	static Object lock = new Object();
+	static volatile boolean startTest = false;
+	static volatile boolean parttwo = false;
+    
+	public void test64bitKqueues() throws Exception {
+		String preferSelect = System.getProperty("java.nio.preferSelect", "false");
+		if (preferSelect.equals("true")) {
+			System.err.println("WARNING! java.nio.preferSelect=true! We're not using kqueues. Test results could be incorrect!");
+		}
+		
+		Selector selector = Selector.open();
+        
+		ServerThread st = new ServerThread();
+		st.start();
+        
+		synchronized (Kqueues64bitTest_R4258155.lock) {
+			while (startTest == false)
+				Kqueues64bitTest_R4258155.lock.wait();
+		}
+        
+		SocketChannel channel1 = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), Kqueues64bitTest_R4258155.PORT));
+		SocketChannel channel2 = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), Kqueues64bitTest_R4258155.PORT));
+		channel1.configureBlocking(false);
+		channel2.configureBlocking(false);
+        
+		SelectionKey channel1Key = channel1.register(selector, channel1.validOps());
+		SelectionKey channel2Key = channel2.register(selector, channel2.validOps());
+        
+		synchronized (Kqueues64bitTest_R4258155.lock) {
+			while (Kqueues64bitTest_R4258155.parttwo == false)
+				Kqueues64bitTest_R4258155.lock.wait();
+		}
+        
+		int count = selector.select();
+		assertFalse("Should get at least one selected channel", (count==0));
+		// System.out.println("selector.select() returned : " + count);
+		Set <SelectionKey> selectedKeys = selector.selectedKeys();
+		for (SelectionKey key : selectedKeys) {
+			boolean IKnowTheKey = key.equals(channel1Key) || key.equals(channel2Key);
+			assertTrue("Got a key I know nothing about", IKnowTheKey);
+            
+		}
+		selector.close();
+	}
+}
+
+class ServerThread extends Thread
+{
+	public void run() {
+		try {
+			ServerSocket server = new ServerSocket(Kqueues64bitTest_R4258155.PORT);
+            
+			synchronized (Kqueues64bitTest_R4258155.lock) {
+				Kqueues64bitTest_R4258155.startTest = true;
+				Kqueues64bitTest_R4258155.lock.notify();
+			}
+            
+			// Wait for two connections
+			Socket conn1 = server.accept();
+			Socket conn2 = server.accept();
+            
+            
+			conn1.getOutputStream().write(61);
+			conn2.getOutputStream().write(62);
+            
+			synchronized (Kqueues64bitTest_R4258155.lock) {
+				Kqueues64bitTest_R4258155.parttwo = true;
+				Kqueues64bitTest_R4258155.lock.notify();
+			}
+            
+			server.close();
+		} catch (IOException ioe) {
+			ioe.printStackTrace();
+		}
+	}
+}
diff -r 0870207843e2 test/java/nio/channels/Selector/SelectorKqueueTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/Selector/SelectorKqueueTest.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ @test
+ @summary com.apple.junit.java.nio.Selector
+ @library ../../regtesthelpers
+ @run main SelectorKqueueTest
+ */
+
+import junit.framework.*;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.util.Iterator;
+
+public class SelectorKqueueTest extends TestCase
+{
+	public static final boolean DEBUG =	false;
+	public static final int	PORT	=	1234;
+    
+	private Pipe	signal;
+	private Thread	listener;
+	private volatile boolean	running;
+    
+    public static Test suite() {
+        return new TestSuite( SelectorKqueueTest.class);
+    }
+    
+    public static void main( String[] args ) {
+        junit.textui.TestRunner.run( suite() );
+    }
+    
+    public void testSelector() {
+		SelectorKqueueTest	test;
+        
+		try {
+			test=new SelectorKqueueTest();
+			test.start();
+			Thread.sleep(3000);
+			test.stop();
+        }
+		catch( Throwable x ) {
+			x.printStackTrace(System.err);
+        }
+	}
+    
+	public SelectorKqueueTest() {
+		super();
+		signal=null;
+		listener=null;
+		running=false;
+	}
+    
+	public void start() throws IOException {
+		if (DEBUG) {System.out.println("start");};
+        
+		running=true;
+        
+		signal=Pipe.open();
+		signal.source().configureBlocking(false);
+        
+		listener=new Thread() {
+			public void run() {
+				try {
+					listen();
+                }
+				catch( Throwable x ) {
+					x.printStackTrace(System.err);
+                }
+            }
+        };
+		listener.setPriority(Thread.NORM_PRIORITY);
+		listener.setDaemon(true);
+		listener.start();
+	}
+    
+	public void stop() throws IOException, InterruptedException {
+		if (DEBUG) {System.out.println("stop");};
+        
+		running=false;
+		signal();
+		listener.join();
+        
+		signal.sink().close();
+		signal.source().close();
+	}
+    
+	protected void listen() throws IOException {
+		ServerSocketChannel	server;
+		Selector			selector;
+		SelectionKey		key;
+		Iterator			iter;
+		int					ret;
+        
+		if (DEBUG) {System.out.println("start listening");};
+        
+		selector=Selector.open();
+        
+		server=ServerSocketChannel.open();
+		server.configureBlocking(false);
+		server.socket().setReuseAddress(true);
+		server.socket().bind(new InetSocketAddress(PORT),5);
+        
+		while (running) {
+			server.register(selector,SelectionKey.OP_ACCEPT);
+			signal.source().register(selector,SelectionKey.OP_READ);
+            
+			ret=selector.select();
+			if (DEBUG) {System.out.println("got #"+ret);};
+            
+			iter=selector.selectedKeys().iterator();
+			while (iter.hasNext()) {
+				key=(SelectionKey) iter.next();
+				iter.remove();
+                
+				if (key.isValid() && key.isAcceptable()) {
+					if (DEBUG) {System.out.println(" accept");};
+                }
+                
+				if (key.isValid() && key.isReadable()) {
+					if (DEBUG) {System.out.println(" read");};
+                }
+                
+				if (key.isValid() && key.isWritable()) {
+					if (DEBUG) {System.out.println(" write");};
+                }
+            }
+        }
+        
+		server.close();
+		selector.close();
+        
+		if (DEBUG) {System.out.println("stop listening");};
+	}
+    
+	protected void signal() throws IOException {
+		byte[]	dummy = new byte[] { (byte) 0 };
+        
+		//System.out.println("signal server");
+		signal.sink().write(ByteBuffer.wrap(dummy));
+	}
+}
diff -r 0870207843e2 test/java/nio/channels/Selector/TestNIOLocalChannels.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/Selector/TestNIOLocalChannels.java	Thu Sep 22 23:15:12 2011 -0700
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ @test
+ @summary This tests the basic functionality of sockets and selectors via local channels. 
+ @summary It starts a server on one Thread, then it starts a client on another thread. 
+ @summary It then checks for the validity of the data transfered betweenthem. 
+ @summary If the data is not transmitted correctly the tests reports an error.
+ @summary com.apple.junit.java.nio.Selector
+ @library ../../regtesthelpers
+ @run main TestNIOLocalChannels
+ */
+
+import junit.framework.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.util.Iterator;
+
+public class TestNIOLocalChannels extends TestCase 
+{
+    static final int PORT = 10000;
+    
+    public static Object lock = new Object();
+    public static boolean finishedReading = false;
+    public static int correctAnswers = 0;
+    
+    
+    protected void setUp()
+    {
+    	new Server().start();
+        
+    }
+    
+    protected void tearDown()
+    {
+    }
+    
+    public void testTestMe() throws Exception
+    {
+    	int count = 0;
+    	while (true)
+    	{
+    		count++;
+    		synchronized(lock)
+    		{
+				if (finishedReading)
+				{
+					assertTrue(" The transfered data from the server to the client didn't match exactly", correctAnswers > 50);
+					break;
+				}
+			}
+    		Thread.sleep(200);
+    		
+    		// this means that the test hung - ABORT
+    		if (count == 1000)  
+    		{
+    			finishedReading = true;
+    			assertTrue(" The test hung - ABORTING", false);
+    			break;
+    		}
+    	}
+    }
+    
+    public static Test suite()
+    {
+        return new TestSuite(TestNIOLocalChannels.class);
+    }
+    
+    public static void main (String[] args)
+    {
+        junit.textui.TestRunner.run(suite());
+    }
+}
+
+/*
+ * Simple HTTP response server, adapted from O'Reilly NIO book's echo
+ * server example.
+ */
+class Server extends Thread {
+    
+    static final byte [] RESPONSE_BYTES =
+    "HTTP/1.0 200 OK\r\nContent-Type: image/gif\r\nContent-Length: 2\r\nServer: D1\r\nConnection: close\r\n\r\nHello".getBytes();
+    
+    final ByteBuffer mRequestBuf;
+    final ByteBuffer mResponseBuf;
+    
+    Server() {
+        mRequestBuf = ByteBuffer.allocateDirect(4096);
+        mResponseBuf = ByteBuffer.allocateDirect(RESPONSE_BYTES.length);
+        mResponseBuf.put(RESPONSE_BYTES);
+        mResponseBuf.flip();
+    }
+    
+    public void run() {
+        try {
+            
+            final ServerSocketChannel serverChannel = ServerSocketChannel.open();
+            
+            serverChannel.socket().bind(new InetSocketAddress(TestNIOLocalChannels.PORT));
+            serverChannel.configureBlocking(false);
+            
+            final Selector selector = Selector.open();
+            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
+            
+            // now we can run our client thread
+            new Client().start();
+            
+            while (true) {
+                
+				synchronized(TestNIOLocalChannels.lock)
+				{
+					if (TestNIOLocalChannels.finishedReading)
+					{
+						break;
+					}
+				}
+                
+                // Block and spin until at least one key is ready.
+                if (selector.select(1000) == 0)
+                    continue;
+                
+                final Iterator keyItr = selector.selectedKeys().iterator();
+                while (keyItr.hasNext()) {
+                    
+                    final SelectionKey key = (SelectionKey) keyItr.next();
+                    
+                    // Set new connections to readable.
+                    if (key.isAcceptable()) {
+                        final SocketChannel ch = ((ServerSocketChannel) key.channel()).accept();
+                        if (ch == null)
+                            return;
+                        ch.configureBlocking(false);
+                        ch.register(selector, SelectionKey.OP_READ);
+                    }
+                    
+                    // Handle readable connections.
+                    else if (key.isReadable()) {
+                        final SocketChannel ch = (SocketChannel) key.channel();
+                        ch.read(mRequestBuf);
+                        mRequestBuf.clear(); // don't need data for testing.
+						mResponseBuf.rewind();
+                        ch.write(mResponseBuf);
+                        ch.close();
+                    }
+                    
+                    // assert increment();
+                    keyItr.remove();
+                }
+            }
+            
+        } catch (Exception e) {
+            System.err.println("PixelServer: exception in main select loop!");
+            e.printStackTrace();
+        }
+    }
+}
+
+/**
+ * Simple HTTP client with statistics logging.
+ */
+class Client extends Thread {
+    public void run() {
+        try {
+            final byte [] buf = new byte[4096];
+            char[] expectedResponse = { 'H', 'e', 'l', 'l', 'o' };
+            int count = 0;
+            while (true) {
+                
+            	synchronized(TestNIOLocalChannels.lock)
+				{
+					if (TestNIOLocalChannels.finishedReading)
+					{
+						break;
+					}
+				}
+                
+            	final InputStream is = new URL("http://localhost:"+TestNIOLocalChannels.PORT+"/"; + count).openStream();
+                int num = 0;
+                while (num != -1)
+                {
+                	num = is.read(buf);
+                	for (int i = 0; i < num; i++)
+                	{
+                		if (((char) buf[i]) == expectedResponse[i])
+                		{
+                			TestNIOLocalChannels.correctAnswers++;
+                		}
+                		else
+                		{
+                			TestNIOLocalChannels.correctAnswers = -1;
+                			break;
+                		}
+                	}
+                }
+                is.close();
+                
+                // we got 50 correct answers, we can break now
+                if (TestNIOLocalChannels.correctAnswers > 50)
+                {
+                	break;
+                }
+                
+                if (TestNIOLocalChannels.correctAnswers == -1)
+                { 
+                	break;
+                }
+                //                 if (count % 5000 == 0) {
+                //                     long t = System.currentTimeMillis();
+                //                     System.out.println("5k hits in " + (t - time) + "ms");
+                //                     time = t;
+                //                 }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+		synchronized(TestNIOLocalChannels.lock)
+		{
+			TestNIOLocalChannels.finishedReading = true;
+		}
+    }
+}
\ No newline at end of file
diff -r 0870207843e2 test/sun/nio/ch/SelProvider.java
--- a/test/sun/nio/ch/SelProvider.java	Sun Sep 11 10:51:01 2011 -0700
+++ b/test/sun/nio/ch/SelProvider.java	Thu Sep 22 23:15:12 2011 -0700
@@ -50,6 +50,8 @@
             } else {
                 throw new RuntimeException("Test does not recognize this operating system");
             }
+        } else if (osname.contains("Mac OS X") || osname.contains("BSD")) {
+            expected = "sun.nio.ch.KQueueSelectorProvider"; 
         } else
             return;
         if (!spName.equals(expected))


Reply via email to