diff --git a/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java b/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java index 16af3aa64d0..e717c6ca1cc 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java +++ b/jdk/src/macosx/classes/sun/nio/ch/DefaultSelectorProvider.java @@ -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 @@ public class DefaultSelectorProvider { * Returns the default SelectorProvider. */ public static SelectorProvider create() { - return new sun.nio.ch.PollSelectorProvider(); + return new sun.nio.ch.KQueueSelectorProvider(); } } diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java index 71d098d2879..7ec35f1bc6d 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java +++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java @@ -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 @@ class KQueueArrayWrapper { 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; diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java index 60d523bb383..b1504264474 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java +++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java @@ -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 @@ class KQueueSelectorImpl // Count of registered descriptors (including interrupt) private int totalChannels; - // Map from file descriptors to selection keys - private HashMap fdToKey; + // Map from a file descriptor to an entry containing the selection key + private HashMap fdMap; // True if this Selector has been closed private boolean closed = false; @@ -59,6 +61,20 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl fd1 = (int)fds; kqueueWrapper = new KQueueArrayWrapper(); kqueueWrapper.initInterrupt(fd0, fd1); - fdToKey = new HashMap<>(); + fdMap = new HashMap<>(); totalChannels = 1; } @@ -82,8 +98,6 @@ class KQueueSelectorImpl if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); - if (timeout == 0 && totalChannels == 1) - return 0; try { begin(); entries = kqueueWrapper.poll(timeout); @@ -94,10 +108,9 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl interruptTriggered = false; } } - return numKeysUpdated; } @@ -145,6 +175,12 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl 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 @@ class KQueueSelectorImpl public void putEventOps(SelectionKeyImpl ski, int ops) { + if (closed) + throw new ClosedSelectorException(); int fd = IOUtil.fdVal(ski.channel.getFD()); kqueueWrapper.setInterest(fd, ops); } diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java index 6e7b7cf3904..e07775f45a9 100644 --- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java +++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java @@ -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 diff --git a/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c b/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c index a26b317aec0..8d49d9cb666 100644 --- a/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c +++ b/jdk/src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c @@ -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 diff --git a/jdk/test/java/nio/channels/Selector/OpRead.java b/jdk/test/java/nio/channels/Selector/OpRead.java index 78340509ed6..cec477901ff 100644 --- a/jdk/test/java/nio/channels/Selector/OpRead.java +++ b/jdk/test/java/nio/channels/Selector/OpRead.java @@ -58,7 +58,10 @@ public class OpRead { 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 keys = selector.selectedKeys(); Iterator iterator = keys.iterator(); while (iterator.hasNext()) { diff --git a/jdk/test/sun/nio/ch/SelProvider.java b/jdk/test/sun/nio/ch/SelProvider.java index 53b18cb529a..cae745f5b78 100644 --- a/jdk/test/sun/nio/ch/SelProvider.java +++ b/jdk/test/sun/nio/ch/SelProvider.java @@ -38,20 +38,9 @@ public class SelProvider { 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))