8199611: (se) Minor selector implementation clean-up
authoralanb
Thu, 15 Mar 2018 10:47:58 +0000
changeset 49248 15a0e60c8b97
parent 49247 95e00d2708fb
child 49249 92cca24c8807
8199611: (se) Minor selector implementation clean-up Reviewed-by: clanger, redestad, bpb
src/java.base/linux/classes/sun/nio/ch/EPoll.java
src/java.base/linux/classes/sun/nio/ch/EPollArrayWrapper.java
src/java.base/linux/classes/sun/nio/ch/EPollPort.java
src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java
src/java.base/macosx/classes/sun/nio/ch/KQueue.java
src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java
src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.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/DevPollArrayWrapper.java
src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java
src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java
--- a/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, 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
@@ -59,6 +59,10 @@
     static final int EPOLL_CTL_DEL  = 2;
     static final int EPOLL_CTL_MOD  = 3;
 
+    // events
+    static final int EPOLLIN   = 0x1;
+    static final int EPOLLOUT  = 0x4;
+
     // flags
     static final int EPOLLONESHOT   = (1 << 30);
 
--- a/src/java.base/linux/classes/sun/nio/ch/EPollArrayWrapper.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollArrayWrapper.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, 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
@@ -93,16 +93,10 @@
     private final long pollArrayAddress;
 
     // The fd of the interrupt line going out
-    private int outgoingInterruptFD;
-
-    // The fd of the interrupt line coming in
-    private int incomingInterruptFD;
-
-    // The index of the interrupt FD
-    private int interruptedIndex;
+    private final int outgoingInterruptFD;
 
     // Number of updated pollfd entries
-    int updated;
+    private int updated;
 
     // object to synchronize fd registration changes
     private final Object updateLock = new Object();
@@ -125,7 +119,7 @@
     private final BitSet registered = new BitSet();
 
 
-    EPollArrayWrapper() throws IOException {
+    EPollArrayWrapper(int fd0, int fd1) throws IOException {
         // creates the epoll file descriptor
         epfd = epollCreate();
 
@@ -133,11 +127,8 @@
         int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
         pollArray = new AllocatedNativeObject(allocationSize, true);
         pollArrayAddress = pollArray.address();
-    }
 
-    void initInterrupt(int fd0, int fd1) {
         outgoingInterruptFD = fd1;
-        incomingInterruptFD = fd0;
         epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
     }
 
@@ -255,22 +246,14 @@
     /**
      * Close epoll file descriptor and free poll array
      */
-    void closeEPollFD() throws IOException {
+    void close() throws IOException {
         FileDispatcherImpl.closeIntFD(epfd);
         pollArray.free();
     }
 
     int poll(long timeout) throws IOException {
         updateRegistrations();
-        updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
-        for (int i=0; i<updated; i++) {
-            if (getDescriptor(i) == incomingInterruptFD) {
-                interruptedIndex = i;
-                interrupted = true;
-                break;
-            }
-        }
-        return updated;
+        return epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
     }
 
     /**
@@ -306,25 +289,10 @@
         }
     }
 
-    // interrupt support
-    private boolean interrupted = false;
-
     public void interrupt() {
         interrupt(outgoingInterruptFD);
     }
 
-    public int interruptedIndex() {
-        return interruptedIndex;
-    }
-
-    boolean interrupted() {
-        return interrupted;
-    }
-
-    void clearInterrupted() {
-        interrupted = false;
-    }
-
     static {
         IOUtil.load();
         init();
--- a/src/java.base/linux/classes/sun/nio/ch/EPollPort.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollPort.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, 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
@@ -93,7 +93,7 @@
         try {
             socketpair(sv);
             // register one end with epoll
-            epollCtl(epfd, EPOLL_CTL_ADD, sv[0], Net.POLLIN);
+            epollCtl(epfd, EPOLL_CTL_ADD, sv[0], EPOLLIN);
         } catch (IOException x) {
             close0(epfd);
             throw x;
--- a/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, 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
@@ -37,16 +37,15 @@
 class EPollSelectorImpl
     extends SelectorImpl
 {
-
     // File descriptors used for interrupt
-    protected int fd0;
-    protected int fd1;
+    private final int fd0;
+    private final int fd1;
 
     // The poll object
-    EPollArrayWrapper pollWrapper;
+    private final EPollArrayWrapper pollWrapper;
 
     // Maps from file descriptors to keys
-    private Map<Integer,SelectionKeyImpl> fdToKey;
+    private final Map<Integer, SelectionKeyImpl> fdToKey;
 
     // True if this Selector has been closed
     private volatile boolean closed;
@@ -65,8 +64,7 @@
         fd0 = (int) (pipeFds >>> 32);
         fd1 = (int) pipeFds;
         try {
-            pollWrapper = new EPollArrayWrapper();
-            pollWrapper.initInterrupt(fd0, fd1);
+            pollWrapper = new EPollArrayWrapper(fd0, fd1);
             fdToKey = new HashMap<>();
         } catch (Throwable t) {
             try {
@@ -83,59 +81,64 @@
         }
     }
 
-    protected int doSelect(long timeout) throws IOException {
+    private void ensureOpen() {
         if (closed)
             throw new ClosedSelectorException();
+    }
+
+    @Override
+    protected int doSelect(long timeout) throws IOException {
+        ensureOpen();
+        int numEntries;
         processDeregisterQueue();
         try {
             begin();
-            pollWrapper.poll(timeout);
+            numEntries = pollWrapper.poll(timeout);
         } finally {
             end();
         }
         processDeregisterQueue();
-        int numKeysUpdated = updateSelectedKeys();
-        if (pollWrapper.interrupted()) {
-            // Clear the wakeup pipe
-            pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0);
-            synchronized (interruptLock) {
-                pollWrapper.clearInterrupted();
-                IOUtil.drain(fd0);
-                interruptTriggered = false;
-            }
-        }
-        return numKeysUpdated;
+        return updateSelectedKeys(numEntries);
     }
 
     /**
      * Update the keys whose fd's have been selected by the epoll.
      * Add the ready keys to the ready queue.
      */
-    private int updateSelectedKeys() {
-        int entries = pollWrapper.updated;
+    private int updateSelectedKeys(int numEntries) throws IOException {
+        boolean interrupted = false;
         int numKeysUpdated = 0;
-        for (int i=0; i<entries; i++) {
+        for (int i=0; i<numEntries; i++) {
             int nextFD = pollWrapper.getDescriptor(i);
-            SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
-            // ski is null in the case of an interrupt
-            if (ski != null) {
-                int rOps = pollWrapper.getEventOps(i);
-                if (selectedKeys.contains(ski)) {
-                    if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
-                        numKeysUpdated++;
-                    }
-                } else {
-                    ski.channel.translateAndSetReadyOps(rOps, ski);
-                    if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
-                        selectedKeys.add(ski);
-                        numKeysUpdated++;
+            if (nextFD == fd0) {
+                interrupted = true;
+            } else {
+                SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
+                if (ski != null) {
+                    int rOps = pollWrapper.getEventOps(i);
+                    if (selectedKeys.contains(ski)) {
+                        if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                            numKeysUpdated++;
+                        }
+                    } else {
+                        ski.channel.translateAndSetReadyOps(rOps, ski);
+                        if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
+                            selectedKeys.add(ski);
+                            numKeysUpdated++;
+                        }
                     }
                 }
             }
         }
+
+        if (interrupted) {
+            clearInterrupt();
+        }
+
         return numKeysUpdated;
     }
 
+    @Override
     protected void implClose() throws IOException {
         if (closed)
             return;
@@ -146,13 +149,10 @@
             interruptTriggered = true;
         }
 
+        pollWrapper.close();
         FileDispatcherImpl.closeIntFD(fd0);
         FileDispatcherImpl.closeIntFD(fd1);
 
-        pollWrapper.closeEPollFD();
-        // it is possible
-        selectedKeys = null;
-
         // Deregister channels
         Iterator<SelectionKey> i = keys.iterator();
         while (i.hasNext()) {
@@ -163,14 +163,11 @@
                 ((SelChImpl)selch).kill();
             i.remove();
         }
-
-        fd0 = -1;
-        fd1 = -1;
     }
 
+    @Override
     protected void implRegister(SelectionKeyImpl ski) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         SelChImpl ch = ski.channel;
         int fd = Integer.valueOf(ch.getFDVal());
         fdToKey.put(fd, ski);
@@ -178,6 +175,7 @@
         keys.add(ski);
     }
 
+    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         assert (ski.getIndex() >= 0);
         SelChImpl ch = ski.channel;
@@ -187,19 +185,20 @@
         ski.setIndex(-1);
         keys.remove(ski);
         selectedKeys.remove(ski);
-        deregister((AbstractSelectionKey)ski);
+        deregister(ski);
         SelectableChannel selch = ski.channel();
         if (!selch.isOpen() && !selch.isRegistered())
             ((SelChImpl)selch).kill();
     }
 
+    @Override
     public void putEventOps(SelectionKeyImpl ski, int ops) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         SelChImpl ch = ski.channel;
         pollWrapper.setInterest(ch.getFDVal(), ops);
     }
 
+    @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
@@ -209,4 +208,11 @@
         }
         return this;
     }
+
+    private void clearInterrupt() throws IOException {
+        synchronized (interruptLock) {
+            IOUtil.drain(fd0);
+            interruptTriggered = false;
+        }
+    }
 }
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, 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
@@ -58,6 +58,7 @@
 
     // flags
     static final int EV_ADD     = 0x0001;
+    static final int EV_DELETE  = 0x0002;
     static final int EV_ONESHOT = 0x0010;
     static final int EV_CLEAR   = 0x0020;
 
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -66,20 +66,18 @@
     static final int NUM_KEVENTS = 128;
 
     // Are we in a 64-bit VM?
-    static boolean is64bit = false;
+    static boolean is64bit;
 
     // The kevent array (used for outcoming events only)
-    private AllocatedNativeObject keventArray = null;
-    private long keventArrayAddress;
+    private final AllocatedNativeObject keventArray;
+    private final long keventArrayAddress;
 
     // The kqueue fd
-    private int kq = -1;
+    private final int kq;
 
     // The fd of the interrupt line going out
-    private int outgoingInterruptFD;
+    private final int outgoingInterruptFD;
 
-    // The fd of the interrupt line coming in
-    private int incomingInterruptFD;
 
     static {
         IOUtil.load();
@@ -89,11 +87,13 @@
         is64bit = "64".equals(datamodel);
     }
 
-    KQueueArrayWrapper() {
+    KQueueArrayWrapper(int fd0, int fd1) throws IOException {
         int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
         keventArray = new AllocatedNativeObject(allocationSize, true);
         keventArrayAddress = keventArray.address();
         kq = init();
+        register0(kq, fd0, 1, 0);
+        outgoingInterruptFD = fd1;
     }
 
     // Used to update file description registrations
@@ -108,12 +108,6 @@
 
     private LinkedList<Update> updateList = new LinkedList<Update>();
 
-    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;
@@ -137,11 +131,11 @@
          * 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;
+            long fd = keventArray.getLong(offset);
+            assert fd <= Integer.MAX_VALUE;
+            return (int) fd;
         } else {
-          return keventArray.getInt(offset);
+            return keventArray.getInt(offset);
         }
     }
 
@@ -168,7 +162,7 @@
 
     void updateRegistrations() {
         synchronized (updateList) {
-            Update u = null;
+            Update u;
             while ((u = updateList.poll()) != null) {
                 SelChImpl ch = u.channel;
                 if (!ch.isOpen())
@@ -179,22 +173,14 @@
         }
     }
 
-
     void close() throws IOException {
-        if (keventArray != null) {
-            keventArray.free();
-            keventArray = null;
-        }
-        if (kq >= 0) {
-            FileDispatcherImpl.closeIntFD(kq);
-            kq = -1;
-        }
+        FileDispatcherImpl.closeIntFD(kq);
+        keventArray.free();
     }
 
     int poll(long timeout) {
         updateRegistrations();
-        int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
-        return updated;
+        return kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
     }
 
     void interrupt() {
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -26,39 +26,38 @@
 /*
  * 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 java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.HashMap;
+import java.util.Iterator;
 
 class KQueueSelectorImpl
     extends SelectorImpl
 {
     // File descriptors used for interrupt
-    protected int fd0;
-    protected int fd1;
+    private final int fd0;
+    private final int fd1;
 
     // The kqueue manipulator
-    KQueueArrayWrapper kqueueWrapper;
-
-    // Count of registered descriptors (including interrupt)
-    private int totalChannels;
+    private final KQueueArrayWrapper kqueueWrapper;
 
     // Map from a file descriptor to an entry containing the selection key
-    private HashMap<Integer,MapEntry> fdMap;
+    private final HashMap<Integer, MapEntry> fdMap;
 
     // True if this Selector has been closed
-    private boolean closed = false;
+    private boolean closed;
 
     // Lock for interrupt triggering and clearing
-    private Object interruptLock = new Object();
-    private boolean interruptTriggered = false;
+    private final Object interruptLock = new Object();
+    private boolean interruptTriggered;
 
     // used by updateSelectedKeys to handle cases where the same file
     // descriptor is polled by more than one filter
@@ -78,16 +77,14 @@
      * Package private constructor called by factory method in
      * the abstract superclass Selector.
      */
-    KQueueSelectorImpl(SelectorProvider sp) {
+    KQueueSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
         long fds = IOUtil.makePipe(false);
         fd0 = (int)(fds >>> 32);
         fd1 = (int)fds;
         try {
-            kqueueWrapper = new KQueueArrayWrapper();
-            kqueueWrapper.initInterrupt(fd0, fd1);
+            kqueueWrapper = new KQueueArrayWrapper(fd0, fd1);
             fdMap = new HashMap<>();
-            totalChannels = 1;
         } catch (Throwable t) {
             try {
                 FileDispatcherImpl.closeIntFD(fd0);
@@ -103,22 +100,26 @@
         }
     }
 
+    private void ensureOpen() {
+        if (closed)
+            throw new ClosedSelectorException();
+    }
 
+    @Override
     protected int doSelect(long timeout)
         throws IOException
     {
-        int entries = 0;
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
+        int numEntries;
         processDeregisterQueue();
         try {
             begin();
-            entries = kqueueWrapper.poll(timeout);
+            numEntries = kqueueWrapper.poll(timeout);
         } finally {
             end();
         }
         processDeregisterQueue();
-        return updateSelectedKeys(entries);
+        return updateSelectedKeys(numEntries);
     }
 
     /**
@@ -126,7 +127,7 @@
      * 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)
+    private int updateSelectedKeys(int numEntries)
         throws IOException
     {
         int numKeysUpdated = 0;
@@ -139,14 +140,12 @@
         // second or subsequent event.
         updateCount++;
 
-        for (int i = 0; i < entries; i++) {
+        for (int i = 0; i < numEntries; i++) {
             int nextFD = kqueueWrapper.getDescriptor(i);
             if (nextFD == fd0) {
                 interrupted = true;
             } else {
                 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;
@@ -175,16 +174,12 @@
         }
 
         if (interrupted) {
-            // Clear the wakeup pipe
-            synchronized (interruptLock) {
-                IOUtil.drain(fd0);
-                interruptTriggered = false;
-            }
+            clearInterrupt();
         }
         return numKeysUpdated;
     }
 
-
+    @Override
     protected void implClose() throws IOException {
         if (!closed) {
             closed = true;
@@ -194,62 +189,51 @@
                 interruptTriggered = true;
             }
 
+            kqueueWrapper.close();
             FileDispatcherImpl.closeIntFD(fd0);
             FileDispatcherImpl.closeIntFD(fd1);
-            if (kqueueWrapper != null) {
-                kqueueWrapper.close();
-                kqueueWrapper = null;
-                selectedKeys = null;
 
-                // Deregister channels
-                Iterator<SelectionKey> 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;
+            // Deregister channels
+            Iterator<SelectionKey> 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();
             }
-            fd0 = -1;
-            fd1 = -1;
         }
     }
 
-
+    @Override
     protected void implRegister(SelectionKeyImpl ski) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         int fd = IOUtil.fdVal(ski.channel.getFD());
         fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
-        totalChannels++;
         keys.add(ski);
     }
 
-
+    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         int fd = ski.channel.getFDVal();
         fdMap.remove(Integer.valueOf(fd));
         kqueueWrapper.release(ski.channel);
-        totalChannels--;
         keys.remove(ski);
         selectedKeys.remove(ski);
-        deregister((AbstractSelectionKey)ski);
+        deregister(ski);
         SelectableChannel selch = ski.channel();
         if (!selch.isOpen() && !selch.isRegistered())
             ((SelChImpl)selch).kill();
     }
 
-
+    @Override
     public void putEventOps(SelectionKeyImpl ski, int ops) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         kqueueWrapper.setInterest(ski.channel, ops);
     }
 
-
+    @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
@@ -259,4 +243,11 @@
         }
         return this;
     }
+
+    private void clearInterrupt() throws IOException {
+        synchronized (interruptLock) {
+            IOUtil.drain(fd0);
+            interruptTriggered = false;
+        }
+    }
 }
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -36,7 +36,7 @@
 import java.nio.channels.spi.*;
 
 public class KQueueSelectorProvider
-extends SelectorProviderImpl
+    extends SelectorProviderImpl
 {
     public AbstractSelector openSelector() throws IOException {
         return new KQueueSelectorImpl(this);
--- a/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -99,7 +99,6 @@
             implCloseInterrupt();
             pollWrapper.free();
             pollWrapper = null;
-            selectedKeys = null;
             channelArray = null;
             totalChannels = 0;
         }
--- a/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -25,9 +25,11 @@
 
 package sun.nio.ch;
 
-import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
 
 
 /**
@@ -45,7 +47,7 @@
     private int index;
 
     private volatile int interestOps;
-    private int readyOps;
+    private volatile int readyOps;
 
     SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
         channel = ch;
@@ -111,4 +113,22 @@
         return interestOps;
     }
 
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("channel=")
+          .append(channel)
+          .append(", selector=")
+          .append(selector);
+        if (isValid()) {
+            sb.append(", interestOps=")
+              .append(interestOps)
+              .append(", readyOps=")
+              .append(readyOps);
+        } else {
+            sb.append(", invalid");
+        }
+        return sb.toString();
+    }
+
 }
--- a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -30,7 +30,6 @@
 import java.nio.channels.ClosedSelectorException;
 import java.nio.channels.IllegalSelectorException;
 import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
 import java.nio.channels.spi.AbstractSelectableChannel;
 import java.nio.channels.spi.AbstractSelector;
 import java.nio.channels.spi.SelectorProvider;
@@ -47,16 +46,15 @@
 public abstract class SelectorImpl
     extends AbstractSelector
 {
+    // The set of keys registered with this Selector
+    protected final HashSet<SelectionKey> keys;
 
     // The set of keys with data ready for an operation
-    protected Set<SelectionKey> selectedKeys;
-
-    // The set of keys registered with this Selector
-    protected HashSet<SelectionKey> keys;
+    protected final Set<SelectionKey> selectedKeys;
 
     // Public views of the key sets
-    private Set<SelectionKey> publicKeys;             // Immutable
-    private Set<SelectionKey> publicSelectedKeys;     // Removal allowed, but not addition
+    private final Set<SelectionKey> publicKeys;             // Immutable
+    private final Set<SelectionKey> publicSelectedKeys;     // Removal allowed, but not addition
 
     protected SelectorImpl(SelectorProvider sp) {
         super(sp);
@@ -66,13 +64,15 @@
         publicSelectedKeys = Util.ungrowableSet(selectedKeys);
     }
 
-    public Set<SelectionKey> keys() {
+    @Override
+    public final Set<SelectionKey> keys() {
         if (!isOpen())
             throw new ClosedSelectorException();
         return publicKeys;
     }
 
-    public Set<SelectionKey> selectedKeys() {
+    @Override
+    public final Set<SelectionKey> selectedKeys() {
         if (!isOpen())
             throw new ClosedSelectorException();
         return publicSelectedKeys;
@@ -92,7 +92,8 @@
         }
     }
 
-    public int select(long timeout)
+    @Override
+    public final int select(long timeout)
         throws IOException
     {
         if (timeout < 0)
@@ -100,15 +101,18 @@
         return lockAndDoSelect((timeout == 0) ? -1 : timeout);
     }
 
-    public int select() throws IOException {
+    @Override
+    public final int select() throws IOException {
         return select(0);
     }
 
-    public int selectNow() throws IOException {
+    @Override
+    public final int selectNow() throws IOException {
         return lockAndDoSelect(0);
     }
 
-    public void implCloseSelector() throws IOException {
+    @Override
+    public final void implCloseSelector() throws IOException {
         wakeup();
         synchronized (this) {
             synchronized (publicKeys) {
@@ -121,8 +125,9 @@
 
     protected abstract void implClose() throws IOException;
 
-    public void putEventOps(SelectionKeyImpl sk, int ops) { }
+    public abstract void putEventOps(SelectionKeyImpl sk, int ops);
 
+    @Override
     protected final SelectionKey register(AbstractSelectableChannel ch,
                                           int ops,
                                           Object attachment)
@@ -140,7 +145,9 @@
 
     protected abstract void implRegister(SelectionKeyImpl ski);
 
-    void processDeregisterQueue() throws IOException {
+    protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
+
+    protected final void processDeregisterQueue() throws IOException {
         // Precondition: Synchronized on this, keys, and selectedKeys
         Set<SelectionKey> cks = cancelledKeys();
         synchronized (cks) {
@@ -159,9 +166,4 @@
             }
         }
     }
-
-    protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
-
-    public abstract Selector wakeup();
-
 }
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -213,7 +213,7 @@
         }
     }
 
-    void closeDevPollFD() throws IOException {
+    void close() throws IOException {
         FileDispatcherImpl.closeIntFD(wfd);
         pollArray.free();
     }
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -37,26 +37,25 @@
 class DevPollSelectorImpl
     extends SelectorImpl
 {
-
     // File descriptors used for interrupt
-    protected int fd0;
-    protected int fd1;
+    private final int fd0;
+    private final int fd1;
 
     // The poll object
-    DevPollArrayWrapper pollWrapper;
+    private final DevPollArrayWrapper pollWrapper;
 
     // Maps from file descriptors to keys
-    private Map<Integer,SelectionKeyImpl> fdToKey;
+    private final Map<Integer, SelectionKeyImpl> fdToKey;
 
     // True if this Selector has been closed
-    private boolean closed = false;
+    private boolean closed;
 
     // Lock for close/cleanup
-    private Object closeLock = new Object();
+    private final Object closeLock = new Object();
 
     // Lock for interrupt triggering and clearing
-    private Object interruptLock = new Object();
-    private boolean interruptTriggered = false;
+    private final Object interruptLock = new Object();
+    private boolean interruptTriggered;
 
     /**
      * Package private constructor called by factory method in
@@ -86,11 +85,16 @@
         }
     }
 
+    private void ensureOpen() {
+        if (closed)
+            throw new ClosedSelectorException();
+    }
+
+    @Override
     protected int doSelect(long timeout)
         throws IOException
     {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         processDeregisterQueue();
         try {
             begin();
@@ -141,6 +145,7 @@
         return numKeysUpdated;
     }
 
+    @Override
     protected void implClose() throws IOException {
         if (closed)
             return;
@@ -151,13 +156,10 @@
             interruptTriggered = true;
         }
 
+        pollWrapper.close();
         FileDispatcherImpl.closeIntFD(fd0);
         FileDispatcherImpl.closeIntFD(fd1);
 
-        pollWrapper.release(fd0);
-        pollWrapper.closeDevPollFD();
-        selectedKeys = null;
-
         // Deregister channels
         Iterator<SelectionKey> i = keys.iterator();
         while (i.hasNext()) {
@@ -168,16 +170,16 @@
                 ((SelChImpl)selch).kill();
             i.remove();
         }
-        fd0 = -1;
-        fd1 = -1;
     }
 
+    @Override
     protected void implRegister(SelectionKeyImpl ski) {
         int fd = IOUtil.fdVal(ski.channel.getFD());
         fdToKey.put(Integer.valueOf(fd), ski);
         keys.add(ski);
     }
 
+    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         int i = ski.getIndex();
         assert (i >= 0);
@@ -193,13 +195,14 @@
             ((SelChImpl)selch).kill();
     }
 
+    @Override
     public void putEventOps(SelectionKeyImpl sk, int ops) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         int fd = IOUtil.fdVal(sk.channel.getFD());
         pollWrapper.setInterest(fd, ops);
     }
 
+    @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
--- a/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, 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
@@ -42,14 +42,14 @@
     private final EventPortWrapper pollWrapper;
 
     // Maps from file descriptors to keys
-    private Map<Integer,SelectionKeyImpl> fdToKey;
+    private final Map<Integer, SelectionKeyImpl> fdToKey;
 
     // True if this Selector has been closed
-    private boolean closed = false;
+    private boolean closed;
 
     // Lock for interrupt triggering and clearing
     private final Object interruptLock = new Object();
-    private boolean interruptTriggered = false;
+    private boolean interruptTriggered;
 
     /**
      * Package private constructor called by factory method in
@@ -61,9 +61,14 @@
         fdToKey = new HashMap<>();
     }
 
-    protected int doSelect(long timeout) throws IOException {
+    private void ensureOpen() {
         if (closed)
             throw new ClosedSelectorException();
+    }
+
+    @Override
+    protected int doSelect(long timeout) throws IOException {
+        ensureOpen();
         processDeregisterQueue();
         int entries;
         try {
@@ -105,6 +110,7 @@
         return numKeysUpdated;
     }
 
+    @Override
     protected void implClose() throws IOException {
         if (closed)
             return;
@@ -116,7 +122,6 @@
         }
 
         pollWrapper.close();
-        selectedKeys = null;
 
         // Deregister channels
         Iterator<SelectionKey> i = keys.iterator();
@@ -130,12 +135,14 @@
         }
     }
 
+    @Override
     protected void implRegister(SelectionKeyImpl ski) {
         int fd = IOUtil.fdVal(ski.channel.getFD());
         fdToKey.put(Integer.valueOf(fd), ski);
         keys.add(ski);
     }
 
+    @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
         int i = ski.getIndex();
         assert (i >= 0);
@@ -151,13 +158,14 @@
             ((SelChImpl)selch).kill();
     }
 
+    @Override
     public void putEventOps(SelectionKeyImpl sk, int ops) {
-        if (closed)
-            throw new ClosedSelectorException();
+        ensureOpen();
         int fd = sk.channel.getFDVal();
         pollWrapper.setInterest(fd, ops);
     }
 
+    @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
--- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Thu Mar 15 10:41:57 2018 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Thu Mar 15 10:47:58 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, 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
@@ -48,7 +48,7 @@
  * @author Mark Reinhold
  */
 
-final class WindowsSelectorImpl extends SelectorImpl {
+class WindowsSelectorImpl extends SelectorImpl {
     // Initial capacity of the poll array
     private final int INIT_CAP = 8;
     // Maximum number of sockets for select().
@@ -81,7 +81,7 @@
     private final int wakeupSourceFd, wakeupSinkFd;
 
     // Lock for close cleanup
-    private Object closeLock = new Object();
+    private final Object closeLock = new Object();
 
     // Maps file descriptors to their indices in  pollArray
     private static final class FdMap extends HashMap<Integer, MapEntry> {
@@ -135,6 +135,7 @@
         pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
     }
 
+    @Override
     protected int doSelect(long timeout) throws IOException {
         if (channelArray == null)
             throw new ClosedSelectorException();
@@ -500,6 +501,7 @@
         return numKeysUpdated;
     }
 
+    @Override
     protected void implClose() throws IOException {
         synchronized (closeLock) {
             if (channelArray != null) {
@@ -520,7 +522,6 @@
                     }
                     pollWrapper.free();
                     pollWrapper = null;
-                    selectedKeys = null;
                     channelArray = null;
                     // Make all remaining helper threads exit
                     for (SelectThread t: threads)