7143744: (se) Stabilize KQueue SelectorProvider and make default on MacOSX
Reviewed-by: michaelm, chegar
--- a/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java Mon Apr 16 20:12:20 2012 +0100
@@ -4,7 +4,9 @@
*
* 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.
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@@ -40,7 +42,7 @@
* Returns the default SelectorProvider.
*/
public static SelectorProvider create() {
- return new sun.nio.ch.PollSelectorProvider();
+ return new sun.nio.ch.KQueueSelectorProvider();
}
}
--- a/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java Mon Apr 16 20:12:20 2012 +0100
@@ -4,7 +4,9 @@
*
* 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.
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@@ -64,8 +66,8 @@
static short FD_OFFSET;
static short FILTER_OFFSET;
- // kevent array size (just under 1K bytes)
- static final int NUM_KEVENTS = 50;
+ // kevent array size
+ static final int NUM_KEVENTS = 128;
// Are we in a 64-bit VM?
static boolean is64bit = false;
--- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java Mon Apr 16 20:12:20 2012 +0100
@@ -4,7 +4,9 @@
*
* 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.
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@@ -49,8 +51,8 @@
// Count of registered descriptors (including interrupt)
private int totalChannels;
- // Map from file descriptors to selection keys
- private HashMap<Integer,SelectionKeyImpl> fdToKey;
+ // Map from a file descriptor to an entry containing the selection key
+ private HashMap<Integer,MapEntry> fdMap;
// True if this Selector has been closed
private boolean closed = false;
@@ -59,6 +61,20 @@
private Object interruptLock = new Object();
private boolean interruptTriggered = false;
+ // used by updateSelectedKeys to handle cases where the same file
+ // descriptor is polled by more than one filter
+ private long updateCount;
+
+ // Used to map file descriptors to a selection key and "update count"
+ // (see updateSelectedKeys for usage).
+ private static class MapEntry {
+ SelectionKeyImpl ski;
+ long updateCount;
+ MapEntry(SelectionKeyImpl ski) {
+ this.ski = ski;
+ }
+ }
+
/**
* Package private constructor called by factory method in
* the abstract superclass Selector.
@@ -70,7 +86,7 @@
fd1 = (int)fds;
kqueueWrapper = new KQueueArrayWrapper();
kqueueWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<>();
+ fdMap = new HashMap<>();
totalChannels = 1;
}
@@ -82,8 +98,6 @@
if (closed)
throw new ClosedSelectorException();
processDeregisterQueue();
- if (timeout == 0 && totalChannels == 1)
- return 0;
try {
begin();
entries = kqueueWrapper.poll(timeout);
@@ -94,10 +108,9 @@
return updateSelectedKeys(entries);
}
-
/**
- * Update the keys whose fd's have been selected by the devpoll
- * driver. Add the ready keys to the ready queue.
+ * Update the keys whose fd's have been selected by kqueue.
+ * Add the ready keys to the selected key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int entries)
@@ -106,24 +119,42 @@
int numKeysUpdated = 0;
boolean interrupted = false;
+ // A file descriptor may be registered with kqueue with more than one
+ // filter and so there may be more than one event for a fd. The update
+ // count in the MapEntry tracks when the fd was last updated and this
+ // ensures that the ready ops are updated rather than replaced by a
+ // second or subsequent event.
+ updateCount++;
+
for (int i = 0; i < entries; i++) {
int nextFD = kqueueWrapper.getDescriptor(i);
if (nextFD == fd0) {
interrupted = true;
} else {
- SelectionKeyImpl ski = fdToKey.get(new Integer(nextFD));
- // ski is null in the case of an interrupt
- if (ski != null) {
+ MapEntry me = fdMap.get(Integer.valueOf(nextFD));
+
+ // entry is null in the case of an interrupt
+ if (me != null) {
int rOps = kqueueWrapper.getReventOps(i);
+ SelectionKeyImpl ski = me.ski;
if (selectedKeys.contains(ski)) {
- if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
- numKeysUpdated++;
+ // first time this file descriptor has been encountered on this
+ // update?
+ if (me.updateCount != updateCount) {
+ if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+ numKeysUpdated++;
+ me.updateCount = updateCount;
+ }
+ } else {
+ // ready ops have already been set on this update
+ ski.channel.translateAndUpdateReadyOps(rOps, ski);
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
- if ((ski.readyOps() & ski.interestOps()) != 0) {
+ if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
+ me.updateCount = updateCount;
}
}
}
@@ -137,7 +168,6 @@
interruptTriggered = false;
}
}
-
return numKeysUpdated;
}
@@ -145,6 +175,12 @@
protected void implClose() throws IOException {
if (!closed) {
closed = true;
+
+ // prevent further wakeup
+ synchronized (interruptLock) {
+ interruptTriggered = true;
+ }
+
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
if (kqueueWrapper != null) {
@@ -172,8 +208,10 @@
protected void implRegister(SelectionKeyImpl ski) {
+ if (closed)
+ throw new ClosedSelectorException();
int fd = IOUtil.fdVal(ski.channel.getFD());
- fdToKey.put(new Integer(fd), ski);
+ fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
totalChannels++;
keys.add(ski);
}
@@ -181,7 +219,7 @@
protected void implDereg(SelectionKeyImpl ski) throws IOException {
int fd = ski.channel.getFDVal();
- fdToKey.remove(new Integer(fd));
+ fdMap.remove(Integer.valueOf(fd));
kqueueWrapper.release(fd);
totalChannels--;
keys.remove(ski);
@@ -194,6 +232,8 @@
public void putEventOps(SelectionKeyImpl ski, int ops) {
+ if (closed)
+ throw new ClosedSelectorException();
int fd = IOUtil.fdVal(ski.channel.getFD());
kqueueWrapper.setInterest(fd, ops);
}
--- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java Mon Apr 16 20:12:20 2012 +0100
@@ -4,7 +4,9 @@
*
* 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.
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
--- a/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c Mon Apr 16 20:12:20 2012 +0100
@@ -4,7 +4,9 @@
*
* 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.
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
--- a/jdk/test/java/nio/channels/Selector/OpRead.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/test/java/nio/channels/Selector/OpRead.java Mon Apr 16 20:12:20 2012 +0100
@@ -58,7 +58,10 @@
boolean done = false;
int failCount = 0;
while (!done) {
- if (selector.select() > 0) {
+ int nSelected = selector.select();
+ if (nSelected > 0) {
+ if (nSelected > 1)
+ throw new RuntimeException("More than one channel selected");
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
--- a/jdk/test/sun/nio/ch/SelProvider.java Mon Apr 16 11:12:10 2012 +0800
+++ b/jdk/test/sun/nio/ch/SelProvider.java Mon Apr 16 20:12:20 2012 +0100
@@ -38,20 +38,9 @@
if ("SunOS".equals(osname)) {
expected = "sun.nio.ch.DevPollSelectorProvider";
} else if ("Linux".equals(osname)) {
- String[] vers = osver.split("\\.", 0);
- if (vers.length >= 2) {
- int major = Integer.parseInt(vers[0]);
- int minor = Integer.parseInt(vers[1]);
- if (major > 2 || (major == 2 && minor >= 6)) {
- expected = "sun.nio.ch.EPollSelectorProvider";
- } else {
- expected = "sun.nio.ch.PollSelectorProvider";
- }
- } else {
- throw new RuntimeException("Test does not recognize this operating system");
- }
+ expected = "sun.nio.ch.EPollSelectorProvider";
} else if (osname.startsWith("Mac OS")) {
- expected = "sun.nio.ch.PollSelectorProvider";
+ expected = "sun.nio.ch.KQueueSelectorProvider";
} else
return;
if (!spName.equals(expected))