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 : [email protected]
Eyes Beyond Web : http://www.eyesbeyond.com
Information Technology FreeBSD : [email protected]
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))