changeset 49295:07779973cbe2

8199791: (se) More Selector cleanup Reviewed-by: redestad, bpb
author alanb
date Fri, 23 Mar 2018 14:18:18 +0000
parents 148e29df1644
children ae041d4dd43e 67b897123581
files make/mapfiles/libnio/mapfile-linux make/mapfiles/libnio/mapfile-macosx make/mapfiles/libnio/mapfile-solaris 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/linux/native/libnio/ch/EPoll.c src/java.base/linux/native/libnio/ch/EPollArrayWrapper.c src/java.base/linux/native/libnio/ch/EPollPort.c 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/KQueuePort.java src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java src/java.base/macosx/native/libnio/ch/KQueue.c src/java.base/macosx/native/libnio/ch/KQueueArrayWrapper.c src/java.base/macosx/native/libnio/ch/KQueuePort.c src/java.base/share/classes/sun/nio/ch/IOUtil.java src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java src/java.base/share/classes/sun/nio/ch/SelectorImpl.java src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.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/EventPortWrapper.java src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c src/java.base/solaris/native/libnio/ch/SolarisEventPort.c src/java.base/unix/classes/sun/nio/ch/PipeImpl.java src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java src/java.base/unix/native/libnio/ch/IOUtil.c test/jdk/java/nio/channels/Selector/CloseWhenKeyIdle.java
diffstat 33 files changed, 754 insertions(+), 1516 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libnio/mapfile-linux	Fri Mar 23 09:51:02 2018 +0100
+++ b/make/mapfiles/libnio/mapfile-linux	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2017, 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,23 +37,12 @@
                 Java_sun_nio_ch_DatagramDispatcher_readv0;
                 Java_sun_nio_ch_DatagramDispatcher_write0;
                 Java_sun_nio_ch_DatagramDispatcher_writev0;
-                Java_sun_nio_ch_EPollArrayWrapper_epollCreate;
-                Java_sun_nio_ch_EPollArrayWrapper_epollCtl;
-                Java_sun_nio_ch_EPollArrayWrapper_epollWait;
-		Java_sun_nio_ch_EPollArrayWrapper_init;
-		Java_sun_nio_ch_EPollArrayWrapper_interrupt;
-		Java_sun_nio_ch_EPollArrayWrapper_offsetofData;
-		Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent;
 		Java_sun_nio_ch_EPoll_eventSize;
 		Java_sun_nio_ch_EPoll_eventsOffset;
 		Java_sun_nio_ch_EPoll_dataOffset;
-		Java_sun_nio_ch_EPoll_epollCreate;
-		Java_sun_nio_ch_EPoll_epollCtl;
-		Java_sun_nio_ch_EPoll_epollWait;
-		Java_sun_nio_ch_EPollPort_close0;
-		Java_sun_nio_ch_EPollPort_drain1;
-		Java_sun_nio_ch_EPollPort_interrupt;
-		Java_sun_nio_ch_EPollPort_socketpair;
+		Java_sun_nio_ch_EPoll_create;
+		Java_sun_nio_ch_EPoll_ctl;
+		Java_sun_nio_ch_EPoll_wait;
                 Java_sun_nio_ch_FileChannelImpl_initIDs;
                 Java_sun_nio_ch_FileChannelImpl_map0;
                 Java_sun_nio_ch_FileChannelImpl_position0;
@@ -95,6 +84,7 @@
                 Java_sun_nio_ch_IOUtil_makePipe;
                 Java_sun_nio_ch_IOUtil_randomBytes;
                 Java_sun_nio_ch_IOUtil_setfdVal;
+                Java_sun_nio_ch_IOUtil_write1;
 		Java_sun_nio_ch_NativeThread_current;
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
--- a/make/mapfiles/libnio/mapfile-macosx	Fri Mar 23 09:51:02 2018 +0100
+++ b/make/mapfiles/libnio/mapfile-macosx	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2017, 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
@@ -42,7 +42,7 @@
                 Java_sun_nio_ch_FileChannelImpl_position0;
                 Java_sun_nio_ch_FileChannelImpl_transferTo0;
                 Java_sun_nio_ch_FileChannelImpl_unmap0;
-		Java_sun_nio_ch_FileDispatcherImpl_allocate0;
+	        Java_sun_nio_ch_FileDispatcherImpl_allocate0;
                 Java_sun_nio_ch_FileDispatcherImpl_close0;
                 Java_sun_nio_ch_FileDispatcherImpl_closeIntFD;
 		Java_sun_nio_ch_FileDispatcherImpl_force0;
@@ -71,117 +71,115 @@
                 Java_sun_nio_ch_IOUtil_configureBlocking;
                 Java_sun_nio_ch_IOUtil_drain;
                 Java_sun_nio_ch_IOUtil_fdVal;
+                Java_sun_nio_ch_IOUtil_fdLimit;
                 Java_sun_nio_ch_IOUtil_initIDs;
+                Java_sun_nio_ch_IOUtil_iovMax;
                 Java_sun_nio_ch_IOUtil_makePipe;
                 Java_sun_nio_ch_IOUtil_randomBytes;
                 Java_sun_nio_ch_IOUtil_setfdVal;
-                Java_sun_nio_ch_IOUtil_iovMax;
-		Java_sun_nio_ch_KQueue_kqueue;
-		Java_sun_nio_ch_KQueue_keventRegister;
-		Java_sun_nio_ch_KQueue_keventPoll;
-		Java_sun_nio_ch_KQueue_keventSize;
-		Java_sun_nio_ch_KQueue_identOffset;
-		Java_sun_nio_ch_KQueue_filterOffset;
-		Java_sun_nio_ch_KQueue_flagsOffset;
-		Java_sun_nio_ch_KQueuePort_socketpair;
-		Java_sun_nio_ch_KQueuePort_interrupt;
-		Java_sun_nio_ch_KQueuePort_drain1;
-		Java_sun_nio_ch_KQueuePort_close0;
-		Java_sun_nio_ch_NativeThread_current;
-		Java_sun_nio_ch_NativeThread_init;
-		Java_sun_nio_ch_NativeThread_signal;
-		Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
-		Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
-		Java_sun_nio_ch_Net_socket0;
-		Java_sun_nio_ch_Net_bind0;
-		Java_sun_nio_ch_Net_connect0;
-		Java_sun_nio_ch_Net_listen;
-		Java_sun_nio_ch_Net_localPort;
-		Java_sun_nio_ch_Net_localInetAddress;
-		Java_sun_nio_ch_Net_getIntOption0;
-		Java_sun_nio_ch_Net_setIntOption0;
+                Java_sun_nio_ch_IOUtil_write1;
+                Java_sun_nio_ch_KQueue_create;
+                Java_sun_nio_ch_KQueue_register;
+                Java_sun_nio_ch_KQueue_poll;
+                Java_sun_nio_ch_KQueue_keventSize;
+                Java_sun_nio_ch_KQueue_identOffset;
+                Java_sun_nio_ch_KQueue_filterOffset;
+                Java_sun_nio_ch_KQueue_flagsOffset;
+                Java_sun_nio_ch_NativeThread_current;
+                Java_sun_nio_ch_NativeThread_init;
+                Java_sun_nio_ch_NativeThread_signal;
+                Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
+                Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
+                Java_sun_nio_ch_Net_socket0;
+                Java_sun_nio_ch_Net_bind0;
+                Java_sun_nio_ch_Net_connect0;
+                Java_sun_nio_ch_Net_listen;
+                Java_sun_nio_ch_Net_localPort;
+                Java_sun_nio_ch_Net_localInetAddress;
+                Java_sun_nio_ch_Net_getIntOption0;
+                Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
                 Java_sun_nio_ch_Net_isReusePortAvailable0;
-		Java_sun_nio_ch_Net_joinOrDrop4;
-		Java_sun_nio_ch_Net_blockOrUnblock4;
-		Java_sun_nio_ch_Net_joinOrDrop6;
-		Java_sun_nio_ch_Net_blockOrUnblock6;
-		Java_sun_nio_ch_Net_setInterface4;
-		Java_sun_nio_ch_Net_getInterface4;
-		Java_sun_nio_ch_Net_setInterface6;
-		Java_sun_nio_ch_Net_getInterface6;
-		Java_sun_nio_ch_Net_shutdown;
-		Java_sun_nio_ch_Net_poll;
-		Java_sun_nio_ch_Net_pollinValue;
-		Java_sun_nio_ch_Net_polloutValue;
-		Java_sun_nio_ch_Net_pollerrValue;
-		Java_sun_nio_ch_Net_pollhupValue;
-		Java_sun_nio_ch_Net_pollnvalValue;
-		Java_sun_nio_ch_Net_pollconnValue;
+                Java_sun_nio_ch_Net_joinOrDrop4;
+                Java_sun_nio_ch_Net_blockOrUnblock4;
+                Java_sun_nio_ch_Net_joinOrDrop6;
+                Java_sun_nio_ch_Net_blockOrUnblock6;
+                Java_sun_nio_ch_Net_setInterface4;
+                Java_sun_nio_ch_Net_getInterface4;
+                Java_sun_nio_ch_Net_setInterface6;
+                Java_sun_nio_ch_Net_getInterface6;
+                Java_sun_nio_ch_Net_shutdown;
+                Java_sun_nio_ch_Net_poll;
+                Java_sun_nio_ch_Net_pollinValue;
+                Java_sun_nio_ch_Net_polloutValue;
+                Java_sun_nio_ch_Net_pollerrValue;
+                Java_sun_nio_ch_Net_pollhupValue;
+                Java_sun_nio_ch_Net_pollnvalValue;
+                Java_sun_nio_ch_Net_pollconnValue;
                 Java_sun_nio_ch_Net_isExclusiveBindAvailable;
                 Java_sun_nio_ch_PollArrayWrapper_interrupt;
                 Java_sun_nio_ch_PollArrayWrapper_poll0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
                 Java_sun_nio_ch_SocketChannelImpl_checkConnect;
-		Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData;
-		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
-		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
-		Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
-		Java_sun_nio_fs_BsdNativeDispatcher_initIDs;
-		Java_sun_nio_fs_BsdNativeDispatcher_getfsstat;
-		Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry;
-		Java_sun_nio_fs_BsdNativeDispatcher_endfsstat;
-		Java_sun_nio_fs_UnixNativeDispatcher_init;
-		Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
-		Java_sun_nio_fs_UnixNativeDispatcher_strerror;
-		Java_sun_nio_fs_UnixNativeDispatcher_dup;
-		Java_sun_nio_fs_UnixNativeDispatcher_access0;
-		Java_sun_nio_fs_UnixNativeDispatcher_exists0;
-		Java_sun_nio_fs_UnixNativeDispatcher_stat0;
+                Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData;
+                Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
+                Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
+                Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
+                Java_sun_nio_fs_BsdNativeDispatcher_initIDs;
+                Java_sun_nio_fs_BsdNativeDispatcher_getfsstat;
+                Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry;
+                Java_sun_nio_fs_BsdNativeDispatcher_endfsstat;
+                Java_sun_nio_fs_UnixNativeDispatcher_init;
+                Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
+                Java_sun_nio_fs_UnixNativeDispatcher_strerror;
+                Java_sun_nio_fs_UnixNativeDispatcher_dup;
+                Java_sun_nio_fs_UnixNativeDispatcher_access0;
+                Java_sun_nio_fs_UnixNativeDispatcher_exists0;
+                Java_sun_nio_fs_UnixNativeDispatcher_stat0;
                 Java_sun_nio_fs_UnixNativeDispatcher_stat1;
-		Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fstat;
-		Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
-		Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
-		Java_sun_nio_fs_UnixNativeDispatcher_chown0;
-		Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fchown;
-		Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
-		Java_sun_nio_fs_UnixNativeDispatcher_futimes;
-		Java_sun_nio_fs_UnixNativeDispatcher_open0;
-		Java_sun_nio_fs_UnixNativeDispatcher_openat0;
-		Java_sun_nio_fs_UnixNativeDispatcher_close0;
-		Java_sun_nio_fs_UnixNativeDispatcher_read;
-		Java_sun_nio_fs_UnixNativeDispatcher_write;
-		Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fclose;
-		Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
-		Java_sun_nio_fs_UnixNativeDispatcher_readdir;
-		Java_sun_nio_fs_UnixNativeDispatcher_closedir;
-		Java_sun_nio_fs_UnixNativeDispatcher_link0;
-		Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
-		Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
-		Java_sun_nio_fs_UnixNativeDispatcher_rename0;
-		Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
-		Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
-		Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
-		Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
-		Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
-		Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
-		Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
-		Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
-		Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
-		Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
-		Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
-		Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
-		Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
-		Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
-		Java_sun_nio_fs_UnixCopyFile_transfer;
-		handleSocketError;
+                Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fstat;
+                Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
+                Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
+                Java_sun_nio_fs_UnixNativeDispatcher_chown0;
+                Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fchown;
+                Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
+                Java_sun_nio_fs_UnixNativeDispatcher_futimes;
+                Java_sun_nio_fs_UnixNativeDispatcher_open0;
+                Java_sun_nio_fs_UnixNativeDispatcher_openat0;
+                Java_sun_nio_fs_UnixNativeDispatcher_close0;
+                Java_sun_nio_fs_UnixNativeDispatcher_read;
+                Java_sun_nio_fs_UnixNativeDispatcher_write;
+                Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fclose;
+                Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
+                Java_sun_nio_fs_UnixNativeDispatcher_readdir;
+                Java_sun_nio_fs_UnixNativeDispatcher_closedir;
+                Java_sun_nio_fs_UnixNativeDispatcher_link0;
+                Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
+                Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
+                Java_sun_nio_fs_UnixNativeDispatcher_rename0;
+                Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
+                Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
+                Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
+                Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
+                Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
+                Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
+                Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
+                Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
+                Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
+                Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
+                Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
+                Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
+                Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
+                Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
+                Java_sun_nio_fs_UnixCopyFile_transfer;
+                handleSocketError;
 
 	local:
 		*;
--- a/make/mapfiles/libnio/mapfile-solaris	Fri Mar 23 09:51:02 2018 +0100
+++ b/make/mapfiles/libnio/mapfile-solaris	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2017, 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
@@ -38,7 +38,6 @@
                 Java_sun_nio_ch_DatagramDispatcher_write0;
                 Java_sun_nio_ch_DatagramDispatcher_writev0;
                 Java_sun_nio_ch_DevPollArrayWrapper_init;
-                Java_sun_nio_ch_DevPollArrayWrapper_interrupt;
                 Java_sun_nio_ch_DevPollArrayWrapper_poll0;
                 Java_sun_nio_ch_DevPollArrayWrapper_register;
                 Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple;
@@ -83,6 +82,7 @@
                 Java_sun_nio_ch_IOUtil_makePipe;
                 Java_sun_nio_ch_IOUtil_randomBytes;
                 Java_sun_nio_ch_IOUtil_setfdVal;
+                Java_sun_nio_ch_IOUtil_write1;
 		Java_sun_nio_ch_NativeThread_current;
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
--- a/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Fri Mar 23 14:18:18 2018 +0000
@@ -109,11 +109,11 @@
 
     private static native int dataOffset();
 
-    static native int epollCreate() throws IOException;
+    static native int create() throws IOException;
 
-    static native int epollCtl(int epfd, int opcode, int fd, int events);
+    static native int ctl(int epfd, int opcode, int fd, int events);
 
-    static native int epollWait(int epfd, long pollAddress, int numfds)
+    static native int wait(int epfd, long pollAddress, int numfds, int timeout)
         throws IOException;
 
     static {
--- a/src/java.base/linux/classes/sun/nio/ch/EPollArrayWrapper.java	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.security.AccessController;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.Map;
-import sun.security.action.GetIntegerAction;
-
-/**
- * Manipulates a native array of epoll_event structs on Linux:
- *
- * typedef union epoll_data {
- *     void *ptr;
- *     int fd;
- *     __uint32_t u32;
- *     __uint64_t u64;
- *  } epoll_data_t;
- *
- * struct epoll_event {
- *     __uint32_t events;
- *     epoll_data_t data;
- * };
- *
- * The system call to wait for I/O events is epoll_wait(2). It populates an
- * array of epoll_event structures that are passed to the call. The data
- * member of the epoll_event structure contains the same data as was set
- * when the file descriptor was registered to epoll via epoll_ctl(2). In
- * this implementation we set data.fd to be the file descriptor that we
- * register. That way, we have the file descriptor available when we
- * process the events.
- */
-
-class EPollArrayWrapper {
-    // EPOLL_EVENTS
-    private static final int EPOLLIN      = 0x001;
-
-    // opcodes
-    private static final int EPOLL_CTL_ADD      = 1;
-    private static final int EPOLL_CTL_DEL      = 2;
-    private static final int EPOLL_CTL_MOD      = 3;
-
-    // Miscellaneous constants
-    private static final int SIZE_EPOLLEVENT  = sizeofEPollEvent();
-    private static final int EVENT_OFFSET     = 0;
-    private static final int DATA_OFFSET      = offsetofData();
-    private static final int FD_OFFSET        = DATA_OFFSET;
-    private static final int OPEN_MAX         = IOUtil.fdLimit();
-    private static final int NUM_EPOLLEVENTS  = Math.min(OPEN_MAX, 8192);
-
-    // Special value to indicate that an update should be ignored
-    private static final byte  KILLED = (byte)-1;
-
-    // Initial size of arrays for fd registration changes
-    private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
-
-    // maximum size of updatesLow
-    private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
-        new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
-
-    // The fd of the epoll driver
-    private final int epfd;
-
-     // The epoll_event array for results from epoll_wait
-    private final AllocatedNativeObject pollArray;
-
-    // Base address of the epoll_event array
-    private final long pollArrayAddress;
-
-    // The fd of the interrupt line going out
-    private final int outgoingInterruptFD;
-
-    // Number of updated pollfd entries
-    private int updated;
-
-    // object to synchronize fd registration changes
-    private final Object updateLock = new Object();
-
-    // number of file descriptors with registration changes pending
-    private int updateCount;
-
-    // file descriptors with registration changes pending
-    private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
-
-    // events for file descriptors with registration changes pending, indexed
-    // by file descriptor and stored as bytes for efficiency reasons. For
-    // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
-    // least) then the update is stored in a map.
-    private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
-    private final Map<Integer,Byte> eventsHigh = new HashMap<>();
-
-    // Used by release and updateRegistrations to track whether a file
-    // descriptor is registered with epoll.
-    private final BitSet registered = new BitSet();
-
-
-    EPollArrayWrapper(int fd0, int fd1) throws IOException {
-        // creates the epoll file descriptor
-        epfd = epollCreate();
-
-        // the epoll_event array passed to epoll_wait
-        int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
-        pollArray = new AllocatedNativeObject(allocationSize, true);
-        pollArrayAddress = pollArray.address();
-
-        outgoingInterruptFD = fd1;
-        epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
-    }
-
-    void putEventOps(int i, int event) {
-        int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
-        pollArray.putInt(offset, event);
-    }
-
-    void putDescriptor(int i, int fd) {
-        int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
-        pollArray.putInt(offset, fd);
-    }
-
-    int getEventOps(int i) {
-        int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
-        return pollArray.getInt(offset);
-    }
-
-    int getDescriptor(int i) {
-        int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
-        return pollArray.getInt(offset);
-    }
-
-    /**
-     * Returns {@code true} if updates for the given key (file
-     * descriptor) are killed.
-     */
-    private boolean isEventsHighKilled(Integer key) {
-        assert key >= MAX_UPDATE_ARRAY_SIZE;
-        Byte value = eventsHigh.get(key);
-        return (value != null && value == KILLED);
-    }
-
-    /**
-     * Sets the pending update events for the given file descriptor. This
-     * method has no effect if the update events is already set to KILLED,
-     * unless {@code force} is {@code true}.
-     */
-    private void setUpdateEvents(int fd, byte events, boolean force) {
-        if (fd < MAX_UPDATE_ARRAY_SIZE) {
-            if ((eventsLow[fd] != KILLED) || force) {
-                eventsLow[fd] = events;
-            }
-        } else {
-            Integer key = Integer.valueOf(fd);
-            if (!isEventsHighKilled(key) || force) {
-                eventsHigh.put(key, Byte.valueOf(events));
-            }
-        }
-    }
-
-    /**
-     * Returns the pending update events for the given file descriptor.
-     */
-    private byte getUpdateEvents(int fd) {
-        if (fd < MAX_UPDATE_ARRAY_SIZE) {
-            return eventsLow[fd];
-        } else {
-            Byte result = eventsHigh.get(Integer.valueOf(fd));
-            // result should never be null
-            return result.byteValue();
-        }
-    }
-
-    /**
-     * Update the events for a given file descriptor
-     */
-    void setInterest(int fd, int mask) {
-        synchronized (updateLock) {
-            // record the file descriptor and events
-            int oldCapacity = updateDescriptors.length;
-            if (updateCount == oldCapacity) {
-                int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
-                int[] newDescriptors = new int[newCapacity];
-                System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
-                updateDescriptors = newDescriptors;
-            }
-            updateDescriptors[updateCount++] = fd;
-
-            // events are stored as bytes for efficiency reasons
-            byte b = (byte)mask;
-            assert (b == mask) && (b != KILLED);
-            setUpdateEvents(fd, b, false);
-        }
-    }
-
-    /**
-     * Add a file descriptor
-     */
-    void add(int fd) {
-        // force the initial update events to 0 as it may be KILLED by a
-        // previous registration.
-        synchronized (updateLock) {
-            assert !registered.get(fd);
-            setUpdateEvents(fd, (byte)0, true);
-        }
-    }
-
-    /**
-     * Remove a file descriptor
-     */
-    void remove(int fd) {
-        synchronized (updateLock) {
-            // kill pending and future update for this file descriptor
-            setUpdateEvents(fd, KILLED, false);
-
-            // remove from epoll
-            if (registered.get(fd)) {
-                epollCtl(epfd, EPOLL_CTL_DEL, fd, 0);
-                registered.clear(fd);
-            }
-        }
-    }
-
-    /**
-     * Close epoll file descriptor and free poll array
-     */
-    void close() throws IOException {
-        FileDispatcherImpl.closeIntFD(epfd);
-        pollArray.free();
-    }
-
-    int poll(long timeout) throws IOException {
-        updateRegistrations();
-        return epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
-    }
-
-    /**
-     * Update the pending registrations.
-     */
-    private void updateRegistrations() {
-        synchronized (updateLock) {
-            int j = 0;
-            while (j < updateCount) {
-                int fd = updateDescriptors[j];
-                short events = getUpdateEvents(fd);
-                boolean isRegistered = registered.get(fd);
-                int opcode = 0;
-
-                if (events != KILLED) {
-                    if (isRegistered) {
-                        opcode = (events != 0) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
-                    } else {
-                        opcode = (events != 0) ? EPOLL_CTL_ADD : 0;
-                    }
-                    if (opcode != 0) {
-                        epollCtl(epfd, opcode, fd, events);
-                        if (opcode == EPOLL_CTL_ADD) {
-                            registered.set(fd);
-                        } else if (opcode == EPOLL_CTL_DEL) {
-                            registered.clear(fd);
-                        }
-                    }
-                }
-                j++;
-            }
-            updateCount = 0;
-        }
-    }
-
-    public void interrupt() {
-        interrupt(outgoingInterruptFD);
-    }
-
-    static {
-        IOUtil.load();
-        init();
-    }
-
-    private native int epollCreate();
-    private native void epollCtl(int epfd, int opcode, int fd, int events);
-    private native int epollWait(long pollAddress, int numfds, long timeout,
-                                 int epfd) throws IOException;
-    private static native int sizeofEPollEvent();
-    private static native int offsetofData();
-    private static native void interrupt(int fd);
-    private static native void init();
-}
--- a/src/java.base/linux/classes/sun/nio/ch/EPollPort.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollPort.java	Fri Mar 23 14:18:18 2018 +0000
@@ -30,7 +30,13 @@
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
-import static sun.nio.ch.EPoll.*;
+
+import static sun.nio.ch.EPoll.EPOLLIN;
+import static sun.nio.ch.EPoll.EPOLLONESHOT;
+import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
+import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
+import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
+
 
 /**
  * AsynchronousChannelGroup implementation based on the Linux epoll facility.
@@ -48,6 +54,9 @@
     // epoll file descriptor
     private final int epfd;
 
+    // address of the poll array passed to epoll_wait
+    private final long address;
+
     // true if epoll closed
     private boolean closed;
 
@@ -57,9 +66,6 @@
     // number of wakeups pending
     private final AtomicInteger wakeupCount = new AtomicInteger();
 
-    // address of the poll array passed to epoll_wait
-    private final long address;
-
     // encapsulates an event for a channel
     static class Event {
         final PollableChannel channel;
@@ -85,23 +91,21 @@
     {
         super(provider, pool);
 
-        // open epoll
-        this.epfd = epollCreate();
+        this.epfd = EPoll.create();
+        this.address = EPoll.allocatePollArray(MAX_EPOLL_EVENTS);
 
         // create socket pair for wakeup mechanism
-        int[] sv = new int[2];
         try {
-            socketpair(sv);
-            // register one end with epoll
-            epollCtl(epfd, EPOLL_CTL_ADD, sv[0], EPOLLIN);
-        } catch (IOException x) {
-            close0(epfd);
-            throw x;
+            long fds = IOUtil.makePipe(true);
+            this.sp = new int[]{(int) (fds >>> 32), (int) fds};
+        } catch (IOException ioe) {
+            EPoll.freePollArray(address);
+            FileDispatcherImpl.closeIntFD(epfd);
+            throw ioe;
         }
-        this.sp = sv;
 
-        // allocate the poll array
-        this.address = allocatePollArray(MAX_EPOLL_EVENTS);
+        // register one end with epoll
+        EPoll.ctl(epfd, EPOLL_CTL_ADD, sp[0], EPOLLIN);
 
         // create the queue and offer the special event to ensure that the first
         // threads polls
@@ -123,17 +127,17 @@
                 return;
             closed = true;
         }
-        freePollArray(address);
-        close0(sp[0]);
-        close0(sp[1]);
-        close0(epfd);
+        try { FileDispatcherImpl.closeIntFD(epfd); } catch (IOException ioe) { }
+        try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
+        try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
+        EPoll.freePollArray(address);
     }
 
     private void wakeup() {
         if (wakeupCount.incrementAndGet() == 1) {
             // write byte to socketpair to force wakeup
             try {
-                interrupt(sp[1]);
+                IOUtil.write1(sp[1], (byte)0);
             } catch (IOException x) {
                 throw new AssertionError(x);
             }
@@ -171,9 +175,9 @@
     @Override
     void startPoll(int fd, int events) {
         // update events (or add to epoll on first usage)
-        int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
+        int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
         if (err == ENOENT)
-            err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
+            err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
         if (err != 0)
             throw new AssertionError();     // should not happen
     }
@@ -191,7 +195,11 @@
         private Event poll() throws IOException {
             try {
                 for (;;) {
-                    int n = epollWait(epfd, address, MAX_EPOLL_EVENTS);
+                    int n;
+                    do {
+                        n = EPoll.wait(epfd, address, MAX_EPOLL_EVENTS, -1);
+                    } while (n == IOStatus.INTERRUPTED);
+
                     /*
                      * 'n' events have been read. Here we map them to their
                      * corresponding channel in batch and queue n-1 so that
@@ -201,14 +209,14 @@
                     fdToChannelLock.readLock().lock();
                     try {
                         while (n-- > 0) {
-                            long eventAddress = getEvent(address, n);
-                            int fd = getDescriptor(eventAddress);
+                            long eventAddress = EPoll.getEvent(address, n);
+                            int fd = EPoll.getDescriptor(eventAddress);
 
                             // wakeup
                             if (fd == sp[0]) {
                                 if (wakeupCount.decrementAndGet() == 0) {
                                     // no more wakeups so drain pipe
-                                    drain1(sp[0]);
+                                    IOUtil.drain(sp[0]);
                                 }
 
                                 // queue special event if there are more events
@@ -222,7 +230,7 @@
 
                             PollableChannel channel = fdToChannel.get(fd);
                             if (channel != null) {
-                                int events = getEvents(eventAddress);
+                                int events = EPoll.getEvents(eventAddress);
                                 Event ev = new Event(channel, events);
 
                                 // n-1 events are queued; This thread handles
@@ -306,18 +314,4 @@
             }
         }
     }
-
-    // -- Native methods --
-
-    private static native void socketpair(int[] sv) throws IOException;
-
-    private static native void interrupt(int fd) throws IOException;
-
-    private static native void drain1(int fd) throws IOException;
-
-    private static native void close0(int fd);
-
-    static {
-        IOUtil.load();
-    }
 }
--- a/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -26,33 +26,59 @@
 package sun.nio.ch;
 
 import java.io.IOException;
-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.ArrayDeque;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static sun.nio.ch.EPoll.EPOLLIN;
+import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
+import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
+import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
+
 
 /**
- * An implementation of Selector for Linux 2.6+ kernels that uses
- * the epoll event notification facility.
+ * Linux epoll based Selector implementation
  */
-class EPollSelectorImpl
-    extends SelectorImpl
-{
-    // File descriptors used for interrupt
+
+class EPollSelectorImpl extends SelectorImpl {
+
+    // maximum number of events to poll in one call to epoll_wait
+    private static final int NUM_EPOLLEVENTS = Math.min(IOUtil.fdLimit(), 1024);
+
+    // epoll file descriptor
+    private final int epfd;
+
+    // address of poll array when polling with epoll_wait
+    private final long pollArrayAddress;
+
+    // file descriptors used for interrupt
     private final int fd0;
     private final int fd1;
 
-    // The poll object
-    private final EPollArrayWrapper pollWrapper;
+    // maps file descriptor to selection key, synchronize on selector
+    private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
 
-    // Maps from file descriptors to keys
-    private final Map<Integer, SelectionKeyImpl> fdToKey;
+    // file descriptors registered with epoll, synchronize on selector
+    private final BitSet registered = new BitSet();
 
-    // True if this Selector has been closed
-    private volatile boolean closed;
+    // pending new registrations/updates, queued by implRegister and putEventOps
+    private final Object updateLock = new Object();
+    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
+    private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+    private final Deque<Integer> updateOps = new ArrayDeque<>();
 
-    // Lock for interrupt triggering and clearing
+    // 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
@@ -60,40 +86,57 @@
      */
     EPollSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
-        long pipeFds = IOUtil.makePipe(false);
-        fd0 = (int) (pipeFds >>> 32);
-        fd1 = (int) pipeFds;
+
+        this.epfd = EPoll.create();
+        this.pollArrayAddress = EPoll.allocatePollArray(NUM_EPOLLEVENTS);
+
         try {
-            pollWrapper = new EPollArrayWrapper(fd0, fd1);
-            fdToKey = new HashMap<>();
-        } catch (Throwable t) {
-            try {
-                FileDispatcherImpl.closeIntFD(fd0);
-            } catch (IOException ioe0) {
-                t.addSuppressed(ioe0);
-            }
-            try {
-                FileDispatcherImpl.closeIntFD(fd1);
-            } catch (IOException ioe1) {
-                t.addSuppressed(ioe1);
-            }
-            throw t;
+            long fds = IOUtil.makePipe(false);
+            this.fd0 = (int) (fds >>> 32);
+            this.fd1 = (int) fds;
+        } catch (IOException ioe) {
+            EPoll.freePollArray(pollArrayAddress);
+            FileDispatcherImpl.closeIntFD(epfd);
+            throw ioe;
         }
+
+        // register one end of the socket pair for wakeups
+        EPoll.ctl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
     }
 
     private void ensureOpen() {
-        if (closed)
+        if (!isOpen())
             throw new ClosedSelectorException();
     }
 
     @Override
     protected int doSelect(long timeout) throws IOException {
-        ensureOpen();
+        assert Thread.holdsLock(this);
+
         int numEntries;
+        processUpdateQueue();
         processDeregisterQueue();
         try {
             begin();
-            numEntries = pollWrapper.poll(timeout);
+
+            // epoll_wait timeout is int
+            int to = (int) Math.min(timeout, Integer.MAX_VALUE);
+            boolean timedPoll = (to > 0);
+            do {
+                long startTime = timedPoll ? System.nanoTime() : 0;
+                numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, 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();
         }
@@ -102,20 +145,69 @@
     }
 
     /**
+     * Process new registrations and changes to the interest ops.
+     */
+    private void processUpdateQueue() {
+        assert Thread.holdsLock(this);
+
+        synchronized (updateLock) {
+            SelectionKeyImpl ski;
+
+            // new registrations
+            while ((ski = newKeys.pollFirst()) != null) {
+                if (ski.isValid()) {
+                    SelChImpl ch = ski.channel;
+                    int fd = ch.getFDVal();
+                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
+                    assert previous == null;
+                    assert registered.get(fd) == false;
+                }
+            }
+
+            // changes to interest ops
+            assert updateKeys.size() == updateOps.size();
+            while ((ski = updateKeys.pollFirst()) != null) {
+                int ops = updateOps.pollFirst();
+                int fd = ski.channel.getFDVal();
+                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                    if (registered.get(fd)) {
+                        if (ops == 0) {
+                            // remove from epoll
+                            EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
+                            registered.clear(fd);
+                        } else {
+                            // modify events
+                            EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, ops);
+                        }
+                    } else if (ops != 0) {
+                        // add to epoll
+                        EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, ops);
+                        registered.set(fd);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Update the keys whose fd's have been selected by the epoll.
      * Add the ready keys to the ready queue.
      */
     private int updateSelectedKeys(int numEntries) throws IOException {
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioSelectedKeys());
+
         boolean interrupted = false;
         int numKeysUpdated = 0;
         for (int i=0; i<numEntries; i++) {
-            int nextFD = pollWrapper.getDescriptor(i);
-            if (nextFD == fd0) {
+            long event = EPoll.getEvent(pollArrayAddress, i);
+            int fd = EPoll.getDescriptor(event);
+            if (fd == fd0) {
                 interrupted = true;
             } else {
-                SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
+                SelectionKeyImpl ski = fdToKey.get(fd);
                 if (ski != null) {
-                    int rOps = pollWrapper.getEventOps(i);
+                    int rOps = EPoll.getEvents(event);
                     if (selectedKeys.contains(ski)) {
                         if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
                             numKeysUpdated++;
@@ -140,16 +232,17 @@
 
     @Override
     protected void implClose() throws IOException {
-        if (closed)
-            return;
-        closed = true;
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioKeys());
 
         // prevent further wakeup
         synchronized (interruptLock) {
             interruptTriggered = true;
         }
 
-        pollWrapper.close();
+        FileDispatcherImpl.closeIntFD(epfd);
+        EPoll.freePollArray(pollArrayAddress);
+
         FileDispatcherImpl.closeIntFD(fd0);
         FileDispatcherImpl.closeIntFD(fd1);
 
@@ -167,42 +260,57 @@
 
     @Override
     protected void implRegister(SelectionKeyImpl ski) {
+        assert Thread.holdsLock(nioKeys());
         ensureOpen();
-        SelChImpl ch = ski.channel;
-        int fd = Integer.valueOf(ch.getFDVal());
-        fdToKey.put(fd, ski);
-        pollWrapper.add(fd);
+        synchronized (updateLock) {
+            newKeys.addLast(ski);
+        }
         keys.add(ski);
     }
 
     @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
-        assert (ski.getIndex() >= 0);
-        SelChImpl ch = ski.channel;
-        int fd = ch.getFDVal();
-        fdToKey.remove(Integer.valueOf(fd));
-        pollWrapper.remove(fd);
-        ski.setIndex(-1);
+        assert !ski.isValid();
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioKeys());
+        assert Thread.holdsLock(nioSelectedKeys());
+
+        int fd = ski.channel.getFDVal();
+        fdToKey.remove(fd);
+        if (registered.get(fd)) {
+            EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
+            registered.clear(fd);
+        }
+
+        selectedKeys.remove(ski);
         keys.remove(ski);
-        selectedKeys.remove(ski);
+
+        // remove from channel's key set
         deregister(ski);
+
         SelectableChannel selch = ski.channel();
         if (!selch.isOpen() && !selch.isRegistered())
-            ((SelChImpl)selch).kill();
+            ((SelChImpl) selch).kill();
     }
 
     @Override
     public void putEventOps(SelectionKeyImpl ski, int ops) {
         ensureOpen();
-        SelChImpl ch = ski.channel;
-        pollWrapper.setInterest(ch.getFDVal(), ops);
+        synchronized (updateLock) {
+            updateOps.addLast(ops);   // ops first in case adding the key fails
+            updateKeys.addLast(ski);
+        }
     }
 
     @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
-                pollWrapper.interrupt();
+                try {
+                    IOUtil.write1(fd1, (byte)0);
+                } catch (IOException ioe) {
+                    throw new InternalError(ioe);
+                }
                 interruptTriggered = true;
             }
         }
--- a/src/java.base/linux/native/libnio/ch/EPoll.c	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/linux/native/libnio/ch/EPoll.c	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, 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
@@ -23,53 +23,51 @@
  * questions.
  */
 
+ #include <dlfcn.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/epoll.h>
+
 #include "jni.h"
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
+#include "nio.h"
 #include "nio_util.h"
 
 #include "sun_nio_ch_EPoll.h"
 
-#include <dlfcn.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/epoll.h>
-
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass this)
+Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass clazz)
 {
     return sizeof(struct epoll_event);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass this)
+Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass clazz)
 {
     return offsetof(struct epoll_event, events);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass this)
+Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass clazz)
 {
     return offsetof(struct epoll_event, data);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_epollCreate(JNIEnv *env, jclass c) {
-    /*
-     * epoll_create expects a size as a hint to the kernel about how to
-     * dimension internal structures. We can't predict the size in advance.
-     */
+Java_sun_nio_ch_EPoll_create(JNIEnv *env, jclass clazz) {
+    /* size hint not used in modern kernels */
     int epfd = epoll_create(256);
     if (epfd < 0) {
-       JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
+        JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
     }
     return epfd;
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
-                                   jint opcode, jint fd, jint events)
+Java_sun_nio_ch_EPoll_ctl(JNIEnv *env, jclass clazz, jint epfd,
+                          jint opcode, jint fd, jint events)
 {
     struct epoll_event event;
     int res;
@@ -77,21 +75,23 @@
     event.events = events;
     event.data.fd = fd;
 
-    RESTARTABLE(epoll_ctl(epfd, (int)opcode, (int)fd, &event), res);
-
+    res = epoll_ctl(epfd, (int)opcode, (int)fd, &event);
     return (res == 0) ? 0 : errno;
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c,
-                                    jint epfd, jlong address, jint numfds)
+Java_sun_nio_ch_EPoll_wait(JNIEnv *env, jclass clazz, jint epfd,
+                           jlong address, jint numfds, jint timeout)
 {
     struct epoll_event *events = jlong_to_ptr(address);
-    int res;
-
-    RESTARTABLE(epoll_wait(epfd, events, numfds, -1), res);
+    int res = epoll_wait(epfd, events, numfds, timeout);
     if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
+            return IOS_THROWN;
+        }
     }
     return res;
 }
--- a/src/java.base/linux/native/libnio/ch/EPollArrayWrapper.c	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2005, 2016, 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-
-#include "sun_nio_ch_EPollArrayWrapper.h"
-
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/epoll.h>
-
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-
-static int
-iepoll(int epfd, struct epoll_event *events, int numfds, jlong timeout)
-{
-    jlong start, now;
-    int remaining = timeout;
-    struct timeval t;
-    int diff;
-
-    gettimeofday(&t, NULL);
-    start = t.tv_sec * 1000 + t.tv_usec / 1000;
-
-    for (;;) {
-        int res = epoll_wait(epfd, events, numfds, remaining);
-        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;
-            }
-        } else {
-            return res;
-        }
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_init(JNIEnv *env, jclass this)
-{
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_epollCreate(JNIEnv *env, jobject this)
-{
-    /*
-     * epoll_create expects a size as a hint to the kernel about how to
-     * dimension internal structures. We can't predict the size in advance.
-     */
-    int epfd = epoll_create(256);
-    if (epfd < 0) {
-       JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
-    }
-    return epfd;
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this)
-{
-    return sizeof(struct epoll_event);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_offsetofData(JNIEnv* env, jclass this)
-{
-    return offsetof(struct epoll_event, data);
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_epollCtl(JNIEnv *env, jobject this, jint epfd,
-                                           jint opcode, jint fd, jint events)
-{
-    struct epoll_event event;
-    int res;
-
-    event.events = events;
-    event.data.fd = fd;
-
-    RESTARTABLE(epoll_ctl(epfd, (int)opcode, (int)fd, &event), res);
-
-    /*
-     * A channel may be registered with several Selectors. When each Selector
-     * is polled a EPOLL_CTL_DEL op will be inserted into its pending update
-     * list to remove the file descriptor from epoll. The "last" Selector will
-     * close the file descriptor which automatically unregisters it from each
-     * epoll descriptor. To avoid costly synchronization between Selectors we
-     * allow pending updates to be processed, ignoring errors. The errors are
-     * harmless as the last update for the file descriptor is guaranteed to
-     * be EPOLL_CTL_DEL.
-     */
-    if (res < 0 && errno != EBADF && errno != ENOENT && errno != EPERM) {
-        JNU_ThrowIOExceptionWithLastError(env, "epoll_ctl failed");
-    }
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_epollWait(JNIEnv *env, jobject this,
-                                            jlong address, jint numfds,
-                                            jlong timeout, jint epfd)
-{
-    struct epoll_event *events = jlong_to_ptr(address);
-    int res;
-
-    if (timeout <= 0) {           /* Indefinite or no wait */
-        RESTARTABLE(epoll_wait(epfd, events, numfds, timeout), res);
-    } else {                      /* Bounded wait; bounded restarts */
-        res = iepoll(epfd, events, numfds, timeout);
-    }
-
-    if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
-    }
-    return res;
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd)
-{
-    int fakebuf[1];
-    fakebuf[0] = 1;
-    if (write(fd, fakebuf, 1) < 0) {
-        JNU_ThrowIOExceptionWithLastError(env,"write to interrupt fd failed");
-    }
-}
--- a/src/java.base/linux/native/libnio/ch/EPollPort.c	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "nio_util.h"
-
-#include "sun_nio_ch_EPollPort.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
-    int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
-    } else {
-        jint res[2];
-        res[0] = (jint)sp[0];
-        res[1] = (jint)sp[1];
-        (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollPort_interrupt(JNIEnv *env, jclass c, jint fd) {
-    int res;
-    int buf[1];
-    buf[0] = 1;
-    RESTARTABLE(write(fd, buf, 1), res);
-    if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "write failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollPort_drain1(JNIEnv *env, jclass cl, jint fd) {
-    int res;
-    char buf[1];
-    RESTARTABLE(read(fd, buf, 1), res);
-    if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_EPollPort_close0(JNIEnv *env, jclass c, jint fd) {
-    int res;
-    RESTARTABLE(close(fd), res);
-}
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Fri Mar 23 14:18:18 2018 +0000
@@ -84,17 +84,17 @@
     }
 
     /**
-     * Returns the file descriptor from a kevent (assuming to be in ident field)
+     * Returns the file descriptor from a kevent (assuming it is in the ident field)
      */
     static int getDescriptor(long address) {
         return unsafe.getInt(address + OFFSET_IDENT);
     }
 
-    static int getFilter(long address) {
+    static short getFilter(long address) {
         return unsafe.getShort(address + OFFSET_FILTER);
     }
 
-    static int getFlags(long address) {
+    static short getFlags(long address) {
         return unsafe.getShort(address + OFFSET_FLAGS);
     }
 
@@ -108,11 +108,11 @@
 
     private static native int flagsOffset();
 
-    static native int kqueue() throws IOException;
+    static native int create() throws IOException;
 
-    static native int keventRegister(int kqpfd, int fd, int filter, int flags);
+    static native int register(int kqfd, int fd, int filter, int flags);
 
-    static native int keventPoll(int kqpfd, long pollAddress, int nevents)
+    static native int poll(int kqfd, long pollAddress, int nevents, long timeout)
         throws IOException;
 
     static {
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * KQueueArrayWrapper.java
- * Implementation of Selector using FreeBSD / Mac OS X kqueues
- * Derived from Sun's DevPollArrayWrapper
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.LinkedList;
-import sun.security.action.GetPropertyAction;
-
-/*
- * struct kevent {           // 32-bit    64-bit
- *     uintptr_t ident;      //   4         8
- *     short     filter;     //   2         2
- *     u_short   flags;      //   2         2
- *     u_int     fflags;     //   4         4
- *     intptr_t  data;       //   4         8
- *     void      *udata;     //   4         8
- * }                  // Total:  20        32
- *
- * The implementation works in 32-bit and 64-bit world. We do this by calling a
- * native function that actually sets the sizes and offsets of the fields based
- * on which mode we're in.
- */
-
-class KQueueArrayWrapper {
-    // kevent filters
-    static short EVFILT_READ;
-    static short EVFILT_WRITE;
-
-    // kevent struct
-    // These fields are now set by initStructSizes in the static initializer.
-    static short SIZEOF_KEVENT;
-    static short FD_OFFSET;
-    static short FILTER_OFFSET;
-
-    // kevent array size
-    static final int NUM_KEVENTS = 128;
-
-    // Are we in a 64-bit VM?
-    static boolean is64bit;
-
-    // The kevent array (used for outcoming events only)
-    private final AllocatedNativeObject keventArray;
-    private final long keventArrayAddress;
-
-    // The kqueue fd
-    private final int kq;
-
-    // The fd of the interrupt line going out
-    private final int outgoingInterruptFD;
-
-
-    static {
-        IOUtil.load();
-        initStructSizes();
-        String datamodel =
-                GetPropertyAction.privilegedGetProperty("sun.arch.data.model");
-        is64bit = "64".equals(datamodel);
-    }
-
-    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
-    private static class Update {
-        SelChImpl channel;
-        int events;
-        Update(SelChImpl channel, int events) {
-            this.channel = channel;
-            this.events = events;
-        }
-    }
-
-    private LinkedList<Update> updateList = new LinkedList<Update>();
-
-    int getReventOps(int index) {
-        int result = 0;
-        int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
-        short filter = keventArray.getShort(offset);
-
-        // This is all that's necessary based on inspection of usage:
-        //   SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl,
-        //   ServerSocketChannelImpl, SocketChannelImpl
-        if (filter == EVFILT_READ) {
-            result |= Net.POLLIN;
-        } else if (filter == EVFILT_WRITE) {
-            result |= Net.POLLOUT;
-        }
-
-        return result;
-    }
-
-    int getDescriptor(int index) {
-        int offset = SIZEOF_KEVENT*index + FD_OFFSET;
-        /* The ident field is 8 bytes in 64-bit world, however the API wants us
-         * 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;
-        } else {
-            return keventArray.getInt(offset);
-        }
-    }
-
-    void setInterest(SelChImpl channel, int events) {
-        synchronized (updateList) {
-            // update existing registration
-            updateList.add(new Update(channel, events));
-        }
-    }
-
-    void release(SelChImpl channel) {
-        synchronized (updateList) {
-            // flush any pending updates
-            for (Iterator<Update> it = updateList.iterator(); it.hasNext();) {
-                if (it.next().channel == channel) {
-                    it.remove();
-                }
-            }
-
-            // remove
-            register0(kq, channel.getFDVal(), 0, 0);
-        }
-    }
-
-    void updateRegistrations() {
-        synchronized (updateList) {
-            Update u;
-            while ((u = updateList.poll()) != null) {
-                SelChImpl ch = u.channel;
-                if (!ch.isOpen())
-                    continue;
-
-                register0(kq, ch.getFDVal(), u.events & Net.POLLIN, u.events & Net.POLLOUT);
-            }
-        }
-    }
-
-    void close() throws IOException {
-        FileDispatcherImpl.closeIntFD(kq);
-        keventArray.free();
-    }
-
-    int poll(long timeout) {
-        updateRegistrations();
-        return kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
-    }
-
-    void interrupt() {
-        interrupt(outgoingInterruptFD);
-    }
-
-    private native int init();
-    private static native void initStructSizes();
-
-    private native void register0(int kq, int fd, int read, int write);
-    private native int kevent0(int kq, long keventAddress, int keventCount,
-                               long timeout);
-    private static native void interrupt(int fd);
-}
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java	Fri Mar 23 14:18:18 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
@@ -30,7 +30,11 @@
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
-import static sun.nio.ch.KQueue.*;
+
+import static sun.nio.ch.KQueue.EVFILT_READ;
+import static sun.nio.ch.KQueue.EVFILT_WRITE;
+import static sun.nio.ch.KQueue.EV_ADD;
+import static sun.nio.ch.KQueue.EV_ONESHOT;
 
 /**
  * AsynchronousChannelGroup implementation based on the BSD kqueue facility.
@@ -45,6 +49,9 @@
     // kqueue file descriptor
     private final int kqfd;
 
+    // address of the poll array passed to kqueue_wait
+    private final long address;
+
     // true if kqueue closed
     private boolean closed;
 
@@ -54,9 +61,6 @@
     // number of wakeups pending
     private final AtomicInteger wakeupCount = new AtomicInteger();
 
-    // address of the poll array passed to kqueue_wait
-    private final long address;
-
     // encapsulates an event for a channel
     static class Event {
         final PollableChannel channel;
@@ -82,28 +86,25 @@
     {
         super(provider, pool);
 
-        // open kqueue
-        this.kqfd = kqueue();
+        this.kqfd = KQueue.create();
+        this.address = KQueue.allocatePollArray(MAX_KEVENTS_TO_POLL);
 
         // create socket pair for wakeup mechanism
-        int[] sv = new int[2];
         try {
-            socketpair(sv);
+            long fds = IOUtil.makePipe(true);
+            this.sp = new int[]{(int) (fds >>> 32), (int) fds};
+        } catch (IOException ioe) {
+            KQueue.freePollArray(address);
+            FileDispatcherImpl.closeIntFD(kqfd);
+            throw ioe;
+        }
 
-            // register one end with kqueue
-            keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
-        } catch (IOException x) {
-            close0(kqfd);
-            throw x;
-        }
-        this.sp = sv;
-
-        // allocate the poll array
-        this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
+        // register one end with kqueue
+        KQueue.register(kqfd, sp[0], EVFILT_READ, EV_ADD);
 
         // create the queue and offer the special event to ensure that the first
         // threads polls
-        this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
+        this.queue = new ArrayBlockingQueue<>(MAX_KEVENTS_TO_POLL);
         this.queue.offer(NEED_TO_POLL);
     }
 
@@ -121,17 +122,18 @@
                 return;
             closed = true;
         }
-        freePollArray(address);
-        close0(sp[0]);
-        close0(sp[1]);
-        close0(kqfd);
+
+        try { FileDispatcherImpl.closeIntFD(kqfd); } catch (IOException ioe) { }
+        try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
+        try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
+        KQueue.freePollArray(address);
     }
 
     private void wakeup() {
         if (wakeupCount.incrementAndGet() == 1) {
             // write byte to socketpair to force wakeup
             try {
-                interrupt(sp[1]);
+                IOUtil.write1(sp[1], (byte)0);
             } catch (IOException x) {
                 throw new AssertionError(x);
             }
@@ -173,9 +175,9 @@
         int err = 0;
         int flags = (EV_ADD|EV_ONESHOT);
         if ((events & Net.POLLIN) > 0)
-            err = keventRegister(kqfd, fd, EVFILT_READ, flags);
+            err = KQueue.register(kqfd, fd, EVFILT_READ, flags);
         if (err == 0 && (events & Net.POLLOUT) > 0)
-            err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
+            err = KQueue.register(kqfd, fd, EVFILT_WRITE, flags);
         if (err != 0)
             throw new InternalError("kevent failed: " + err);  // should not happen
     }
@@ -193,7 +195,11 @@
         private Event poll() throws IOException {
             try {
                 for (;;) {
-                    int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
+                    int n;
+                    do {
+                        n = KQueue.poll(kqfd, address, MAX_KEVENTS_TO_POLL, -1L);
+                    } while (n == IOStatus.INTERRUPTED);
+
                     /*
                      * 'n' events have been read. Here we map them to their
                      * corresponding channel in batch and queue n-1 so that
@@ -203,14 +209,14 @@
                     fdToChannelLock.readLock().lock();
                     try {
                         while (n-- > 0) {
-                            long keventAddress = getEvent(address, n);
-                            int fd = getDescriptor(keventAddress);
+                            long keventAddress = KQueue.getEvent(address, n);
+                            int fd = KQueue.getDescriptor(keventAddress);
 
                             // wakeup
                             if (fd == sp[0]) {
                                 if (wakeupCount.decrementAndGet() == 0) {
                                     // no more wakeups so drain pipe
-                                    drain1(sp[0]);
+                                    IOUtil.drain(sp[0]);
                                 }
 
                                 // queue special event if there are more events
@@ -224,7 +230,7 @@
 
                             PollableChannel channel = fdToChannel.get(fd);
                             if (channel != null) {
-                                int filter = getFilter(keventAddress);
+                                int filter = KQueue.getFilter(keventAddress);
                                 int events = 0;
                                 if (filter == EVFILT_READ)
                                     events = Net.POLLIN;
@@ -314,18 +320,4 @@
             }
         }
     }
-
-    // -- Native methods --
-
-    private static native void socketpair(int[] sv) throws IOException;
-
-    private static native void interrupt(int fd) throws IOException;
-
-    private static native void drain1(int fd) throws IOException;
-
-    private static native void close0(int fd);
-
-    static {
-        IOUtil.load();
-    }
 }
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -23,11 +23,6 @@
  * questions.
  */
 
-/*
- * KQueueSelectorImpl.java
- * Implementation of Selector using FreeBSD / Mac OS X kqueues
- */
-
 package sun.nio.ch;
 
 import java.io.IOException;
@@ -36,85 +31,111 @@
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.BitSet;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
-class KQueueSelectorImpl
-    extends SelectorImpl
-{
-    // File descriptors used for interrupt
+import static sun.nio.ch.KQueue.EVFILT_READ;
+import static sun.nio.ch.KQueue.EVFILT_WRITE;
+import static sun.nio.ch.KQueue.EV_ADD;
+import static sun.nio.ch.KQueue.EV_DELETE;
+
+/**
+ * KQueue based Selector implementation for macOS
+ */
+
+class KQueueSelectorImpl extends SelectorImpl {
+
+    // maximum number of events to poll in one call to kqueue
+    private static final int MAX_KEVENTS = 256;
+
+    // kqueue file descriptor
+    private final int kqfd;
+
+    // address of poll array (event list) when polling for pending events
+    private final long pollArrayAddress;
+
+    // file descriptors used for interrupt
     private final int fd0;
     private final int fd1;
 
-    // The kqueue manipulator
-    private final KQueueArrayWrapper kqueueWrapper;
+    // maps file descriptor to selection key, synchronize on selector
+    private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
 
-    // Map from a file descriptor to an entry containing the selection key
-    private final HashMap<Integer, MapEntry> fdMap;
+    // file descriptors registered with kqueue, synchronize on selector
+    private final BitSet registeredReadFilter = new BitSet();
+    private final BitSet registeredWriteFilter = new BitSet();
 
-    // True if this Selector has been closed
-    private boolean closed;
+    // pending new registrations/updates, queued by implRegister and putEventOps
+    private final Object updateLock = new Object();
+    private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
+    private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+    private final Deque<Integer> updateOps = new ArrayDeque<>();
 
-    // Lock for interrupt triggering and clearing
+    // interrupt triggering and clearing
     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
-    private long updateCount;
+    private int pollCount;
 
-    // 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.
-     */
     KQueueSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
-        long fds = IOUtil.makePipe(false);
-        fd0 = (int)(fds >>> 32);
-        fd1 = (int)fds;
+
+        this.kqfd = KQueue.create();
+        this.pollArrayAddress = KQueue.allocatePollArray(MAX_KEVENTS);
+
         try {
-            kqueueWrapper = new KQueueArrayWrapper(fd0, fd1);
-            fdMap = new HashMap<>();
-        } catch (Throwable t) {
-            try {
-                FileDispatcherImpl.closeIntFD(fd0);
-            } catch (IOException ioe0) {
-                t.addSuppressed(ioe0);
-            }
-            try {
-                FileDispatcherImpl.closeIntFD(fd1);
-            } catch (IOException ioe1) {
-                t.addSuppressed(ioe1);
-            }
-            throw t;
+            long fds = IOUtil.makePipe(false);
+            this.fd0 = (int) (fds >>> 32);
+            this.fd1 = (int) fds;
+        } catch (IOException ioe) {
+            KQueue.freePollArray(pollArrayAddress);
+            FileDispatcherImpl.closeIntFD(kqfd);
+            throw ioe;
         }
+
+        // register one end of the socket pair for wakeups
+        KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD);
     }
 
     private void ensureOpen() {
-        if (closed)
+        if (!isOpen())
             throw new ClosedSelectorException();
     }
 
     @Override
-    protected int doSelect(long timeout)
-        throws IOException
-    {
-        ensureOpen();
+    protected int doSelect(long timeout) throws IOException {
+        assert Thread.holdsLock(this);
+
         int numEntries;
+        processUpdateQueue();
         processDeregisterQueue();
         try {
             begin();
-            numEntries = kqueueWrapper.poll(timeout);
+
+            long to = Math.min(timeout, Integer.MAX_VALUE);  // max kqueue timeout
+            boolean timedPoll = (to > 0);
+            do {
+                long startTime = timedPoll ? System.nanoTime() : 0;
+                numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, 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();
         }
@@ -123,39 +144,100 @@
     }
 
     /**
+     * Process new registrations and changes to the interest ops.
+     */
+    private void processUpdateQueue() {
+        assert Thread.holdsLock(this);
+
+        synchronized (updateLock) {
+            SelectionKeyImpl ski;
+
+            // new registrations
+            while ((ski = newKeys.pollFirst()) != null) {
+                if (ski.isValid()) {
+                    SelChImpl ch = ski.channel;
+                    int fd = ch.getFDVal();
+                    SelectionKeyImpl previous = fdToKey.put(fd, ski);
+                    assert previous == null;
+                    assert registeredReadFilter.get(fd) == false;
+                    assert registeredWriteFilter.get(fd) == false;
+                }
+            }
+
+            // changes to interest ops
+            assert updateKeys.size() == updateOps.size();
+            while ((ski = updateKeys.pollFirst()) != null) {
+                int ops = updateOps.pollFirst();
+                int fd = ski.channel.getFDVal();
+                if (ski.isValid() && fdToKey.containsKey(fd)) {
+                    // add or delete interest in read events
+                    if (registeredReadFilter.get(fd)) {
+                        if ((ops & Net.POLLIN) == 0) {
+                            KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
+                            registeredReadFilter.clear(fd);
+                        }
+                    } else if ((ops & Net.POLLIN) != 0) {
+                        KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
+                        registeredReadFilter.set(fd);
+                    }
+
+                    // add or delete interest in write events
+                    if (registeredWriteFilter.get(fd)) {
+                        if ((ops & Net.POLLOUT) == 0) {
+                            KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
+                            registeredWriteFilter.clear(fd);
+                        }
+                    } else if ((ops & Net.POLLOUT) != 0) {
+                        KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
+                        registeredWriteFilter.set(fd);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * 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 numEntries)
-        throws IOException
-    {
+    private int updateSelectedKeys(int numEntries) throws IOException {
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioSelectedKeys());
+
         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++;
+        // filter and so there may be more than one event for a fd. The poll
+        // count is incremented here and compared against the SelectionKey's
+        // "lastPolled" field. This ensures that the ready ops is updated rather
+        // than replaced when a file descriptor is polled by both the read and
+        // write filter.
+        pollCount++;
 
         for (int i = 0; i < numEntries; i++) {
-            int nextFD = kqueueWrapper.getDescriptor(i);
-            if (nextFD == fd0) {
+            long kevent = KQueue.getEvent(pollArrayAddress, i);
+            int fd = KQueue.getDescriptor(kevent);
+            if (fd == fd0) {
                 interrupted = true;
             } else {
-                MapEntry me = fdMap.get(Integer.valueOf(nextFD));
-                if (me != null) {
-                    int rOps = kqueueWrapper.getReventOps(i);
-                    SelectionKeyImpl ski = me.ski;
+                SelectionKeyImpl ski = fdToKey.get(fd);
+                if (ski != null) {
+                    int rOps = 0;
+                    short filter = KQueue.getFilter(kevent);
+                    if (filter == EVFILT_READ) {
+                        rOps |= Net.POLLIN;
+                    } else if (filter == EVFILT_WRITE) {
+                        rOps |= Net.POLLOUT;
+                    }
+
                     if (selectedKeys.contains(ski)) {
-                        // first time this file descriptor has been encountered on this
-                        // update?
-                        if (me.updateCount != updateCount) {
+                        // file descriptor may be polled more than once per poll
+                        if (ski.lastPolled != pollCount) {
                             if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
                                 numKeysUpdated++;
-                                me.updateCount = updateCount;
+                                ski.lastPolled = pollCount;
                             }
                         } else {
                             // ready ops have already been set on this update
@@ -166,7 +248,7 @@
                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                             selectedKeys.add(ski);
                             numKeysUpdated++;
-                            me.updateCount = updateCount;
+                            ski.lastPolled = pollCount;
                         }
                     }
                 }
@@ -181,63 +263,90 @@
 
     @Override
     protected void implClose() throws IOException {
-        if (!closed) {
-            closed = true;
+        assert !isOpen();
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioKeys());
 
-            // prevent further wakeup
-            synchronized (interruptLock) {
-                interruptTriggered = true;
-            }
+        // prevent further wakeup
+        synchronized (interruptLock) {
+            interruptTriggered = true;
+        }
 
-            kqueueWrapper.close();
-            FileDispatcherImpl.closeIntFD(fd0);
-            FileDispatcherImpl.closeIntFD(fd1);
+        FileDispatcherImpl.closeIntFD(kqfd);
+        KQueue.freePollArray(pollArrayAddress);
 
-            // 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();
-            }
+        FileDispatcherImpl.closeIntFD(fd0);
+        FileDispatcherImpl.closeIntFD(fd1);
+
+        // 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();
         }
     }
 
     @Override
     protected void implRegister(SelectionKeyImpl ski) {
+        assert Thread.holdsLock(nioKeys());
         ensureOpen();
-        int fd = IOUtil.fdVal(ski.channel.getFD());
-        fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
+        synchronized (updateLock) {
+            newKeys.addLast(ski);
+        }
         keys.add(ski);
     }
 
     @Override
     protected void implDereg(SelectionKeyImpl ski) throws IOException {
+        assert !ski.isValid();
+        assert Thread.holdsLock(this);
+        assert Thread.holdsLock(nioKeys());
+        assert Thread.holdsLock(nioSelectedKeys());
+
         int fd = ski.channel.getFDVal();
-        fdMap.remove(Integer.valueOf(fd));
-        kqueueWrapper.release(ski.channel);
+        fdToKey.remove(fd);
+        if (registeredReadFilter.get(fd)) {
+            KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
+            registeredReadFilter.clear(fd);
+        }
+        if (registeredWriteFilter.get(fd)) {
+            KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
+            registeredWriteFilter.clear(fd);
+        }
+
+        selectedKeys.remove(ski);
         keys.remove(ski);
-        selectedKeys.remove(ski);
+
+        // remove from channel's key set
         deregister(ski);
+
         SelectableChannel selch = ski.channel();
         if (!selch.isOpen() && !selch.isRegistered())
-            ((SelChImpl)selch).kill();
+            ((SelChImpl) selch).kill();
     }
 
     @Override
     public void putEventOps(SelectionKeyImpl ski, int ops) {
         ensureOpen();
-        kqueueWrapper.setInterest(ski.channel, ops);
+        synchronized (updateLock) {
+            updateOps.addLast(ops);   // ops first in case adding the key fails
+            updateKeys.addLast(ski);
+        }
     }
 
     @Override
     public Selector wakeup() {
         synchronized (interruptLock) {
             if (!interruptTriggered) {
-                kqueueWrapper.interrupt();
+                try {
+                    IOUtil.write1(fd1, (byte)0);
+                } catch (IOException ioe) {
+                    throw new InternalError(ioe);
+                }
                 interruptTriggered = true;
             }
         }
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java	Fri Mar 23 14:18:18 2018 +0000
@@ -23,17 +23,10 @@
  * questions.
  */
 
-/*
- * KQueueSelectorProvider.java
- * Implementation of Selector using FreeBSD / Mac OS X kqueues
- * Derived from Sun's DevPollSelectorProvider
- */
-
 package sun.nio.ch;
 
 import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
+import java.nio.channels.spi.AbstractSelector;
 
 public class KQueueSelectorProvider
     extends SelectorProviderImpl
--- a/src/java.base/macosx/native/libnio/ch/KQueue.c	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/macosx/native/libnio/ch/KQueue.c	Fri Mar 23 14:18:18 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
@@ -23,76 +23,91 @@
  * questions.
  */
 
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "nio_util.h"
-
-#include "sun_nio_ch_KQueue.h"
-
 #include <strings.h>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/time.h>
 
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_KQueue.h"
+
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass this)
+Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass clazz)
 {
     return sizeof(struct kevent);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass this)
+Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass clazz)
 {
     return offsetof(struct kevent, ident);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass this)
+Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass clazz)
 {
     return offsetof(struct kevent, filter);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass this)
+Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass clazz)
 {
     return offsetof(struct kevent, flags);
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_kqueue(JNIEnv *env, jclass c) {
+Java_sun_nio_ch_KQueue_create(JNIEnv *env, jclass clazz) {
     int kqfd = kqueue();
     if (kqfd < 0) {
         JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
+        return IOS_THROWN;
     }
     return kqfd;
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_keventRegister(JNIEnv *env, jclass c, jint kqfd,
-                                      jint fd, jint filter, jint flags)
+Java_sun_nio_ch_KQueue_register(JNIEnv *env, jclass clazz, jint kqfd,
+                                jint fd, jint filter, jint flags)
 
 {
     struct kevent changes[1];
-    struct timespec timeout = {0, 0};
     int res;
 
     EV_SET(&changes[0], fd, filter, flags, 0, 0, 0);
-    RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, &timeout), res);
+    RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, NULL), res);
     return (res == -1) ? errno : 0;
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueue_keventPoll(JNIEnv *env, jclass c,
-                                  jint kqfd, jlong address, jint nevents)
+Java_sun_nio_ch_KQueue_poll(JNIEnv *env, jclass clazz, jint kqfd, jlong address,
+                            jint nevents, jlong timeout)
 {
     struct kevent *events = jlong_to_ptr(address);
     int res;
+    struct timespec ts;
+    struct timespec *tsp;
 
-    RESTARTABLE(kevent(kqfd, NULL, 0, events, nevents, NULL), res);
+    if (timeout >= 0) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = (timeout % 1000) * 1000000;
+        tsp = &ts;
+    } else {
+        tsp = NULL;
+    }
+
+    res = kevent(kqfd, NULL, 0, events, nevents, tsp);
     if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
+            return IOS_THROWN;
+        }
     }
     return res;
 }
--- a/src/java.base/macosx/native/libnio/ch/KQueueArrayWrapper.c	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * KQueueArrayWrapper.c
- * Implementation of Selector using FreeBSD / Mac OS X kqueues
- * Derived from Sun's DevPollArrayWrapper
- */
-
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "nio_util.h"
-
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz)
-{
-#define CHECK_EXCEPTION() { \
-    if ((*env)->ExceptionCheck(env)) { \
-        goto exceptionOccurred; \
-    } \
-}
-
-#define CHECK_ERROR_AND_EXCEPTION(_field) { \
-    if (_field == NULL) { \
-        goto badField; \
-    } \
-    CHECK_EXCEPTION(); \
-}
-
-
-    jfieldID field;
-
-    field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S");
-    CHECK_ERROR_AND_EXCEPTION(field);
-    (*env)->SetStaticShortField(env, clazz, field, EVFILT_READ);
-    CHECK_EXCEPTION();
-
-    field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S");
-    CHECK_ERROR_AND_EXCEPTION(field);
-    (*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE);
-    CHECK_EXCEPTION();
-
-    field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S");
-    CHECK_ERROR_AND_EXCEPTION(field);
-    (*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent));
-    CHECK_EXCEPTION();
-
-    field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S");
-    CHECK_ERROR_AND_EXCEPTION(field);
-    (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident));
-    CHECK_EXCEPTION();
-
-    field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S");
-    CHECK_ERROR_AND_EXCEPTION(field);
-    (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter));
-    CHECK_EXCEPTION();
-    return;
-
-badField:
-    return;
-
-exceptionOccurred:
-    return;
-
-#undef CHECK_EXCEPTION
-#undef CHECK_ERROR_AND_EXCEPTION
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this)
-{
-    int kq = kqueue();
-    if (kq < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed");
-    }
-    return kq;
-}
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this,
-                                             jint kq, jint fd, jint r, jint w)
-{
-    struct kevent changes[2];
-    struct kevent errors[2];
-    struct timespec dontBlock = {0, 0};
-
-    // if (r) then { register for read } else { unregister for read }
-    // if (w) then { register for write } else { unregister for write }
-    // Ignore errors - they're probably complaints about deleting non-
-    //   added filters - but provide an error array anyway because
-    //   kqueue behaves erratically if some of its registrations fail.
-    EV_SET(&changes[0], fd, EVFILT_READ,  r ? EV_ADD : EV_DELETE, 0, 0, 0);
-    EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0);
-    kevent(kq, changes, 2, errors, 2, &dontBlock);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq,
-                                           jlong kevAddr, jint kevCount,
-                                           jlong timeout)
-{
-    struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr);
-    struct timespec ts;
-    struct timespec *tsp;
-    int result;
-
-    // Java timeout is in milliseconds. Convert to struct timespec.
-    // Java timeout == -1 : wait forever : timespec timeout of NULL
-    // Java timeout == 0  : return immediately : timespec timeout of zero
-    if (timeout >= 0) {
-        // For some indeterminate reason kevent(2) has been found to fail with
-        // an EINVAL error for timeout values greater than or equal to
-        // 100000001000L. To avoid this problem, clamp the timeout arbitrarily
-        // to the maximum value of a 32-bit signed integer which is
-        // approximately 25 days in milliseconds.
-        const jlong timeoutMax = 0x7fffffff; // java.lang.Integer.MAX_VALUE
-        if (timeout > timeoutMax) {
-            timeout = timeoutMax;
-        }
-        ts.tv_sec = timeout / 1000;
-        ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec
-        tsp = &ts;
-    } else {
-        tsp = NULL;
-    }
-
-    RESTARTABLE(kevent(kq, NULL, 0, kevs, kevCount, tsp), result);
-    if (result < 0) {
-        JNU_ThrowIOExceptionWithLastError(env,
-            "KQueueArrayWrapper: kevent poll failed");
-    }
-
-    return result;
-}
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd)
-{
-    char c = 1;
-    if (1 != write(fd, &c, 1)) {
-        JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed");
-    }
-}
-
--- a/src/java.base/macosx/native/libnio/ch/KQueuePort.c	Fri Mar 23 09:51:02 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2012, 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
- * under the terms of the GNU General Public License version 2 only, as
- * 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
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "nio_util.h"
-
-#include "sun_nio_ch_KQueuePort.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueuePort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
-    int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
-    } else {
-        jint res[2];
-        res[0] = (jint)sp[0];
-        res[1] = (jint)sp[1];
-        (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueuePort_interrupt(JNIEnv *env, jclass c, jint fd) {
-    int res;
-    int buf[1];
-    buf[0] = 1;
-    RESTARTABLE(write(fd, buf, 1), res);
-    if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "write failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueuePort_drain1(JNIEnv *env, jclass cl, jint fd) {
-    int res;
-    char buf[1];
-    RESTARTABLE(read(fd, buf, 1), res);
-    if (res < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_KQueuePort_close0(JNIEnv *env, jclass c, jint fd) {
-    int res;
-    RESTARTABLE(close(fd), res);
-}
--- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java	Fri Mar 23 14:18:18 2018 +0000
@@ -397,7 +397,9 @@
      * The read end of the pipe is returned in the high 32 bits,
      * while the write end is returned in the low 32 bits.
      */
-    static native long makePipe(boolean blocking);
+    static native long makePipe(boolean blocking) throws IOException;
+
+    static native int write1(int fd, byte b) throws IOException;
 
     static native boolean drain(int fd) throws IOException;
 
--- a/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -33,10 +33,10 @@
 
 
 /**
- * An implementation of SelectionKey for Solaris.
+ * An implementation of SelectionKey.
  */
 
-public class SelectionKeyImpl
+public final class SelectionKeyImpl
     extends AbstractSelectionKey
 {
 
@@ -54,12 +54,14 @@
         selector = sel;
     }
 
+    @Override
     public SelectableChannel channel() {
         return (SelectableChannel)channel;
     }
 
+    @Override
     public Selector selector() {
-        return selector;
+        return (Selector)selector;
     }
 
     int getIndex() {                                    // package-private
@@ -75,16 +77,19 @@
             throw new CancelledKeyException();
     }
 
+    @Override
     public int interestOps() {
         ensureValid();
         return interestOps;
     }
 
+    @Override
     public SelectionKey interestOps(int ops) {
         ensureValid();
         return nioInterestOps(ops);
     }
 
+    @Override
     public int readyOps() {
         ensureValid();
         return readyOps;
@@ -131,4 +136,6 @@
         return sb.toString();
     }
 
+    // used by Selector implementations to record when the key was selected
+    int lastPolled;
 }
--- a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -78,6 +78,16 @@
         return publicSelectedKeys;
     }
 
+    /**
+     * Returns the public view of the key sets
+     */
+    protected final Set<SelectionKey> nioKeys() {
+        return publicKeys;
+    }
+    protected final Set<SelectionKey> nioSelectedKeys() {
+        return publicSelectedKeys;
+    }
+
     protected abstract int doSelect(long timeout) throws IOException;
 
     private int lockAndDoSelect(long timeout) throws IOException {
@@ -125,8 +135,6 @@
 
     protected abstract void implClose() throws IOException;
 
-    public abstract void putEventOps(SelectionKeyImpl sk, int ops);
-
     @Override
     protected final SelectionKey register(AbstractSelectableChannel ch,
                                           int ops,
@@ -166,4 +174,9 @@
             }
         }
     }
+
+    /**
+     * Invoked to change the key's interest set
+     */
+    public abstract void putEventOps(SelectionKeyImpl ski, int ops);
 }
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -210,25 +210,20 @@
 
     @Override
     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
-        acceptLock.lock();
-        try {
-            synchronized (stateLock) {
-                ensureOpen();
-                if (localAddress != null)
-                    throw new AlreadyBoundException();
-                InetSocketAddress isa = (local == null)
-                                        ? new InetSocketAddress(0)
-                                        : Net.checkAddress(local);
-                SecurityManager sm = System.getSecurityManager();
-                if (sm != null)
-                    sm.checkListen(isa.getPort());
-                NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
-                Net.bind(fd, isa.getAddress(), isa.getPort());
-                Net.listen(fd, backlog < 1 ? 50 : backlog);
-                localAddress = Net.localAddress(fd);
-            }
-        } finally {
-            acceptLock.unlock();
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localAddress != null)
+                throw new AlreadyBoundException();
+            InetSocketAddress isa = (local == null)
+                                    ? new InetSocketAddress(0)
+                                    : Net.checkAddress(local);
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkListen(isa.getPort());
+            NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
+            Net.bind(fd, isa.getAddress(), isa.getPort());
+            Net.listen(fd, backlog < 1 ? 50 : backlog);
+            localAddress = Net.localAddress(fd);
         }
         return this;
     }
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Fri Mar 23 14:18:18 2018 +0000
@@ -127,7 +127,7 @@
     // descriptor is registered with /dev/poll.
     private final BitSet registered = new BitSet();
 
-    DevPollArrayWrapper() {
+    DevPollArrayWrapper() throws IOException {
         int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
         pollArray = new AllocatedNativeObject(allocationSize, true);
         pollArrayAddress = pollArray.address();
@@ -136,7 +136,7 @@
             eventsHigh = new HashMap<>();
     }
 
-    void initInterrupt(int fd0, int fd1) {
+    void initInterrupt(int fd0, int fd1) throws IOException {
         outgoingInterruptFD = fd1;
         incomingInterruptFD = fd0;
         register(wfd, fd0, POLLIN);
@@ -200,7 +200,7 @@
         }
     }
 
-    void release(int fd) {
+    void release(int fd) throws IOException {
         synchronized (updateLock) {
             // ignore any pending update for this file descriptor
             setUpdateEvents(fd, IGNORE);
@@ -297,7 +297,11 @@
     boolean interrupted = false;
 
     public void interrupt() {
-        interrupt(outgoingInterruptFD);
+        try {
+            IOUtil.write1(outgoingInterruptFD, (byte)0);
+        } catch (IOException ioe) {
+            throw new InternalError(ioe);
+        }
     }
 
     public int interruptedIndex() {
@@ -312,13 +316,12 @@
         interrupted = false;
     }
 
-    private native int init();
-    private native void register(int wfd, int fd, int mask);
+    private native int init() throws IOException;
+    private native void register(int wfd, int fd, int mask) throws IOException;
     private native void registerMultiple(int wfd, long address, int len)
         throws IOException;
-    private native int poll0(long pollAddress, int numfds, long timeout,
-                             int wfd);
-    private static native void interrupt(int fd);
+    private native int poll0(long pollAddress, int numfds, long timeout, int wfd)
+        throws IOException;
 
     static {
         IOUtil.load();
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -61,7 +61,7 @@
      * Package private constructor called by factory method in
      * the abstract superclass Selector.
      */
-    DevPollSelectorImpl(SelectorProvider sp) {
+    DevPollSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
         long pipeFds = IOUtil.makePipe(false);
         fd0 = (int) (pipeFds >>> 32);
--- a/src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java	Fri Mar 23 14:18:18 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
@@ -181,12 +181,26 @@
         }
 
         // poll for events
-        int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
+        int numEntries;
+        long to = timeout;
+        boolean timedPoll = (to > 0);
+        do {
+            long startTime = timedPoll ? System.currentTimeMillis() : 0;
+            numEntries = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
+            if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
+                // timed poll interrupted so need to adjust timeout
+                to -= System.currentTimeMillis() - startTime;
+                if (to <= 0) {
+                    // timeout also expired so no retry
+                    numEntries = 0;
+                }
+            }
+        } while (numEntries == IOStatus.INTERRUPTED);
 
         // after polling we need to queue all polled file descriptors as they
         // are candidates to register for the next poll.
         synchronized (updateLock) {
-            for (int i=0; i<updated; i++) {
+            for (int i=0; i<numEntries; i++) {
                 if (getSource(i) == PORT_SOURCE_USER) {
                     interrupted = true;
                     setDescriptor(i, -1);
@@ -199,7 +213,7 @@
             }
         }
 
-        return updated;
+        return numEntries;
     }
 
     private void setInterest(int fd) {
--- a/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	Fri Mar 23 14:18:18 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
@@ -164,7 +164,10 @@
                     // A error here is fatal (thread will not be replaced)
                     replaceMe = false;
                     try {
-                        port_get(port, address);
+                        int n;
+                        do {
+                            n = port_get(port, address);
+                        } while (n == IOStatus.INTERRUPTED);
                     } catch (IOException x) {
                         x.printStackTrace();
                         return;
@@ -240,7 +243,7 @@
     /**
      * Retrieves a single event from a port
      */
-    static native void port_get(int port, long pe) throws IOException;
+    static native int port_get(int port, long address) throws IOException;
 
     /**
      * Retrieves at most {@code max} events from a port.
--- a/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	Fri Mar 23 14:18:18 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
@@ -176,14 +176,3 @@
     }
     return result;
 }
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
-{
-    int fakebuf[1];
-    fakebuf[0] = 1;
-    if (write(fd, fakebuf, 1) < 0) {
-        JNU_ThrowIOExceptionWithLastError(env,
-                                          "Write to interrupt fd failed");
-    }
-}
--- a/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, 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
@@ -23,17 +23,18 @@
  * questions.
  */
 
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <port.h>
+
 #include "jni.h"
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
+#include "nio.h"
 #include "nio_util.h"
 
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <sys/types.h>
-#include <port.h>
-
 #include "sun_nio_ch_SolarisEventPort.h"
 
 JNIEXPORT jint JNICALL
@@ -51,8 +52,10 @@
 Java_sun_nio_ch_SolarisEventPort_port_1close
     (JNIEnv* env, jclass clazz, jint port)
 {
-    int res;
-    RESTARTABLE(close(port), res);
+    int res = close(port);
+    if (res < 0 && res != EINTR) {
+        JNU_ThrowIOExceptionWithLastError(env, "close failed");
+    }
 }
 
 JNIEXPORT jboolean JNICALL
@@ -93,17 +96,23 @@
     }
 }
 
-JNIEXPORT void JNICALL
+JNIEXPORT jint JNICALL
 Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz,
     jint port, jlong eventAddress)
 {
     int res;
     port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress);
 
-    RESTARTABLE(port_get((int)port, ev, NULL), res);
+    res = port_get((int)port, ev, NULL);
     if (res == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "port_get");
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "port_get failed");
+            return IOS_THROWN;
+        }
     }
+    return res;
 }
 
 JNIEXPORT jint JNICALL
@@ -125,9 +134,13 @@
     }
 
     res = port_getn((int)port, list, (uint_t)max, &n, tsp);
-    if (res == -1) {
-        if (errno != ETIME && errno != EINTR)
-            JNU_ThrowIOExceptionWithLastError(env, "port_getn");
+    if (res == -1 && errno != ETIME) {
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "port_getn failed");
+            return IOS_THROWN;
+        }
     }
 
     return (jint)n;
--- a/src/java.base/unix/classes/sun/nio/ch/PipeImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/PipeImpl.java	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2010, 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
@@ -38,7 +38,7 @@
     private final SourceChannel source;
     private final SinkChannel sink;
 
-    PipeImpl(SelectorProvider sp) {
+    PipeImpl(SelectorProvider sp) throws IOException {
         long pipeFds = IOUtil.makePipe(true);
         int readFd = (int) (pipeFds >>> 32);
         int writeFd = (int) pipeFds;
--- a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java	Fri Mar 23 14:18:18 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
@@ -51,7 +51,7 @@
      * Package private constructor called by factory method in
      * the abstract superclass Selector.
      */
-    PollSelectorImpl(SelectorProvider sp) {
+    PollSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp, 1, 1);
         long pipeFds = IOUtil.makePipe(false);
         fd0 = (int) (pipeFds >>> 32);
--- a/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, 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,15 +25,15 @@
 
 package sun.nio.ch;
 
-import java.io.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
 
 /**
  * Allows different platforms to call different native methods
  * for read and write operations.
  */
 
-class SocketDispatcher extends NativeDispatcher
-{
+class SocketDispatcher extends NativeDispatcher {
 
     int read(FileDescriptor fd, long address, int len) throws IOException {
         return FileDispatcherImpl.read0(fd, address, len);
--- a/src/java.base/unix/native/libnio/ch/IOUtil.c	Fri Mar 23 09:51:02 2018 +0100
+++ b/src/java.base/unix/native/libnio/ch/IOUtil.c	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, 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
@@ -104,10 +104,19 @@
     return ((jlong) fd[0] << 32) | (jlong) fd[1];
 }
 
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_IOUtil_write1(JNIEnv *env, jclass cl, jint fd, jbyte b)
+{
+    char c = (char)b;
+    return convertReturnVal(env, write(fd, &c, 1), JNI_FALSE);
+}
+
+
 JNIEXPORT jboolean JNICALL
 Java_sun_nio_ch_IOUtil_drain(JNIEnv *env, jclass cl, jint fd)
 {
-    char buf[128];
+    char buf[16];
     int tn = 0;
 
     for (;;) {
--- a/test/jdk/java/nio/channels/Selector/CloseWhenKeyIdle.java	Fri Mar 23 09:51:02 2018 +0100
+++ b/test/jdk/java/nio/channels/Selector/CloseWhenKeyIdle.java	Fri Mar 23 14:18:18 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -62,22 +62,6 @@
 
     public static void main(String[] args) throws Exception {
 
-        // Skip test on pre-2.6 kernels until the poll SelectorProvider
-        // is updated
-        String osname = System.getProperty("os.name");
-        if (osname.equals("Linux")) {
-            String[] ver = System.getProperty("os.version").split("\\.", 0);
-            if (ver.length >=2 ) {
-                int major = Integer.parseInt(ver[0]);
-                int minor = Integer.parseInt(ver[1]);
-                if (major < 2 || (major == 2 && minor < 6)) {
-                    System.out.println("Test passing on pre-2.6 kernel");
-                    return;
-                }
-            }
-        }
-
-
         // establish loopback connection
 
         ServerSocketChannel ssc = ServerSocketChannel.open();