7143744: (se) Stabilize KQueue SelectorProvider and make default on MacOSX
Reviewed-by: michaelm, chegar
This commit is contained in:
parent
a51733d81d
commit
b29ee10938
@ -4,7 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* 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
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
@ -40,7 +42,7 @@ public class DefaultSelectorProvider {
|
|||||||
* Returns the default SelectorProvider.
|
* Returns the default SelectorProvider.
|
||||||
*/
|
*/
|
||||||
public static SelectorProvider create() {
|
public static SelectorProvider create() {
|
||||||
return new sun.nio.ch.PollSelectorProvider();
|
return new sun.nio.ch.KQueueSelectorProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* 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
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
@ -64,8 +66,8 @@ class KQueueArrayWrapper {
|
|||||||
static short FD_OFFSET;
|
static short FD_OFFSET;
|
||||||
static short FILTER_OFFSET;
|
static short FILTER_OFFSET;
|
||||||
|
|
||||||
// kevent array size (just under 1K bytes)
|
// kevent array size
|
||||||
static final int NUM_KEVENTS = 50;
|
static final int NUM_KEVENTS = 128;
|
||||||
|
|
||||||
// Are we in a 64-bit VM?
|
// Are we in a 64-bit VM?
|
||||||
static boolean is64bit = false;
|
static boolean is64bit = false;
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* 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
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
@ -49,8 +51,8 @@ class KQueueSelectorImpl
|
|||||||
// Count of registered descriptors (including interrupt)
|
// Count of registered descriptors (including interrupt)
|
||||||
private int totalChannels;
|
private int totalChannels;
|
||||||
|
|
||||||
// Map from file descriptors to selection keys
|
// Map from a file descriptor to an entry containing the selection key
|
||||||
private HashMap<Integer,SelectionKeyImpl> fdToKey;
|
private HashMap<Integer,MapEntry> fdMap;
|
||||||
|
|
||||||
// True if this Selector has been closed
|
// True if this Selector has been closed
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
@ -59,6 +61,20 @@ class KQueueSelectorImpl
|
|||||||
private Object interruptLock = new Object();
|
private Object interruptLock = new Object();
|
||||||
private boolean interruptTriggered = false;
|
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
|
* Package private constructor called by factory method in
|
||||||
* the abstract superclass Selector.
|
* the abstract superclass Selector.
|
||||||
@ -70,7 +86,7 @@ class KQueueSelectorImpl
|
|||||||
fd1 = (int)fds;
|
fd1 = (int)fds;
|
||||||
kqueueWrapper = new KQueueArrayWrapper();
|
kqueueWrapper = new KQueueArrayWrapper();
|
||||||
kqueueWrapper.initInterrupt(fd0, fd1);
|
kqueueWrapper.initInterrupt(fd0, fd1);
|
||||||
fdToKey = new HashMap<>();
|
fdMap = new HashMap<>();
|
||||||
totalChannels = 1;
|
totalChannels = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +98,6 @@ class KQueueSelectorImpl
|
|||||||
if (closed)
|
if (closed)
|
||||||
throw new ClosedSelectorException();
|
throw new ClosedSelectorException();
|
||||||
processDeregisterQueue();
|
processDeregisterQueue();
|
||||||
if (timeout == 0 && totalChannels == 1)
|
|
||||||
return 0;
|
|
||||||
try {
|
try {
|
||||||
begin();
|
begin();
|
||||||
entries = kqueueWrapper.poll(timeout);
|
entries = kqueueWrapper.poll(timeout);
|
||||||
@ -94,10 +108,9 @@ class KQueueSelectorImpl
|
|||||||
return updateSelectedKeys(entries);
|
return updateSelectedKeys(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the keys whose fd's have been selected by the devpoll
|
* Update the keys whose fd's have been selected by kqueue.
|
||||||
* driver. Add the ready keys to the ready queue.
|
* Add the ready keys to the selected key set.
|
||||||
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
||||||
*/
|
*/
|
||||||
private int updateSelectedKeys(int entries)
|
private int updateSelectedKeys(int entries)
|
||||||
@ -106,24 +119,42 @@ class KQueueSelectorImpl
|
|||||||
int numKeysUpdated = 0;
|
int numKeysUpdated = 0;
|
||||||
boolean interrupted = false;
|
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++) {
|
for (int i = 0; i < entries; i++) {
|
||||||
int nextFD = kqueueWrapper.getDescriptor(i);
|
int nextFD = kqueueWrapper.getDescriptor(i);
|
||||||
if (nextFD == fd0) {
|
if (nextFD == fd0) {
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
} else {
|
} else {
|
||||||
SelectionKeyImpl ski = fdToKey.get(new Integer(nextFD));
|
MapEntry me = fdMap.get(Integer.valueOf(nextFD));
|
||||||
// ski is null in the case of an interrupt
|
|
||||||
if (ski != null) {
|
// entry is null in the case of an interrupt
|
||||||
|
if (me != null) {
|
||||||
int rOps = kqueueWrapper.getReventOps(i);
|
int rOps = kqueueWrapper.getReventOps(i);
|
||||||
|
SelectionKeyImpl ski = me.ski;
|
||||||
if (selectedKeys.contains(ski)) {
|
if (selectedKeys.contains(ski)) {
|
||||||
|
// first time this file descriptor has been encountered on this
|
||||||
|
// update?
|
||||||
|
if (me.updateCount != updateCount) {
|
||||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||||
numKeysUpdated++;
|
numKeysUpdated++;
|
||||||
|
me.updateCount = updateCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ready ops have already been set on this update
|
||||||
|
ski.channel.translateAndUpdateReadyOps(rOps, ski);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ski.channel.translateAndSetReadyOps(rOps, ski);
|
ski.channel.translateAndSetReadyOps(rOps, ski);
|
||||||
if ((ski.readyOps() & ski.interestOps()) != 0) {
|
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
|
||||||
selectedKeys.add(ski);
|
selectedKeys.add(ski);
|
||||||
numKeysUpdated++;
|
numKeysUpdated++;
|
||||||
|
me.updateCount = updateCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +168,6 @@ class KQueueSelectorImpl
|
|||||||
interruptTriggered = false;
|
interruptTriggered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return numKeysUpdated;
|
return numKeysUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +175,12 @@ class KQueueSelectorImpl
|
|||||||
protected void implClose() throws IOException {
|
protected void implClose() throws IOException {
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
|
// prevent further wakeup
|
||||||
|
synchronized (interruptLock) {
|
||||||
|
interruptTriggered = true;
|
||||||
|
}
|
||||||
|
|
||||||
FileDispatcherImpl.closeIntFD(fd0);
|
FileDispatcherImpl.closeIntFD(fd0);
|
||||||
FileDispatcherImpl.closeIntFD(fd1);
|
FileDispatcherImpl.closeIntFD(fd1);
|
||||||
if (kqueueWrapper != null) {
|
if (kqueueWrapper != null) {
|
||||||
@ -172,8 +208,10 @@ class KQueueSelectorImpl
|
|||||||
|
|
||||||
|
|
||||||
protected void implRegister(SelectionKeyImpl ski) {
|
protected void implRegister(SelectionKeyImpl ski) {
|
||||||
|
if (closed)
|
||||||
|
throw new ClosedSelectorException();
|
||||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||||
fdToKey.put(new Integer(fd), ski);
|
fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
|
||||||
totalChannels++;
|
totalChannels++;
|
||||||
keys.add(ski);
|
keys.add(ski);
|
||||||
}
|
}
|
||||||
@ -181,7 +219,7 @@ class KQueueSelectorImpl
|
|||||||
|
|
||||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||||
int fd = ski.channel.getFDVal();
|
int fd = ski.channel.getFDVal();
|
||||||
fdToKey.remove(new Integer(fd));
|
fdMap.remove(Integer.valueOf(fd));
|
||||||
kqueueWrapper.release(fd);
|
kqueueWrapper.release(fd);
|
||||||
totalChannels--;
|
totalChannels--;
|
||||||
keys.remove(ski);
|
keys.remove(ski);
|
||||||
@ -194,6 +232,8 @@ class KQueueSelectorImpl
|
|||||||
|
|
||||||
|
|
||||||
public void putEventOps(SelectionKeyImpl ski, int ops) {
|
public void putEventOps(SelectionKeyImpl ski, int ops) {
|
||||||
|
if (closed)
|
||||||
|
throw new ClosedSelectorException();
|
||||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||||
kqueueWrapper.setInterest(fd, ops);
|
kqueueWrapper.setInterest(fd, ops);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* 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
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* 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
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
@ -58,7 +58,10 @@ public class OpRead {
|
|||||||
boolean done = false;
|
boolean done = false;
|
||||||
int failCount = 0;
|
int failCount = 0;
|
||||||
while (!done) {
|
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();
|
Set<SelectionKey> keys = selector.selectedKeys();
|
||||||
Iterator<SelectionKey> iterator = keys.iterator();
|
Iterator<SelectionKey> iterator = keys.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
|
@ -38,20 +38,9 @@ public class SelProvider {
|
|||||||
if ("SunOS".equals(osname)) {
|
if ("SunOS".equals(osname)) {
|
||||||
expected = "sun.nio.ch.DevPollSelectorProvider";
|
expected = "sun.nio.ch.DevPollSelectorProvider";
|
||||||
} else if ("Linux".equals(osname)) {
|
} 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";
|
expected = "sun.nio.ch.EPollSelectorProvider";
|
||||||
} else {
|
|
||||||
expected = "sun.nio.ch.PollSelectorProvider";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Test does not recognize this operating system");
|
|
||||||
}
|
|
||||||
} else if (osname.startsWith("Mac OS")) {
|
} else if (osname.startsWith("Mac OS")) {
|
||||||
expected = "sun.nio.ch.PollSelectorProvider";
|
expected = "sun.nio.ch.KQueueSelectorProvider";
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
if (!spName.equals(expected))
|
if (!spName.equals(expected))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user