8200583: (se) Selector clean-up, part 4
authoralanb
Thu, 05 Apr 2018 15:01:57 +0100
changeset 49526 cad4c844902a
parent 49525 4d98473ed33e
child 49527 5aa40f834b50
8200583: (se) Selector clean-up, part 4 Reviewed-by: bpb, chegar
src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
src/java.base/share/classes/sun/nio/ch/SelChImpl.java
src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java
src/java.base/share/classes/sun/nio/ch/SelectorImpl.java
src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java
src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c
src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java
src/java.base/windows/classes/sun/nio/ch/PollArrayWrapper.java
src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java
--- a/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -63,20 +63,14 @@
     // maps file descriptor to selection key, synchronize on selector
     private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
 
-    // pending new registrations/updates, queued by implRegister and putEventOpos
+    // pending new registrations/updates, queued by setEventOps
     private final Object updateLock = new Object();
-    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
     // interrupt triggering and clearing
     private final Object interruptLock = new Object();
     private boolean interruptTriggered;
 
-    /**
-     * Package private constructor called by factory method in
-     * the abstract superclass Selector.
-     */
     EPollSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
 
@@ -140,30 +134,21 @@
     }
 
     /**
-     * Process new registrations and changes to the interest ops.
+     * Process changes to the interest ops.
      */
     private void processUpdateQueue() {
         assert Thread.holdsLock(this);
 
         synchronized (updateLock) {
             SelectionKeyImpl ski;
-
-            // new registrations
-            while ((ski = newKeys.pollFirst()) != null) {
+            while ((ski = updateKeys.pollFirst()) != null) {
                 if (ski.isValid()) {
-                    int fd = ski.channel.getFDVal();
-                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
-                    assert previous == null;
-                    assert ski.registeredEvents() == 0;
-                }
-            }
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
 
-            // changes to interest ops
-            assert updateKeys.size() == updateEvents.size();
-            while ((ski = updateKeys.pollFirst()) != null) {
-                int newEvents = updateEvents.pollFirst();
-                int fd = ski.channel.getFDVal();
-                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                    int newEvents = ski.translateInterestOps();
                     int registeredEvents = ski.registeredEvents();
                     if (newEvents != registeredEvents) {
                         if (newEvents == 0) {
@@ -206,11 +191,11 @@
                 if (ski != null) {
                     int rOps = EPoll.getEvents(event);
                     if (selectedKeys.contains(ski)) {
-                        if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                        if (ski.translateAndSetReadyOps(rOps)) {
                             numKeysUpdated++;
                         }
                     } else {
-                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        ski.translateAndSetReadyOps(rOps);
                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                             selectedKeys.add(ski);
                             numKeysUpdated++;
@@ -244,19 +229,11 @@
     }
 
     @Override
-    protected void implRegister(SelectionKeyImpl ski) {
-        ensureOpen();
-        synchronized (updateLock) {
-            newKeys.addLast(ski);
-        }
-    }
-
-    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         assert !ski.isValid();
         assert Thread.holdsLock(this);
 
-        int fd = ski.channel.getFDVal();
+        int fd = ski.getFDVal();
         if (fdToKey.remove(fd) != null) {
             if (ski.registeredEvents() != 0) {
                 EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
@@ -268,10 +245,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);  // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -62,11 +62,9 @@
     // maps file descriptor to selection key, synchronize on selector
     private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
 
-    // pending new registrations/updates, queued by implRegister and putEventOps
+    // pending new registrations/updates, queued by setEventOps
     private final Object updateLock = new Object();
-    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
     // interrupt triggering and clearing
     private final Object interruptLock = new Object();
@@ -138,30 +136,21 @@
     }
 
     /**
-     * Process new registrations and changes to the interest ops.
+     * Process changes to the interest ops.
      */
     private void processUpdateQueue() {
         assert Thread.holdsLock(this);
 
         synchronized (updateLock) {
             SelectionKeyImpl ski;
-
-            // new registrations
-            while ((ski = newKeys.pollFirst()) != null) {
+            while ((ski = updateKeys.pollFirst()) != null) {
                 if (ski.isValid()) {
-                    int fd = ski.channel.getFDVal();
-                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
-                    assert previous == null;
-                    assert ski.registeredEvents() == 0;
-                }
-            }
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
 
-            // changes to interest ops
-            assert updateKeys.size() == updateKeys.size();
-            while ((ski = updateKeys.pollFirst()) != null) {
-                int newEvents = updateEvents.pollFirst();
-                int fd = ski.channel.getFDVal();
-                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                    int newEvents = ski.translateInterestOps();
                     int registeredEvents = ski.registeredEvents();
                     if (newEvents != registeredEvents) {
 
@@ -229,16 +218,16 @@
                     if (selectedKeys.contains(ski)) {
                         // file descriptor may be polled more than once per poll
                         if (ski.lastPolled != pollCount) {
-                            if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                            if (ski.translateAndSetReadyOps(rOps)) {
                                 numKeysUpdated++;
                                 ski.lastPolled = pollCount;
                             }
                         } else {
                             // ready ops have already been set on this update
-                            ski.channel.translateAndUpdateReadyOps(rOps, ski);
+                            ski.translateAndUpdateReadyOps(rOps);
                         }
                     } else {
-                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        ski.translateAndSetReadyOps(rOps);
                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                             selectedKeys.add(ski);
                             numKeysUpdated++;
@@ -273,19 +262,11 @@
     }
 
     @Override
-    protected void implRegister(SelectionKeyImpl ski) {
-        ensureOpen();
-        synchronized (updateLock) {
-            newKeys.addLast(ski);
-        }
-    }
-
-    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         assert !ski.isValid();
         assert Thread.holdsLock(this);
 
-        int fd = ski.channel.getFDVal();
+        int fd = ski.getFDVal();
         int registeredEvents = ski.registeredEvents();
         if (fdToKey.remove(fd) != null) {
             if (registeredEvents != 0) {
@@ -301,10 +282,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);  // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }
--- a/src/java.base/share/classes/sun/nio/ch/SelChImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/share/classes/sun/nio/ch/SelChImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -49,7 +49,7 @@
      *          contains at least one bit that the previous value did not
      *          contain
      */
-    boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
+    boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski);
 
     /**
      * Sets the specified ops if present in interestOps. The specified
@@ -59,7 +59,7 @@
      *          contains at least one bit that the previous value did not
      *          contain
      */
-    boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
+    boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski);
 
     /**
      * Translates an interest operation set into a native event set
--- a/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -39,7 +39,7 @@
 public final class SelectionKeyImpl
     extends AbstractSelectionKey
 {
-    final SelChImpl channel;                            // package-private
+    private final SelChImpl channel;
     private final SelectorImpl selector;
 
     private volatile int interestOps;
@@ -61,6 +61,10 @@
             throw new CancelledKeyException();
     }
 
+    int getFDVal() {
+        return channel.getFDVal();
+    }
+
     @Override
     public SelectableChannel channel() {
         return (SelectableChannel)channel;
@@ -103,8 +107,8 @@
     public SelectionKey nioInterestOps(int ops) {
         if ((ops & ~channel().validOps()) != 0)
             throw new IllegalArgumentException();
-        selector.putEventOps(this, channel.translateInterestOps(ops));
         interestOps = ops;
+        selector.setEventOps(this);
         return this;
     }
 
@@ -112,6 +116,18 @@
         return interestOps;
     }
 
+    int translateInterestOps() {
+        return channel.translateInterestOps(interestOps);
+    }
+
+    boolean translateAndSetReadyOps(int ops) {
+        return channel.translateAndSetReadyOps(ops, this);
+    }
+
+    boolean translateAndUpdateReadyOps(int ops) {
+        return channel.translateAndUpdateReadyOps(ops, this);
+    }
+
     void registeredEvents(int events) {
         // assert Thread.holdsLock(selector);
         this.registeredEvents = events;
--- a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -64,17 +64,20 @@
         publicSelectedKeys = Util.ungrowableSet(selectedKeys);
     }
 
+    private void ensureOpen() {
+        if (!isOpen())
+            throw new ClosedSelectorException();
+    }
+
     @Override
     public final Set<SelectionKey> keys() {
-        if (!isOpen())
-            throw new ClosedSelectorException();
+        ensureOpen();
         return publicKeys;
     }
 
     @Override
     public final Set<SelectionKey> selectedKeys() {
-        if (!isOpen())
-            throw new ClosedSelectorException();
+        ensureOpen();
         return publicSelectedKeys;
     }
 
@@ -112,8 +115,7 @@
 
     private int lockAndDoSelect(long timeout) throws IOException {
         synchronized (this) {
-            if (!isOpen())
-                throw new ClosedSelectorException();
+            ensureOpen();
             synchronized (publicKeys) {
                 synchronized (publicSelectedKeys) {
                     return doSelect(timeout);
@@ -176,7 +178,8 @@
             throw new IllegalSelectorException();
         SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
         k.attach(attachment);
-        // register before adding to key set
+
+        // register with selector (if needed) before adding to key set
         implRegister(k);
         synchronized (publicKeys) {
             keys.add(k);
@@ -185,7 +188,15 @@
         return k;
     }
 
-    protected abstract void implRegister(SelectionKeyImpl ski);
+    /**
+     * Register the key in the selector.
+     *
+     * The default implementation checks if the selector is open. It should
+     * be overridden by selector implementations as needed.
+     */
+    protected void implRegister(SelectionKeyImpl ski) {
+        ensureOpen();
+    }
 
     protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
 
@@ -222,5 +233,5 @@
     /**
      * Change the event set in the selector
      */
-    protected abstract void putEventOps(SelectionKeyImpl ski, int events);
+    protected abstract void setEventOps(SelectionKeyImpl ski);
 }
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -55,17 +55,14 @@
     // maps file descriptor to selection key, synchronize on selector
     private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
 
-    // pending new registrations/updates, queued by implRegister and putEventOps
+    // pending new registrations/updates, queued by setEventOps
     private final Object updateLock = new Object();
-    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
     // interrupt triggering and clearing
     private final Object interruptLock = new Object();
     private boolean interruptTriggered;
 
-
     DevPollSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
         this.pollWrapper = new DevPollArrayWrapper();
@@ -88,18 +85,34 @@
     }
 
     @Override
-    protected int doSelect(long timeout)
-        throws IOException
-    {
+    protected int doSelect(long timeout) throws IOException {
         assert Thread.holdsLock(this);
-        boolean blocking = (timeout != 0);
+
+        long to = timeout;
+        boolean blocking = (to != 0);
+        boolean timedPoll = (to > 0);
 
         int numEntries;
         processUpdateQueue();
         processDeregisterQueue();
         try {
             begin(blocking);
-            numEntries = pollWrapper.poll(timeout);
+
+            do {
+                long startTime = timedPoll ? System.nanoTime() : 0;
+                numEntries = pollWrapper.poll(to);
+                if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
+                    // timed poll interrupted so need to adjust timeout
+                    long adjust = System.nanoTime() - startTime;
+                    to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+                    if (to <= 0) {
+                        // timeout expired so no retry
+                        numEntries = 0;
+                    }
+                }
+            } while (numEntries == IOStatus.INTERRUPTED);
+            assert IOStatus.check(numEntries);
+
         } finally {
             end(blocking);
         }
@@ -108,7 +121,7 @@
     }
 
     /**
-     * Process new registrations and changes to the interest ops.
+     * Process changes to the interest ops.
      */
     private void processUpdateQueue() throws IOException {
         assert Thread.holdsLock(this);
@@ -116,25 +129,18 @@
         synchronized (updateLock) {
             SelectionKeyImpl ski;
 
-            // new registrations
-            while ((ski = newKeys.pollFirst()) != null) {
-                if (ski.isValid()) {
-                    int fd = ski.channel.getFDVal();
-                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
-                    assert previous == null;
-                    assert ski.registeredEvents() == 0;
-                }
-            }
-
             // Translate the queued updates to changes to the set of monitored
             // file descriptors. The changes are written to the /dev/poll driver
             // in bulk.
-            assert updateKeys.size() == updateEvents.size();
             int index = 0;
             while ((ski = updateKeys.pollFirst()) != null) {
-                int newEvents = updateEvents.pollFirst();
-                int fd = ski.channel.getFDVal();
-                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                if (ski.isValid()) {
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
+
+                    int newEvents = ski.translateInterestOps();
                     int registeredEvents = ski.registeredEvents();
                     if (newEvents != registeredEvents) {
                         if (registeredEvents != 0)
@@ -178,11 +184,11 @@
                 if (ski != null) {
                     int rOps = pollWrapper.getReventOps(i);
                     if (selectedKeys.contains(ski)) {
-                        if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                        if (ski.translateAndSetReadyOps(rOps)) {
                             numKeysUpdated++;
                         }
                     } else {
-                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        ski.translateAndSetReadyOps(rOps);
                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                             selectedKeys.add(ski);
                             numKeysUpdated++;
@@ -214,20 +220,13 @@
         FileDispatcherImpl.closeIntFD(fd1);
     }
 
-    @Override
-    protected void implRegister(SelectionKeyImpl ski) {
-        ensureOpen();
-        synchronized (updateLock) {
-            newKeys.addLast(ski);
-        }
-    }
 
     @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         assert !ski.isValid();
         assert Thread.holdsLock(this);
 
-        int fd = ski.channel.getFDVal();
+        int fd = ski.getFDVal();
         if (fdToKey.remove(fd) != null) {
             if (ski.registeredEvents() != 0) {
                 pollWrapper.register(fd, POLLREMOVE);
@@ -239,10 +238,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);   // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }
--- a/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -72,12 +72,10 @@
     // the last update operation, incremented by processUpdateQueue
     private int lastUpdate;
 
-    // pending new registrations/updates, queued by implRegister, putEventOps,
-    // and updateSelectedKeys
+    // pending new registrations/updates, queued by setEventOps and
+    // updateSelectedKeys
     private final Object updateLock = new Object();
-    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
     // interrupt triggering and clearing
     private final Object interruptLock = new Object();
@@ -146,23 +144,14 @@
 
         synchronized (updateLock) {
             SelectionKeyImpl ski;
-
-            // new registrations
-            while ((ski = newKeys.pollFirst()) != null) {
+            while ((ski = updateKeys.pollFirst()) != null) {
                 if (ski.isValid()) {
-                    int fd = ski.channel.getFDVal();
-                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
-                    assert previous == null;
-                    assert ski.registeredEvents() == 0;
-                }
-            }
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
 
-            // changes to interest ops
-            assert updateKeys.size() == updateEvents.size();
-            while ((ski = updateKeys.pollFirst()) != null) {
-                int newEvents = updateEvents.pollFirst();
-                int fd = ski.channel.getFDVal();
-                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                    int newEvents = ski.translateInterestOps();
                     if (newEvents != ski.registeredEvents()) {
                         if (newEvents == 0) {
                             port_dissociate(pfd, PORT_SOURCE_FD, fd);
@@ -199,22 +188,20 @@
                     if (ski != null) {
                         int rOps = getEventOps(i);
                         if (selectedKeys.contains(ski)) {
-                            if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                            if (ski.translateAndSetReadyOps(rOps)) {
                                 numKeysUpdated++;
                             }
                         } else {
-                            ski.channel.translateAndSetReadyOps(rOps, ski);
+                            ski.translateAndSetReadyOps(rOps);
                             if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                                 selectedKeys.add(ski);
                                 numKeysUpdated++;
                             }
                         }
 
-                        // re-queue key to head so that it is re-associated at
-                        // next select (and before other changes)
-                        updateEvents.addFirst(ski.registeredEvents());
-                        updateKeys.addFirst(ski);
+                        // re-queue key so it re-associated at next select
                         ski.registeredEvents(0);
+                        updateKeys.addLast(ski);
                     }
                 } else if (source == PORT_SOURCE_USER) {
                     interrupted = true;
@@ -245,19 +232,11 @@
     }
 
     @Override
-    protected void implRegister(SelectionKeyImpl ski) {
-        ensureOpen();
-        synchronized (updateLock) {
-            newKeys.addLast(ski);
-        }
-    }
-
-    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         assert !ski.isValid();
         assert Thread.holdsLock(this);
 
-        int fd = ski.channel.getFDVal();
+        int fd = ski.getFDVal();
         if (fdToKey.remove(fd) != null) {
             if (ski.registeredEvents() != 0) {
                 port_dissociate(pfd, PORT_SOURCE_FD, fd);
@@ -269,10 +248,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);  // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }
--- a/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	Thu Apr 05 15:01:57 2018 +0100
@@ -23,84 +23,20 @@
  * questions.
  */
 
+#include <sys/devpoll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+
 #include "jni.h"
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
-#include "sun_nio_ch_DevPollArrayWrapper.h"
-#include <poll.h>
-#include <unistd.h>
-#include <sys/time.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-typedef uint32_t        caddr32_t;
-
-/* /dev/poll ioctl */
-#define         DPIOC   (0xD0 << 8)
-#define DP_POLL         (DPIOC | 1)     /* poll on fds in cached in /dev/poll */
-#define DP_ISPOLLED     (DPIOC | 2)     /* is this fd cached in /dev/poll */
-#define DEVPOLLSIZE     1000            /* /dev/poll table size increment */
-#define POLLREMOVE      0x0800          /* Removes fd from monitored set */
-
-/*
- * /dev/poll DP_POLL ioctl format
- */
-typedef struct dvpoll {
-        pollfd_t        *dp_fds;        /* pollfd array */
-        nfds_t          dp_nfds;        /* num of pollfd's in dp_fds[] */
-        int             dp_timeout;     /* time out in millisec */
-} dvpoll_t;
-
-typedef struct dvpoll32 {
-        caddr32_t       dp_fds;         /* pollfd array */
-        uint32_t        dp_nfds;        /* num of pollfd's in dp_fds[] */
-        int32_t         dp_timeout;     /* time out in millisec */
-} dvpoll32_t;
-
-#ifdef  __cplusplus
-}
-#endif
+#include "nio.h"
+#include "nio_util.h"
 
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-static int
-idevpoll(jint wfd, int dpctl, struct dvpoll a)
-{
-    jlong start, now;
-    int remaining = a.dp_timeout;
-    struct timeval t;
-    int diff;
-
-    gettimeofday(&t, NULL);
-    start = t.tv_sec * 1000 + t.tv_usec / 1000;
-
-    for (;;) {
-        /*  poll(7d) ioctl does not return remaining count */
-        int res = ioctl(wfd, dpctl, &a);
-        if (res < 0 && errno == EINTR) {
-            if (remaining >= 0) {
-                gettimeofday(&t, NULL);
-                now = t.tv_sec * 1000 + t.tv_usec / 1000;
-                diff = now - start;
-                remaining -= diff;
-                if (diff < 0 || remaining <= 0) {
-                    return 0;
-                }
-                start = now;
-                a.dp_timeout = remaining;
-            }
-        } else {
-            return res;
-        }
-    }
-}
+#include "sun_nio_ch_DevPollArrayWrapper.h"
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this)
@@ -153,26 +89,24 @@
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
-                                       jlong address, jint numfds,
-                                       jlong timeout, jint wfd)
+                                          jlong address, jint numfds,
+                                          jlong timeout, jint wfd)
 {
     struct dvpoll a;
     void *pfd = (void *) jlong_to_ptr(address);
-    int result = 0;
+    int result;
 
     a.dp_fds = pfd;
     a.dp_nfds = numfds;
     a.dp_timeout = (int)timeout;
-
-    if (timeout <= 0) {             /* Indefinite or no wait */
-        RESTARTABLE (ioctl(wfd, DP_POLL, &a), result);
-    } else {                        /* Bounded wait; bounded restarts */
-        result = idevpoll(wfd, DP_POLL, a);
-    }
-
+    result = ioctl(wfd, DP_POLL, &a);
     if (result < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
-        return -1;
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
+            return IOS_THROWN;
+        }
     }
     return result;
 }
--- a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -60,7 +60,6 @@
     // pending updates, queued by putEventOps
     private final Object updateLock = new Object();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
     // interrupt triggering and clearing
     private final Object interruptLock = new Object();
@@ -136,10 +135,9 @@
         assert Thread.holdsLock(this);
 
         synchronized (updateLock) {
-            assert updateKeys.size() == updateEvents.size();
             SelectionKeyImpl ski;
             while ((ski = updateKeys.pollFirst()) != null) {
-                int newEvents = updateEvents.pollFirst();
+                int newEvents = ski.translateInterestOps();
                 if (ski.isValid()) {
                     int index = ski.getIndex();
                     assert index >= 0 && index < pollArraySize;
@@ -173,14 +171,14 @@
             int rOps = getReventOps(i);
             if (rOps != 0) {
                 SelectionKeyImpl ski = pollKeys.get(i);
-                assert ski.channel.getFDVal() == getDescriptor(i);
+                assert ski.getFDVal() == getDescriptor(i);
                 if (ski.isValid()) {
                     if (selectedKeys.contains(ski)) {
-                        if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                        if (ski.translateAndSetReadyOps(rOps)) {
                             numKeysUpdated++;
                         }
                     } else {
-                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        ski.translateAndSetReadyOps(rOps);
                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                             selectedKeys.add(ski);
                             numKeysUpdated++;
@@ -233,10 +231,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);  // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }
@@ -285,7 +282,7 @@
 
         int index = pollArraySize;
         assert index > 0;
-        putDescriptor(index, ski.channel.getFDVal());
+        putDescriptor(index, ski.getFDVal());
         putEventOps(index, ops);
         putReventOps(index, 0);
         ski.setIndex(index);
@@ -301,7 +298,7 @@
     private void update(SelectionKeyImpl ski, int ops) {
         int index = ski.getIndex();
         assert index > 0 && index < pollArraySize;
-        assert getDescriptor(index) == ski.channel.getFDVal();
+        assert getDescriptor(index) == ski.getFDVal();
         putEventOps(index, ops);
     }
 
@@ -311,7 +308,7 @@
     private void remove(SelectionKeyImpl ski) {
         int index = ski.getIndex();
         assert index > 0 && index < pollArraySize;
-        assert getDescriptor(index) == ski.channel.getFDVal();
+        assert getDescriptor(index) == ski.getFDVal();
 
         // replace pollfd at index with the last pollfd in array
         int lastIndex = pollArraySize - 1;
@@ -321,7 +318,7 @@
             int lastFd = getDescriptor(lastIndex);
             int lastOps = getEventOps(lastIndex);
             int lastRevents = getReventOps(lastIndex);
-            assert lastKey.channel.getFDVal() == lastFd;
+            assert lastKey.getFDVal() == lastFd;
             putDescriptor(index, lastFd);
             putEventOps(index, lastOps);
             putReventOps(index, lastRevents);
--- a/src/java.base/windows/classes/sun/nio/ch/PollArrayWrapper.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/windows/classes/sun/nio/ch/PollArrayWrapper.java	Thu Apr 05 15:01:57 2018 +0100
@@ -64,7 +64,7 @@
 
     // Prepare another pollfd struct for use.
     void putEntry(int index, SelectionKeyImpl ski) {
-        putDescriptor(index, ski.channel.getFDVal());
+        putDescriptor(index, ski.getFDVal());
         putEventOps(index, 0);
     }
 
--- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Thu Apr 05 09:55:16 2018 +0200
+++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Thu Apr 05 15:01:57 2018 +0100
@@ -83,12 +83,12 @@
             return get(Integer.valueOf(desc));
         }
         private MapEntry put(SelectionKeyImpl ski) {
-            return put(Integer.valueOf(ski.channel.getFDVal()), new MapEntry(ski));
+            return put(Integer.valueOf(ski.getFDVal()), new MapEntry(ski));
         }
         private MapEntry remove(SelectionKeyImpl ski) {
-            Integer fd = Integer.valueOf(ski.channel.getFDVal());
+            Integer fd = Integer.valueOf(ski.getFDVal());
             MapEntry x = get(fd);
-            if ((x != null) && (x.ski.channel == ski.channel))
+            if ((x != null) && (x.ski.channel() == ski.channel()))
                 return remove(fd);
             return null;
         }
@@ -114,11 +114,10 @@
     private final Object interruptLock = new Object();
     private volatile boolean interruptTriggered;
 
-    // pending new registrations/updates, queued by implRegister and putEventOps
+    // pending new registrations/updates, queued by implRegister and setEventOps
     private final Object updateLock = new Object();
     private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
     private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
-    private final Deque<Integer> updateEvents = new ArrayDeque<>();
 
 
     WindowsSelectorImpl(SelectorProvider sp) throws IOException {
@@ -204,10 +203,9 @@
             }
 
             // changes to interest ops
-            assert updateKeys.size() == updateEvents.size();
             while ((ski = updateKeys.pollFirst()) != null) {
-                int events = updateEvents.pollFirst();
-                int fd = ski.channel.getFDVal();
+                int events = ski.translateInterestOps();
+                int fd = ski.getFDVal();
                 if (ski.isValid() && fdMap.containsKey(fd)) {
                     int index = ski.getIndex();
                     assert index >= 0 && index < totalChannels;
@@ -408,13 +406,13 @@
 
                 if (selectedKeys.contains(sk)) { // Key in selected set
                     if (me.clearedCount != updateCount) {
-                        if (sk.channel.translateAndSetReadyOps(rOps, sk) &&
+                        if (sk.translateAndSetReadyOps(rOps) &&
                             (me.updateCount != updateCount)) {
                             me.updateCount = updateCount;
                             numKeysUpdated++;
                         }
                     } else { // The readyOps have been set; now add
-                        if (sk.channel.translateAndUpdateReadyOps(rOps, sk) &&
+                        if (sk.translateAndUpdateReadyOps(rOps) &&
                             (me.updateCount != updateCount)) {
                             me.updateCount = updateCount;
                             numKeysUpdated++;
@@ -423,14 +421,14 @@
                     me.clearedCount = updateCount;
                 } else { // Key is not in selected set yet
                     if (me.clearedCount != updateCount) {
-                        sk.channel.translateAndSetReadyOps(rOps, sk);
+                        sk.translateAndSetReadyOps(rOps);
                         if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
                             selectedKeys.add(sk);
                             me.updateCount = updateCount;
                             numKeysUpdated++;
                         }
                     } else { // The readyOps have been set; now add
-                        sk.channel.translateAndUpdateReadyOps(rOps, sk);
+                        sk.translateAndUpdateReadyOps(rOps);
                         if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
                             selectedKeys.add(sk);
                             me.updateCount = updateCount;
@@ -613,10 +611,9 @@
     }
 
     @Override
-    public void putEventOps(SelectionKeyImpl ski, int events) {
+    public void setEventOps(SelectionKeyImpl ski) {
         ensureOpen();
         synchronized (updateLock) {
-            updateEvents.addLast(events);  // events first in case adding key fails
             updateKeys.addLast(ski);
         }
     }