changeset 53281:765ba1379572 fibers

Switch Socket/ServerSocket to use NIO based SocketImpl
author alanb
date Wed, 09 Jan 2019 13:44:43 +0000
parents d106b8016296
children dc44aabf8a69
files src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java src/java.base/share/classes/java/net/ServerSocket.java src/java.base/share/classes/java/net/Socket.java src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java src/java.base/share/classes/sun/nio/ch/SocketStreams.java src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c test/jdk/ProblemList.txt test/jdk/java/lang/Fiber/NetSockets.java
diffstat 10 files changed, 1078 insertions(+), 678 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jan 09 13:44:43 2019 +0000
@@ -38,7 +38,6 @@
 import sun.net.NetHooks;
 import sun.net.ResourceManager;
 import sun.net.util.SocketExceptions;
-import sun.nio.ch.SocketStreams;
 
 /**
  * Default Socket Implementation. This implementation does
@@ -56,7 +55,8 @@
     private boolean shut_rd = false;
     private boolean shut_wr = false;
 
-    private SocketStreams socketStreams;
+    private SocketInputStream socketInputStream = null;
+    private SocketOutputStream socketOutputStream = null;
 
     /* number of threads using the FileDescriptor */
     protected int fdUseCount = 0;
@@ -267,12 +267,7 @@
             int tmp = ((Integer) val).intValue();
             if (tmp < 0)
                 throw new IllegalArgumentException("timeout < 0");
-            synchronized (fdLock) {
-                timeout = tmp;
-                if (socketStreams != null) {
-                    socketStreams.readTimeout(tmp);
-                }
-            }
+            timeout = tmp;
             break;
         case IP_TOS:
              if (val == null || !(val instanceof Integer)) {
@@ -393,31 +388,32 @@
      */
 
     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
-        SocketStreams socketStreams;
         synchronized (fdLock) {
             if (!closePending && (socket == null || !socket.isBound())) {
                 NetHooks.beforeTcpConnect(fd, address, port);
             }
-
-            socketStreams = this.socketStreams;
-            if (socketStreams == null) {
-                this.socketStreams = new SocketStreams(socket, fd, false).readTimeout(timeout);
-                socketStreams = this.socketStreams;
+        }
+        try {
+            acquireFD();
+            try {
+                socketConnect(address, port, timeout);
+                /* socket may have been closed during poll/select */
+                synchronized (fdLock) {
+                    if (closePending) {
+                        throw new SocketException ("Socket closed");
+                    }
+                }
+                // If we have a ref. to the Socket, then sets the flags
+                // created, bound & connected to true.
+                // This is normally done in Socket.connect() but some
+                // subclasses of Socket may call impl.connect() directly!
+                if (socket != null) {
+                    socket.setBound();
+                    socket.setConnected();
+                }
+            } finally {
+                releaseFD();
             }
-        }
-
-        try {
-            socketStreams.connect(address, port, timeout);
-
-            // If we have a ref. to the Socket, then sets the flags
-            // created, bound & connected to true.
-            // This is normally done in Socket.connect() but some
-            // subclasses of Socket may call impl.connect() directly!
-            if (socket != null) {
-                socket.setBound();
-                socket.setConnected();
-            }
-
         } catch (IOException e) {
             close();
             throw SocketExceptions.of(e, new InetSocketAddress(address, port));
@@ -474,14 +470,14 @@
                 throw new IOException("Socket Closed");
             if (shut_rd)
                 throw new IOException("Socket input is shutdown");
-            if (socketStreams == null)
-                socketStreams = new SocketStreams(socket, fd, true).readTimeout(timeout);
-            return socketStreams.inputStream();
+            if (socketInputStream == null)
+                socketInputStream = new SocketInputStream(this);
         }
+        return socketInputStream;
     }
 
     void setInputStream(SocketInputStream in) {
-        throw new UnsupportedOperationException();
+        socketInputStream = in;
     }
 
     /**
@@ -493,10 +489,10 @@
                 throw new IOException("Socket Closed");
             if (shut_wr)
                 throw new IOException("Socket output is shutdown");
-            if (socketStreams == null)
-                socketStreams = new SocketStreams(socket, fd, true).readTimeout(timeout);
-            return socketStreams.outputStream();
+            if (socketOutputStream == null)
+                socketOutputStream = new SocketOutputStream(this);
         }
+        return socketOutputStream;
     }
 
     void setFileDescriptor(FileDescriptor fd) {
@@ -553,25 +549,6 @@
     protected void close() throws IOException {
         synchronized(fdLock) {
             if (fd != null) {
-                if (socketStreams != null) {
-                    try {
-                        SocketCleanable.unregister(fd);
-                        closePending = true;
-                        socketStreams.close();
-                    } finally {
-                        fd = null;
-                    }
-                } else {
-                    // closing not delegate to SocketStreams
-                    localClose();
-                }
-            }
-        }
-    }
-
-    private void localClose() throws IOException {
-        synchronized(fdLock) {
-            if (fd != null) {
                 if (!stream) {
                     ResourceManager.afterUdpClose();
                 }
@@ -625,33 +602,23 @@
      * Shutdown read-half of the socket connection;
      */
     protected void shutdownInput() throws IOException {
-        synchronized (fdLock) {
-            if (fd != null) {
-                if (socketStreams != null) {
-                    socketStreams.shutdownInput();
-                } else {
-                    socketShutdown(SHUT_RD);
-                }
-                shut_rd = true;
-            }
-
-        }
+      if (fd != null) {
+          socketShutdown(SHUT_RD);
+          if (socketInputStream != null) {
+              socketInputStream.setEOF(true);
+          }
+          shut_rd = true;
+      }
     }
 
     /**
      * Shutdown write-half of the socket connection;
      */
     protected void shutdownOutput() throws IOException {
-        synchronized (fdLock) {
-            if (fd != null) {
-                if (socketStreams != null) {
-                    socketStreams.shutdownOutput();
-                } else {
-                    socketShutdown(SHUT_WR);
-                }
-                shut_wr = true;
-            }
-        }
+      if (fd != null) {
+          socketShutdown(SHUT_WR);
+          shut_wr = true;
+      }
     }
 
     protected boolean supportsUrgentData () {
--- a/src/java.base/share/classes/java/net/ServerSocket.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/share/classes/java/net/ServerSocket.java	Wed Jan 09 13:44:43 2019 +0000
@@ -27,6 +27,7 @@
 
 import jdk.internal.access.JavaNetSocketAccess;
 import jdk.internal.access.SharedSecrets;
+import sun.nio.ch.NioSocketImpl;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -296,7 +297,7 @@
         } else {
             // No need to do a checkOldImpl() here, we know it's an up to date
             // SocketImpl!
-            impl = new SocksSocketImpl();
+            impl = new NioSocketImpl();
         }
         if (impl != null)
             impl.setServerSocket(this);
@@ -554,7 +555,9 @@
             si.address = new InetAddress();
             si.fd = new FileDescriptor();
             getImpl().accept(si);
-            SocketCleanable.register(si.fd);   // raw fd has been set
+
+            // FIXME: disable Cleaner for now
+            //SocketCleanable.register(si.fd);   // raw fd has been set
 
             SecurityManager security = System.getSecurityManager();
             if (security != null) {
--- a/src/java.base/share/classes/java/net/Socket.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/share/classes/java/net/Socket.java	Wed Jan 09 13:44:43 2019 +0000
@@ -34,6 +34,7 @@
 import java.security.PrivilegedAction;
 import java.util.Set;
 import java.util.Collections;
+import sun.nio.ch.NioSocketImpl;
 
 /**
  * This class implements client sockets (also called just
@@ -143,7 +144,7 @@
         } else {
             if (p == Proxy.NO_PROXY) {
                 if (factory == null) {
-                    impl = new PlainSocketImpl();
+                    impl = new NioSocketImpl();
                     impl.setSocket(this);
                 } else
                     setImpl();
@@ -502,7 +503,7 @@
         } else {
             // No need to do a checkOldImpl() here, we know it's an up to date
             // SocketImpl!
-            impl = new SocksSocketImpl();
+            impl = new NioSocketImpl();
         }
         if (impl != null)
             impl.setSocket(this);
@@ -907,18 +908,26 @@
             throw new SocketException("Socket is not connected");
         if (isInputShutdown())
             throw new SocketException("Socket input is shutdown");
-        InputStream is = null;
-        try {
-            is = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<>() {
-                    public InputStream run() throws IOException {
-                        return impl.getInputStream();
-                    }
-                });
-        } catch (java.security.PrivilegedActionException e) {
-            throw (IOException) e.getException();
-        }
-        return is;
+        // wrap the input stream so that the close method closes this socket
+        InputStream in = impl.getInputStream();
+        return new InputStream() {
+            @Override
+            public int read() throws IOException {
+                return in.read();
+            }
+            @Override
+            public int read(byte b[], int off, int len) throws IOException {
+                return in.read(b, off, len);
+            }
+            @Override
+            public int available() throws IOException {
+                return in.available();
+            }
+            @Override
+            public void close() throws IOException {
+                Socket.this.close();
+            }
+        };
     }
 
     /**
@@ -946,18 +955,22 @@
             throw new SocketException("Socket is not connected");
         if (isOutputShutdown())
             throw new SocketException("Socket output is shutdown");
-        OutputStream os = null;
-        try {
-            os = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<>() {
-                    public OutputStream run() throws IOException {
-                        return impl.getOutputStream();
-                    }
-                });
-        } catch (java.security.PrivilegedActionException e) {
-            throw (IOException) e.getException();
-        }
-        return os;
+        // wrap the output stream so that the close method closes this socket
+        OutputStream out = impl.getOutputStream();
+        return new OutputStream() {
+            @Override
+            public void write(int b) throws IOException {
+                out.write(b);
+            }
+            @Override
+            public void write(byte b[], int off, int len) throws IOException {
+                out.write(b, off, len);
+            }
+            @Override
+            public void close() throws IOException {
+                Socket.this.close();
+            }
+        };
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Wed Jan 09 13:44:43 2019 +0000
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 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.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import jdk.internal.misc.Strands;
+import sun.net.NetHooks;
+import sun.net.ResourceManager;
+import sun.net.util.SocketExceptions;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+/**
+ * NIO based SocketImpl.
+ *
+ * This implementation attempts to be compatible with legacy PlainSocketImpl,
+ * including throwing exceptions that are not specified by SocketImpl.
+ *
+ * This implementation is not yet integrated with the Cleaner mechanism. It
+ * also does not support extended socket options at this time.
+ */
+
+public class NioSocketImpl extends SocketImpl {
+    private static final NativeDispatcher nd = new SocketDispatcher();
+
+    // Lock held when reading or writing
+    private final ReentrantLock readLock = new ReentrantLock();
+    private final ReentrantLock writeLock = new ReentrantLock();
+
+    // The stateLock is needed when changing state
+    private final Object stateLock = new Object();
+    private static final int ST_NEW = 0;
+    private static final int ST_UNCONNECTED = 1;
+    private static final int ST_CONNECTING = 2;
+    private static final int ST_CONNECTED = 3;
+    private static final int ST_CLOSING = 4;
+    private static final int ST_CLOSED = 5;
+    private volatile int state;  // need stateLock to change
+
+    // protected by stateLock
+    private long readerThread;
+    private long writerThread;
+    private int fdVal;
+    private boolean stream;
+    private int timeout;  // read or accept timeout in millis
+
+    // flags to indicate if the connection is shutdown for input and output
+    private volatile boolean isInputClosed;
+    private volatile boolean isOutputClosed;
+
+    /**
+     * Creates a instance of this SocketImpl
+     */
+    public NioSocketImpl() { }
+
+    /**
+     * Returns true if the socket is open.
+     */
+    private boolean isOpen() {
+        return state < ST_CLOSING;
+    }
+
+    /**
+     * Closes a SocketException if the socket is not open.
+     */
+    private void ensureOpen() throws SocketException {
+        if (state >= ST_CLOSING)
+            throw new SocketException("Socket closed");
+    }
+
+    /**
+     * Closes a SocketException if the socket is not open and connected.
+     */
+    private void ensureOpenAndConnected() throws SocketException {
+        int state = this.state;
+        if (state < ST_CONNECTED)
+            throw new SocketException("not connected");
+        if (state > ST_CONNECTED)
+            throw new SocketException("socket closed");
+    }
+
+    /**
+     * Disables the current thread or fiber for scheduling purposes until this
+     * socket is ready for I/O, or asynchronously closed, for up to the
+     * specified waiting time, unless the permit is available.
+     */
+    private void park(int event, long nanos) throws IOException {
+        Object strand = Strands.currentStrand();
+        if (PollerProvider.available() && (strand instanceof Fiber)) {
+            Poller.register(strand, fdVal, event);
+            if (isOpen()) {
+                try {
+                    if (Fiber.cancelled()) {
+                        // throw SocketException for now
+                        throw new SocketException("I/O operation cancelled");
+                    }
+                    if (nanos == 0) {
+                        Strands.parkFiber();
+                    } else {
+                        Strands.parkFiber(nanos);
+                    }
+                    if (Fiber.cancelled()) {
+                        // throw SocketException for now
+                        throw new SocketException("I/O operation cancelled");
+                    }
+                } finally{
+                    Poller.deregister(strand, fdVal, event);
+                }
+            }
+        } else {
+            long millis;
+            if (nanos == 0) {
+                millis = -1;
+            } else {
+                millis = MILLISECONDS.convert(nanos, NANOSECONDS);
+            }
+            Net.poll(fd, event, millis);
+        }
+    }
+
+    /**
+     * Marks the beginning of a read operation that might block.
+     * @throws SocketException if the socket is closed or not connected
+     */
+    private void beginRead() throws SocketException {
+        synchronized (stateLock) {
+            ensureOpenAndConnected();
+            readerThread = NativeThread.current();
+        }
+    }
+
+    /**
+     * Marks the end of a read operation that may have blocked.
+     * @throws SocketException is the socket is closed
+     */
+    private void endRead(boolean completed) throws SocketException {
+        synchronized (stateLock) {
+            readerThread = 0;
+            int state = this.state;
+            if (state == ST_CLOSING)
+                stateLock.notifyAll();
+            if (!completed && state >= ST_CLOSING)
+                throw new SocketException("Socket closed");
+        }
+    }
+
+    /**
+     * Reads bytes from the socket into the given buffer.
+     * @throws IOException if the socket is closed or an I/O occurs
+     * @throws SocketTimeoutException if the read timeout elapses
+     */
+    private int read(ByteBuffer dst) throws IOException {
+        readLock.lock();
+        try {
+            int n = 0;
+            beginRead();
+            try {
+                if (isInputClosed)
+                    return IOStatus.EOF;
+                n = IOUtil.read(fd, dst, -1, nd);
+                if (n == IOStatus.UNAVAILABLE && isOpen()) {
+                    long nanos = NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
+                    if (nanos > 0) {
+                        // read with timeout
+                        do {
+                            long startTime = System.nanoTime();
+                            park(Net.POLLIN, nanos);
+                            n = IOUtil.read(fd, dst, -1, nd);
+                            if (n == IOStatus.UNAVAILABLE) {
+                                nanos -= System.nanoTime() - startTime;
+                                if (nanos <= 0)
+                                    throw new SocketTimeoutException();
+                            }
+                        } while (n == IOStatus.UNAVAILABLE && isOpen());
+                    } else {
+                        // read, no timeout
+                        do {
+                            park(Net.POLLIN, 0);
+                            n = IOUtil.read(fd, dst, -1, nd);
+                        } while (n == IOStatus.UNAVAILABLE && isOpen());
+                    }
+                }
+                return n;
+            } finally {
+                endRead(n > 0);
+            }
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Marks the beginning of a write operation that might block.
+     * @throws SocketException if the socket is closed or not connected
+     */
+    private void beginWrite() throws SocketException {
+        synchronized (stateLock) {
+            ensureOpenAndConnected();
+            writerThread = NativeThread.current();
+        }
+    }
+
+    /**
+     * Marks the end of a write operation that may have blocked.
+     * @throws SocketException is the socket is closed
+     */
+    private void endWrite(boolean completed) throws SocketException {
+        synchronized (stateLock) {
+            writerThread = 0;
+            int state = this.state;
+            if (state == ST_CLOSING)
+                stateLock.notifyAll();
+            if (!completed && state >= ST_CLOSING)
+                throw new SocketException("Socket closed");
+        }
+    }
+
+    /**
+     * Writes a sequence of bytes to this socket from the given buffer.
+     * @throws IOException if the socket is closed or an I/O occurs
+     */
+    private int write(ByteBuffer dst) throws IOException {
+        writeLock.lock();
+        try {
+            int n = 0;
+            beginWrite();
+            try {
+                n = IOUtil.write(fd, dst, -1, nd);
+                while (n == IOStatus.UNAVAILABLE && isOpen()) {
+                    park(Net.POLLOUT, 0);
+                    n = IOUtil.write(fd, dst, -1, nd);
+                }
+                return n;
+            } finally {
+                endWrite(n > 0);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Creates the socket.
+     * @param stream {@code true} for a streams socket
+     */
+    @Override
+    protected void create(boolean stream) throws IOException {
+        synchronized (stateLock) {
+            assert state == ST_NEW;
+            if (!stream)
+                ResourceManager.beforeUdpCreate();
+            FileDescriptor fd = null;
+            try {
+                fd = Net.socket(stream);
+                IOUtil.configureBlocking(fd, false);
+            } catch (IOException ioe) {
+                if (!stream)
+                    ResourceManager.afterUdpClose();
+                if (fd != null)
+                    nd.close(fd);
+                throw ioe;
+            }
+            this.fd = fd;
+            this.fdVal = IOUtil.fdVal(fd);
+            this.stream = stream;
+            this.state = ST_UNCONNECTED;
+        }
+    }
+
+    /**
+     * Marks the beginning of a connect operation that might block.
+     * @throws SocketException if the socket is closed or already connected
+     */
+    private void beginConnect(InetAddress address, int port) throws IOException {
+        synchronized (stateLock) {
+            int state = this.state;
+            if (state >= ST_CLOSING)
+                throw new SocketException("Socket closed");
+            if (state != ST_UNCONNECTED)
+                throw new SocketException("Already connected");
+            this.state = ST_CONNECTING;
+
+            // invoke beforeTcpConnect hook if not already bound
+            if (localport == 0) {
+                NetHooks.beforeTcpConnect(fd, address, port);
+            }
+
+            // save the remote address/port
+            this.address = address;
+            this.port = port;
+
+            readerThread = NativeThread.current();
+        }
+    }
+
+    /**
+     * Marks the end of a connect operation that may have blocked.
+     * @throws SocketException is the socket is closed
+     */
+    private void endConnect(boolean completed) throws IOException {
+        synchronized (stateLock) {
+            readerThread = 0;
+            int state = this.state;
+            if (state == ST_CLOSING)
+                stateLock.notifyAll();
+            if (completed && state == ST_CONNECTING) {
+                this.state = ST_CONNECTED;
+                localport = Net.localAddress(fd).getPort();
+            } else if (!completed && state >= ST_CLOSING) {
+                throw new SocketException("Socket closed");
+            }
+        }
+    }
+
+    /**
+     * Connect the socket. Closes the socket if connection cannot be established.
+     * @throws IllegalArgumentException if the address is not an InetSocketAddress
+     * @throws UnknownHostException if the InetSocketAddress is not resolved
+     * @throws IOException if the connection cannot be established
+     */
+    private void implConnect(SocketAddress remote, long millis) throws IOException {
+        if (!(remote instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress isa = (InetSocketAddress) remote;
+        if (isa.isUnresolved()) {
+            throw new UnknownHostException(isa.getHostName());
+        }
+
+        InetAddress address = isa.getAddress();
+        if (address.isAnyLocalAddress())
+            address = InetAddress.getLocalHost();
+        int port = isa.getPort();
+
+        try {
+            readLock.lock();
+            try {
+                writeLock.lock();
+                try {
+                    boolean connected = false;
+                    try {
+                        beginConnect(address, port);
+                        int n = Net.connect(fd, address, port);
+                        if (n == IOStatus.UNAVAILABLE && isOpen()) {
+                            long nanos = NANOSECONDS.convert(millis, MILLISECONDS);
+                            if (nanos > 0) {
+                                // connect with timeout
+                                do {
+                                    long startTime = System.nanoTime();
+                                    park(Net.POLLOUT, nanos);
+                                    n = SocketChannelImpl.checkConnect(fd, false);
+                                    if (n == IOStatus.UNAVAILABLE) {
+                                        nanos -= System.nanoTime() - startTime;
+                                        if (nanos <= 0)
+                                            throw new SocketTimeoutException();
+                                    }
+                                } while (n == IOStatus.UNAVAILABLE && isOpen());
+                            } else {
+                                // connect, no timeout
+                                do {
+                                    park(Net.POLLOUT, 0);
+                                    n = SocketChannelImpl.checkConnect(fd, false);
+                                } while (n == IOStatus.UNAVAILABLE && isOpen());
+                            }
+                        }
+                        connected = (n > 0) && isOpen();
+                    } finally {
+                        endConnect(connected);
+                    }
+                } finally {
+                    writeLock.unlock();
+                }
+            } finally {
+                readLock.unlock();
+            }
+        } catch (IOException ioe) {
+            close();
+            throw SocketExceptions.of(ioe, isa);
+        }
+    }
+
+    @Override
+    protected void connect(String host, int port) throws IOException {
+        implConnect(new InetSocketAddress(host, port), timeout);
+    }
+
+    @Override
+    protected void connect(InetAddress address, int port) throws IOException {
+        implConnect(new InetSocketAddress(address, port), timeout);
+    }
+
+    @Override
+    protected void connect(SocketAddress address, int timeout) throws IOException {
+        implConnect(address, timeout);
+    }
+
+    @Override
+    protected void bind(InetAddress host, int port) throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localport != 0)
+                throw new SocketException("Already bound");
+            NetHooks.beforeTcpBind(fd, host, port);
+            Net.bind(fd, host, port);
+            InetSocketAddress localAddress = Net.localAddress(fd);
+
+            address = localAddress.getAddress(); // needed by ServerSocket
+            localport = localAddress.getPort();
+        }
+    }
+
+    @Override
+    protected void listen(int backlog) throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localport == 0)
+                throw new SocketException("Not bound");
+            Net.listen(fd, backlog < 1 ? 50 : backlog);
+        }
+    }
+
+    /**
+     * Marks the beginning of an accept operation that might block.
+     * @throws SocketException if the socket is closed
+     */
+    private void beginAccept() throws  SocketException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localport == 0)
+                throw new SocketException("Not bound");
+            readerThread = NativeThread.current();
+        }
+    }
+
+    /**
+     * Marks the end of an accept operation that may have blocked.
+     * @throws SocketException is the socket is closed
+     */
+    private void endAccept(boolean completed) throws SocketException {
+        synchronized (stateLock) {
+            int state = this.state;
+            readerThread = 0;
+            if (state == ST_CLOSING)
+                stateLock.notifyAll();
+            if (!completed && state >= ST_CLOSING)
+                throw new SocketException("Socket closed");
+        }
+    }
+
+    @Override
+    protected void accept(SocketImpl obj) throws IOException {
+        if (!(obj instanceof NioSocketImpl))
+            throw new UnsupportedOperationException("SocketImpl type not supported");
+        NioSocketImpl si = (NioSocketImpl) obj;
+
+        readLock.lock();
+        try {
+            InetSocketAddress[] isaa = new InetSocketAddress[1];
+
+            int n = 0;
+            try {
+                beginAccept();
+                n = ServerSocketChannelImpl.accept0(this.fd, si.fd, isaa);
+                if (n == IOStatus.UNAVAILABLE && isOpen()) {
+                    long nanos = NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
+                    if (nanos > 0) {
+                        // accept with timeout
+                        do {
+                            long startTime = System.nanoTime();
+                            park(Net.POLLIN, nanos);
+                            n = ServerSocketChannelImpl.accept0(this.fd, si.fd, isaa);
+                            if (n == IOStatus.UNAVAILABLE) {
+                                nanos -= System.nanoTime() - startTime;
+                                if (nanos <= 0)
+                                    throw new SocketTimeoutException();
+                            }
+                        } while (n == IOStatus.UNAVAILABLE && isOpen());
+                    } else {
+                        // accept, no timeout
+                        do {
+                            park(Net.POLLIN, 0);
+                            n = ServerSocketChannelImpl.accept0(this.fd, si.fd, isaa);
+                        } while (n == IOStatus.UNAVAILABLE && isOpen());
+                    }
+                }
+            } finally {
+                endAccept(n > 0);
+                assert IOStatus.check(n);
+            }
+
+            // set fields in SocketImpl
+            synchronized (si.stateLock) {
+                assert si.state == ST_NEW;
+                try {
+                    IOUtil.configureBlocking(si.fd, false);
+                } catch (IOException ioe) {
+                    nd.close(si.fd);
+                    throw ioe;
+                }
+                si.fdVal = IOUtil.fdVal(si.fd);
+                si.localport = Net.localAddress(si.fd).getPort();
+                si.address = isaa[0].getAddress();
+                si.port = isaa[0].getPort();
+                si.state = ST_CONNECTED;
+            }
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    protected InputStream getInputStream() throws IOException {
+        return new InputStream() {
+            private volatile boolean eof;
+            @Override
+            public int read() throws IOException {
+                byte[] a = new byte[1];
+                int n = read(a, 0, 1);
+                return (n > 0) ? (a[0] & 0xff) : -1;
+            }
+            @Override
+            public int read(byte b[], int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, b.length);
+                if (eof) {
+                    return -1; // legacy SocketInputStream behavior
+                } else if (len == 0) {
+                    return 0;
+                } else {
+                    ByteBuffer dst = ByteBuffer.wrap(b, off, len);
+                    int n = NioSocketImpl.this.read(dst);
+                    if (n == -1)
+                        eof = true;
+                    return n;
+                }
+            }
+            @Override
+            public int available() throws IOException {
+                return NioSocketImpl.this.available();
+            }
+            @Override
+            public void close() throws IOException {
+                NioSocketImpl.this.close();
+            }
+        };
+    }
+
+    @Override
+    protected OutputStream getOutputStream() throws IOException {
+        return new OutputStream() {
+            @Override
+            public void write(int b) throws IOException {
+                byte[] a = new byte[] { (byte) b };
+                write(a, 0, 1);
+            }
+            @Override
+            public void write(byte b[], int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, b.length);
+                if (len > 0) {
+                    ByteBuffer src = ByteBuffer.wrap(b, off, len);
+                    while (src.hasRemaining()) {
+                        NioSocketImpl.this.write(src);
+                    }
+                }
+            }
+            @Override
+            public void close() throws IOException {
+                NioSocketImpl.this.close();
+            }
+        };
+    }
+
+    @Override
+    protected int available() throws IOException {
+        readLock.lock();
+        try {
+            ensureOpenAndConnected();
+            if (isInputClosed) {
+                return 0;
+            } else {
+                return Net.available(fd);
+            }
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Closes the socket, signalling and waiting for blocking I/O operations
+     * to complete. If invoked on a fiber then it pins the carrier thread until
+     * blocking I/O operations have completed.
+     */
+    @Override
+    protected void close() throws IOException {
+        boolean interrupted = false;
+
+        synchronized (stateLock) {
+            if (state > ST_CONNECTED)
+                return;
+            state = ST_CLOSING;
+
+            // unpark and wait for fibers to complete I/O operations
+            if (NativeThread.isFiber(readerThread) ||
+                    NativeThread.isFiber(writerThread)) {
+                Poller.stopPoll(fdVal);
+
+                while (NativeThread.isFiber(readerThread) ||
+                        NativeThread.isFiber(writerThread)) {
+                    try {
+                        stateLock.wait();
+                    } catch (InterruptedException e) {
+                        interrupted = true;
+                    }
+                }
+            }
+
+            // interrupt and wait for kernel threads to complete I/O operations
+            long reader = readerThread;
+            long writer = writerThread;
+            if (NativeThread.isKernelThread(reader) ||
+                    NativeThread.isKernelThread(writer)) {
+                nd.preClose(fd);
+
+                if (NativeThread.isKernelThread(reader))
+                    NativeThread.signal(reader);
+                if (NativeThread.isKernelThread(writer))
+                    NativeThread.signal(writer);
+
+                // wait for blocking I/O operations to end
+                while (NativeThread.isKernelThread(readerThread) ||
+                        NativeThread.isKernelThread(writerThread)) {
+                    try {
+                        stateLock.wait();
+                    } catch (InterruptedException e) {
+                        interrupted = true;
+                    }
+                }
+            }
+
+            state = ST_CLOSED;
+            try {
+                nd.close(fd);
+            } finally {
+                if (!stream)
+                    ResourceManager.afterUdpClose();
+            }
+        }
+
+        // restore interrupt status
+        if (interrupted)
+            Thread.currentThread().interrupt();
+    }
+
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        if (Net.isReusePortAvailable()) {
+            Set<SocketOption<?>> options = new HashSet<>();
+            options.addAll(super.supportedOptions());
+            options.add(StandardSocketOptions.SO_REUSEPORT);
+            return Collections.unmodifiableSet(options);
+        } else {
+            return super.supportedOptions();
+        }
+    }
+
+    private boolean booleanValue(Object value, String desc) throws SocketException {
+        if (!(value instanceof Boolean))
+            throw new SocketException("Bad value for " + desc);
+        return (boolean) value;
+    }
+
+    private int intValue(Object value, String desc) throws SocketException {
+        if (!(value instanceof Integer))
+            throw new SocketException("Bad value for " + desc);
+        return (int) value;
+    }
+
+    @Override
+    public void setOption(int name, Object value) throws SocketException {
+        synchronized (stateLock) {
+            ensureOpen();
+            try {
+                switch (name) {
+                case SO_LINGER: {
+                    if (!(value instanceof Integer) && !(value instanceof Boolean))
+                        throw new SocketException("Bad value for SO_LINGER");
+                    int i = 0;
+                    if (value instanceof Integer) {
+                        i = ((Integer) value).intValue();
+                        if (i < 0)
+                            i = Integer.valueOf(-1);
+                        if (i > 65535)
+                            i = Integer.valueOf(65535);
+                    }
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_LINGER, i);
+                    break;
+                }
+                case SO_TIMEOUT: {
+                    int i = intValue(value, "SO_TIMEOUT");
+                    if (i < 0)
+                        throw new IllegalArgumentException("timeout < 0");
+                    timeout = i;
+                    break;
+                }
+                case IP_TOS: {
+                    int i = intValue(value, "IP_TOS");
+                    if (i < 0 || i > 255)
+                        throw new IllegalArgumentException("Invalid IP_TOS value");
+                    ProtocolFamily family = Net.isIPv6Available() ?
+                        StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+                    Net.setSocketOption(fd, family, StandardSocketOptions.IP_TOS, i);
+                    break;
+                }
+                case TCP_NODELAY: {
+                    boolean b = booleanValue(value, "TCP_NODELAY");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.TCP_NODELAY, b);
+                    break;
+                }
+                case SO_SNDBUF: {
+                    int i = intValue(value, "SO_SNDBUF");
+                    if (i < 0)
+                        throw new SocketException("bad parameter for SO_SNDBUF");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_SNDBUF, i);
+                    break;
+                }
+                case SO_RCVBUF: {
+                    int i = intValue(value, "SO_RCVBUF");
+                    if (i < 0)
+                        throw new SocketException("bad parameter for SO_RCVBUF");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_RCVBUF, i);
+                    break;
+                }
+                case SO_KEEPALIVE: {
+                    boolean b = booleanValue(value, "SO_KEEPALIVE");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_KEEPALIVE, b);
+                    break;
+                }
+                case SO_OOBINLINE: {
+                    boolean b = booleanValue(value, "SO_OOBINLINE");
+                    Net.setSocketOption(fd, Net.UNSPEC, ExtendedSocketOption.SO_OOBINLINE, b);
+                    break;
+                }
+                case SO_REUSEADDR: {
+                    boolean b = booleanValue(value, "SO_REUSEADDR");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR, b);
+                    break;
+                }
+                case SO_REUSEPORT: {
+                    if (!Net.isReusePortAvailable())
+                        throw new UnsupportedOperationException("SO_REUSEPORT not supported");
+                    boolean b = booleanValue(value, "SO_REUSEPORT");
+                    Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEPORT, b);
+                    break;
+                }
+                default:
+                    throw new SocketException("Unknown option " + name);
+                }
+            } catch (IOException ioe) {
+                throw new SocketException(ioe.getMessage());
+            }
+        }
+    }
+
+    @Override
+    public Object getOption(int name) throws SocketException {
+        synchronized (stateLock) {
+            ensureOpen();
+            try {
+                switch (name) {
+                case SO_TIMEOUT:
+                    return timeout;
+                case TCP_NODELAY:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.TCP_NODELAY);
+                case SO_OOBINLINE:
+                    return Net.getSocketOption(fd, Net.UNSPEC, ExtendedSocketOption.SO_OOBINLINE);
+                case SO_LINGER:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_LINGER);
+                case SO_REUSEADDR:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR);
+                case SO_BINDADDR:
+                    return Net.localAddress(fd).getAddress();
+                case SO_SNDBUF:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_SNDBUF);
+                case SO_RCVBUF:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_RCVBUF);
+                case IP_TOS:
+                    ProtocolFamily family = Net.isIPv6Available() ?
+                            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+                    return Net.getSocketOption(fd, family, StandardSocketOptions.IP_TOS);
+                case SO_KEEPALIVE:
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_KEEPALIVE);
+                case SO_REUSEPORT:
+                    if (!Net.isReusePortAvailable())
+                        throw new UnsupportedOperationException("SO_REUSEPORT not supported");
+                    return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEPORT);
+                default:
+                    throw new SocketException("Unknown option " + name);
+                }
+            } catch (IOException ioe) {
+                throw new SocketException(ioe.getMessage());
+            }
+        }
+    }
+
+    @Override
+    protected void shutdownInput() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (!isInputClosed) {
+                Net.shutdown(fd, Net.SHUT_RD);
+                long reader = readerThread;
+                if (NativeThread.isFiber(reader)) {
+                    Poller.stopPoll(fdVal, Net.POLLIN);
+                } else if (NativeThread.isKernelThread(reader)) {
+                    NativeThread.signal(reader);
+                }
+                isInputClosed = true;
+            }
+        }
+    }
+
+    @Override
+    protected void shutdownOutput() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (!isOutputClosed) {
+                Net.shutdown(fd, Net.SHUT_WR);
+                long writer = writerThread;
+                if (NativeThread.isFiber(writer)) {
+                    Poller.stopPoll(fdVal, Net.POLLOUT);
+                } else if (NativeThread.isKernelThread(writer)) {
+                    NativeThread.signal(writer);
+                }
+                isOutputClosed = true;
+            }
+        }
+    }
+
+    @Override
+    protected boolean supportsUrgentData() {
+        return true;
+    }
+
+    @Override
+    protected void sendUrgentData(int data) throws IOException {
+        writeLock.lock();
+        try {
+            int n = 0;
+            try {
+                beginWrite();
+                n = SocketChannelImpl.sendOutOfBandData(fd, (byte) data);
+                if (n == IOStatus.UNAVAILABLE) {
+                    throw new RuntimeException("not implemented");
+                }
+            } finally {
+                endWrite(n > 0);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+}
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Wed Jan 09 13:44:43 2019 +0000
@@ -557,9 +557,9 @@
     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
     // connections are pending) or IOStatus.INTERRUPTED.
     //
-    private native int accept0(FileDescriptor ssfd,
-                               FileDescriptor newfd,
-                               InetSocketAddress[] isaa)
+    static native int accept0(FileDescriptor ssfd,
+                              FileDescriptor newfd,
+                              InetSocketAddress[] isaa)
         throws IOException;
 
     private static native void initIDs();
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Jan 09 13:44:43 2019 +0000
@@ -1180,7 +1180,7 @@
     static native int checkConnect(FileDescriptor fd, boolean block)
         throws IOException;
 
-    private static native int sendOutOfBandData(FileDescriptor fd, byte data)
+    static native int sendOutOfBandData(FileDescriptor fd, byte data)
         throws IOException;
 
     static {
--- a/src/java.base/share/classes/sun/nio/ch/SocketStreams.java	Tue Jan 08 14:54:18 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,570 +0,0 @@
-/*
- * Copyright (c) 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.Closeable;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.nio.ByteBuffer;
-import java.util.Objects;
-import java.util.concurrent.locks.ReentrantLock;
-
-import jdk.internal.misc.Strands;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-/**
- * Wraps a file descriptor to a TCP socket and provides methods to obtain input
- * and output streams to read/write from the socket.
- */
-
-public class SocketStreams implements Closeable {
-    private static final NativeDispatcher nd = new SocketDispatcher();
-
-    private final Closeable parent;
-    private final FileDescriptor fd;
-    private final int fdVal;
-
-    // Lock held when reading or writing
-    private final ReentrantLock readLock = new ReentrantLock();
-    private final ReentrantLock writeLock = new ReentrantLock();
-
-    // The stateLock is needed when changing state
-    private final Object stateLock = new Object();
-    private static final int ST_UNCONNECTED = 0;
-    private static final int ST_CONNECTING = 1;
-    private static final int ST_CONNECTED = 2;
-    private static final int ST_CLOSING = 3;
-    private static final int ST_CLOSED = 4;
-    private volatile int state;  // need stateLock to change
-
-    // protected by stateLock
-    private long readerThread;
-    private long writerThread;
-
-    // flags to indicate if the connection is shutdown for input and output
-    private volatile boolean isInputClosed;
-    private volatile boolean isOutputClosed;
-
-    // the read timeout
-    private volatile long readTimeoutNanos;
-
-    /**
-     * Creates a SocketStreams to wrap the given file description.
-     */
-    public SocketStreams(Closeable parent,
-                         FileDescriptor fd,
-                         boolean connected) throws IOException {
-        this.parent = Objects.requireNonNull(parent);
-        this.fd = fd;
-        this.fdVal = IOUtil.fdVal(fd);
-        if (connected) {
-            synchronized (stateLock) {
-                this.state = ST_CONNECTED;
-            }
-        }
-        IOUtil.configureBlocking(fd, false);
-    }
-
-    /**
-     * Returns true if the socket is open.
-     */
-    private boolean isOpen() {
-        return state < ST_CLOSING;
-    }
-
-    /**
-     * Closes a SocketException if the socket is not open.
-     */
-    private void ensureOpen() throws SocketException {
-        if (state >= ST_CLOSED)
-            throw new SocketException("socket closed");
-    }
-
-    /**
-     * Closes a SocketException if the socket is not open and connected.
-     */
-    private void ensureOpenAndConnected() throws SocketException {
-        int state = this.state;
-        if (state < ST_CONNECTED) {
-            throw new SocketException("not connected");
-        } else if (state > ST_CONNECTED) {
-            throw new SocketException("socket closed");
-        }
-    }
-
-    /**
-     * Disables the current thread or fiber for scheduling purposes until this
-     * socket is ready for I/O, or asynchronously closed, for up to the
-     * specified waiting time, unless the permit is available.
-     */
-    private void park(int event, long nanos) throws IOException {
-        Object strand = Strands.currentStrand();
-        if (PollerProvider.available() && (strand instanceof Fiber)) {
-            Poller.register(strand, fdVal, event);
-            if (isOpen()) {
-                try {
-                    if (Fiber.cancelled()) {
-                        // throw IOException for now
-                        throw new SocketException("I/O operation cancelled");
-                    }
-                    if (nanos == 0) {
-                        Strands.parkFiber();
-                    } else {
-                        Strands.parkFiber(nanos);
-                    }
-                    if (Fiber.cancelled()) {
-                        // throw IOException for now
-                        throw new SocketException("I/O operation cancelled");
-                    }
-                } finally{
-                    Poller.deregister(strand, fdVal, event);
-                }
-            }
-        } else {
-            long millis;
-            if (nanos == 0) {
-                millis = -1;
-            } else {
-                millis = MILLISECONDS.convert(nanos, NANOSECONDS);
-            }
-            Net.poll(fd, event, millis);
-        }
-    }
-
-    /**
-     * Marks the beginning of a connect operation that might block.
-     *
-     * @throws SocketException if the socket is closed or already conneced
-     */
-    private void beginConnect() throws IOException {
-        synchronized (stateLock) {
-            int state = this.state;
-            if (state > ST_CONNECTED) {
-                throw new SocketException("socket closed");
-            } else if (state != ST_UNCONNECTED) {
-                throw new SocketException("already connected");
-            }
-            this.state = ST_CONNECTING;
-            readerThread = NativeThread.current();
-        }
-    }
-
-    /**
-     * Marks the end of a connect operation that may have blocked.
-     *
-     * @throws SocketException is the socket is closed
-     */
-    private void endConnect(boolean completed) throws IOException {
-        synchronized (stateLock) {
-            readerThread = 0;
-            int state = this.state;
-            if (state == ST_CLOSING)
-                stateLock.notifyAll();
-            if (completed && state == ST_CONNECTING) {
-                this.state = ST_CONNECTED;
-            } else if (!completed && state >= ST_CLOSING) {
-                throw new SocketException("socket closed");
-            }
-        }
-    }
-
-    /**
-     * Marks the beginning of a read operation that might block.
-     *
-     * @throws SocketException if the socket is closed or not connected
-     */
-    private void beginRead() throws SocketException {
-        synchronized (stateLock) {
-            ensureOpenAndConnected();
-            readerThread = NativeThread.current();
-        }
-    }
-
-    /**
-     * Marks the end of a read operation that may have blocked.
-     *
-     * @throws SocketException is the socket is closed
-     */
-    private void endRead(boolean completed) throws SocketException {
-        synchronized (stateLock) {
-            readerThread = 0;
-            int state = this.state;
-            if (state == ST_CLOSING)
-                stateLock.notifyAll();
-            if (!completed && state > ST_CONNECTED)
-                throw new SocketException("socket closed");
-        }
-    }
-
-    /**
-     * Marks the beginning of a write operation that might block.
-     *
-     * @throws SocketException if the socket is closed or not connected
-     */
-    private void beginWrite() throws SocketException {
-        synchronized (stateLock) {
-            ensureOpenAndConnected();
-            writerThread = NativeThread.current();
-        }
-    }
-
-    /**
-     * Marks the end of a write operation that may have blocked.
-     *
-     * @throws SocketException is the socket is closed
-     */
-    private void endWrite(boolean completed) throws SocketException {
-        synchronized (stateLock) {
-            writerThread = 0;
-            int state = this.state;
-            if (state == ST_CLOSING)
-                stateLock.notifyAll();
-            if (!completed && state > ST_CONNECTED)
-                throw new SocketException("socket closed");
-        }
-    }
-
-    /**
-     * Connect the socket to the given address/port.
-     *
-     * @throws IOException if the socket is closed or an I/O occurs
-     * @throws SocketTimeoutException if the connect timeout elapses
-     */
-    public void connect(InetAddress address, int port, long millis) throws IOException {
-        readLock.lock();
-        try {
-            writeLock.lock();
-            try {
-                boolean connected = false;
-                try {
-                    beginConnect();
-                    int n = Net.connect(fd, address, port);
-                    if (n == IOStatus.UNAVAILABLE && isOpen()) {
-                        long nanos = NANOSECONDS.convert(millis, MILLISECONDS);
-                        if (nanos > 0) {
-                            // connect with timeout
-                            do {
-                                long startTime = System.nanoTime();
-                                park(Net.POLLOUT, nanos);
-                                n = SocketChannelImpl.checkConnect(fd, false);
-                                if (n == IOStatus.UNAVAILABLE) {
-                                    nanos -= System.nanoTime() - startTime;
-                                    if (nanos <= 0)
-                                        throw new SocketTimeoutException();
-                                }
-                            } while (n == IOStatus.UNAVAILABLE && isOpen());
-                        } else {
-                            // connect, no timeout
-                            do {
-                                park(Net.POLLOUT, 0);
-                                n = SocketChannelImpl.checkConnect(fd, false);
-                            } while (n == IOStatus.UNAVAILABLE && isOpen());
-                        }
-                    }
-                    connected = (n > 0) && isOpen();
-                } finally {
-                    endConnect(connected);
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        } finally {
-            readLock.unlock();
-        }
-    }
-
-    /**
-     * Reads bytes from the socket into the given buffer.
-     *
-     * @throws IOException if the socket is closed or an I/O occurs
-     * @throws SocketTimeoutException if the read timeout elapses
-     */
-    private int read(ByteBuffer dst) throws IOException {
-        readLock.lock();
-        try {
-            int n = 0;
-            beginRead();
-            try {
-                if (isInputClosed)
-                    return IOStatus.EOF;
-                n = IOUtil.read(fd, dst, -1, nd);
-                if (n == IOStatus.UNAVAILABLE && isOpen()) {
-                    long nanos = readTimeoutNanos;
-                    if (nanos > 0) {
-                        // read with timeout
-                        do {
-                            long startTime = System.nanoTime();
-                            park(Net.POLLIN, nanos);
-                            n = IOUtil.read(fd, dst, -1, nd);
-                            if (n == IOStatus.UNAVAILABLE) {
-                                nanos -= System.nanoTime() - startTime;
-                                if (nanos <= 0)
-                                    throw new SocketTimeoutException();
-                            }
-                        } while (n == IOStatus.UNAVAILABLE && isOpen());
-                    } else {
-                        // read, no timeout
-                        do {
-                            park(Net.POLLIN, 0);
-                            n = IOUtil.read(fd, dst, -1, nd);
-                        } while (n == IOStatus.UNAVAILABLE && isOpen());
-                    }
-                }
-                return n;
-            } finally {
-                endRead(n > 0);
-            }
-        } finally {
-            readLock.unlock();
-        }
-    }
-
-    /**
-     * Writes a sequence of bytes to this socket from the given buffer.
-     *
-     * @throws IOException if the socket is closed or an I/O occurs
-     */
-    private int write(ByteBuffer dst) throws IOException {
-        writeLock.lock();
-        try {
-            int n = 0;
-            beginWrite();
-            try {
-                n = IOUtil.write(fd, dst, -1, nd);
-                while (n == IOStatus.UNAVAILABLE && isOpen()) {
-                    park(Net.POLLOUT, 0);
-                    n = IOUtil.write(fd, dst, -1, nd);
-                }
-                return n;
-            } finally {
-                endWrite(n > 0);
-            }
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of bytes in the socket buffer waiting to be read
-     */
-    private int available() throws IOException {
-        readLock.lock();
-        try {
-            ensureOpenAndConnected();
-            if (isInputClosed) {
-                return 0;
-            } else {
-                return Net.available(fd);
-            }
-        } finally {
-            readLock.unlock();
-        }
-    }
-
-    /**
-     * Closes the socket.
-     *
-     * This method waits for outstanding read/write operations to complete. If
-     * a thread is blocked reading or writing then the socket is pre-closed and
-     * the threads signalled to ensure that the outstanding I/O operations
-     * complete quickly.
-     */
-    @Override
-    public void close() throws IOException {
-        boolean interrupted = false;
-
-        synchronized (stateLock) {
-            if (state > ST_CONNECTED)
-                return;
-            state = ST_CLOSING;
-
-            // unpark and wait for fibers to complete I/O operations
-            if (NativeThread.isFiber(readerThread) ||
-                    NativeThread.isFiber(writerThread)) {
-                Poller.stopPoll(fdVal);
-
-                while (NativeThread.isFiber(readerThread) ||
-                        NativeThread.isFiber(writerThread)) {
-                    try {
-                        stateLock.wait();
-                    } catch (InterruptedException e) {
-                        interrupted = true;
-                    }
-                }
-            }
-
-            // interrupt and wait for kernel threads to complete I/O operations
-            long reader = readerThread;
-            long writer = writerThread;
-            if (NativeThread.isKernelThread(reader) ||
-                    NativeThread.isKernelThread(writer)) {
-                nd.preClose(fd);
-
-                if (NativeThread.isKernelThread(reader))
-                    NativeThread.signal(reader);
-                if (NativeThread.isKernelThread(writer))
-                    NativeThread.signal(writer);
-
-                // wait for blocking I/O operations to end
-                while (NativeThread.isKernelThread(readerThread) ||
-                        NativeThread.isKernelThread(writerThread)) {
-                    try {
-                        stateLock.wait();
-                    } catch (InterruptedException e) {
-                        interrupted = true;
-                    }
-                }
-            }
-
-            state = ST_CLOSED;
-            nd.close(fd);
-        }
-
-        // restore interrupt status
-        if (interrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Returns an InputStream to read from the socket.
-     */
-    public InputStream inputStream() {
-        return new InputStream() {
-            private volatile boolean eof;
-            @Override
-            public int read() throws IOException {
-                byte[] a = new byte[1];
-                int n = read(a, 0, 1);
-                return (n > 0) ? (a[0] & 0xff) : -1;
-            }
-            @Override
-            public int read(byte b[], int off, int len) throws IOException {
-                Objects.checkFromIndexSize(off, len, b.length);
-                if (eof) {
-                    return -1; // legacy SocketInputStream behavior
-                } else if (len == 0) {
-                    return 0;
-                } else {
-                    ByteBuffer dst = ByteBuffer.wrap(b, off, len);
-                    int n = SocketStreams.this.read(dst);
-                    if (n == -1)
-                        eof = true;
-                    return n;
-                }
-            }
-            @Override
-            public int available() throws IOException {
-                return SocketStreams.this.available();
-            }
-            @Override
-            public void close() throws IOException {
-                parent.close();
-            }
-        };
-    }
-
-    /**
-     * Returns an OutputStream to write to the socket.
-     */
-    public OutputStream outputStream() {
-        return new OutputStream() {
-            @Override
-            public void write(int b) throws IOException {
-                byte[] a = new byte[] { (byte) b };
-                write(a, 0, 1);
-            }
-            @Override
-            public void write(byte b[], int off, int len) throws IOException {
-                Objects.checkFromIndexSize(off, len, b.length);
-                if (len > 0) {
-                    ByteBuffer src = ByteBuffer.wrap(b, off, len);
-                    while (src.hasRemaining()) {
-                        SocketStreams.this.write(src);
-                    }
-                }
-            }
-            @Override
-            public void close() throws IOException {
-                parent.close();
-            }
-        };
-    }
-
-    /**
-     * Shutdown the connection for reading without closing the socket.
-     */
-    public SocketStreams shutdownInput() throws IOException {
-        synchronized (stateLock) {
-            ensureOpen();
-            if (!isInputClosed) {
-                Net.shutdown(fd, Net.SHUT_RD);
-                long reader = readerThread;
-                if (NativeThread.isFiber(reader)) {
-                    Poller.stopPoll(fdVal, Net.POLLIN);
-                } else if (NativeThread.isKernelThread(reader)) {
-                    NativeThread.signal(reader);
-                }
-                isInputClosed = true;
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Shutdown the connection for writing without closing the socket.
-     */
-    public SocketStreams shutdownOutput() throws IOException {
-        synchronized (stateLock) {
-            ensureOpen();
-            if (!isOutputClosed) {
-                Net.shutdown(fd, Net.SHUT_WR);
-                long writer = writerThread;
-                if (NativeThread.isFiber(writer)) {
-                    Poller.stopPoll(fdVal, Net.POLLOUT);
-                } else if (NativeThread.isKernelThread(writer)) {
-                    NativeThread.signal(writer);
-                }
-                isOutputClosed = true;
-            }
-            return this;
-        }
-    }
-
-    /**
-     * Sets the read timeout in millis.
-     */
-    public SocketStreams readTimeout(long millis) {
-        readTimeoutNanos = NANOSECONDS.convert(millis, MILLISECONDS);
-        return this;
-    }
-}
--- a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c	Tue Jan 08 14:54:18 2019 +0000
+++ b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c	Wed Jan 09 13:44:43 2019 +0000
@@ -74,7 +74,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this,
+Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jclass clazz,
                                                 jobject ssfdo, jobject newfdo,
                                                 jobjectArray isaa)
 {
--- a/test/jdk/ProblemList.txt	Tue Jan 08 14:54:18 2019 +0000
+++ b/test/jdk/ProblemList.txt	Wed Jan 09 13:44:43 2019 +0000
@@ -572,6 +572,9 @@
 java/net/Socks/SocksIPv6Test.java                               0000000 generic-all
 java/net/Socket/SocksConnectTimeout.java                        0000000 generic-all
 
+java/net/Inet6Address/B6206527.java                             8216417 macosx-all
+java/net/ipv6tests/B6521014.java                                8216417 macosx-all
+
 ############################################################################
 
 # jdk_nio
--- a/test/jdk/java/lang/Fiber/NetSockets.java	Tue Jan 08 14:54:18 2019 +0000
+++ b/test/jdk/java/lang/Fiber/NetSockets.java	Wed Jan 09 13:44:43 2019 +0000
@@ -205,6 +205,67 @@
         });
     }
 
+    /**
+     * ServerSocket accept, no blocking
+     */
+    public void testServerSocketCAccept1() {
+        test(() -> {
+            try (var listener = new ServerSocket(0)) {
+                var socket1 = new Socket(listener.getInetAddress(), listener.getLocalPort());
+                // accept should not block
+                var socket2 = listener.accept();
+                socket1.close();
+                socket2.close();
+            }
+        });
+    }
+
+    /**
+     * Fiber blocks in ServerSocket.accept
+     */
+    public void testServerSocketAccept2() {
+        test(() -> {
+            try (var listener = new ServerSocket(0)) {
+                var socket1 = new Socket();
+                ScheduledConnector.schedule(socket1, listener.getLocalSocketAddress(), DELAY);
+                // accept will block
+                var socket2 = listener.accept();
+                socket1.close();
+                socket2.close();
+            }
+        });
+    }
+
+    /**
+     * ServerSocket close while Fiber blocked in accept
+     */
+    public void testServerSocketAcceptAsyncClose() {
+        test(() -> {
+            try (var listener = new ServerSocket(0)) {
+                ScheduledCloser.schedule(listener, DELAY);
+                try {
+                    listener.accept().close();
+                    throw new RuntimeException("connection accepted???");
+                } catch (SocketException expected) { }
+            }
+        });
+    }
+
+    /**
+     * Fiber cancelled while blocked in ServerSocket.accept
+     */
+    public void testServerSocketAcceptCancel() {
+        test(() -> {
+            try (var listener = new ServerSocket(0)) {
+                var fiber = Fiber.current().orElseThrow();
+                ScheduledCanceller.schedule(fiber, DELAY);
+                try {
+                    listener.accept().close();
+                    throw new RuntimeException("connection accepted???");
+                } catch (SocketException expected) { }
+            }
+        });
+    }
 
     // -- supporting classes --
 
@@ -323,6 +384,33 @@
     }
 
     /**
+     * Establish a connection to a socket address after a delay
+     */
+    static class ScheduledConnector implements Runnable {
+        private final Socket socket;
+        private final SocketAddress address;
+        private final long delay;
+
+        ScheduledConnector(Socket socket, SocketAddress address, long delay) {
+            this.socket = socket;
+            this.address = address;
+            this.delay = delay;
+        }
+
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(delay);
+                socket.connect(address);
+            } catch (Exception e) { }
+        }
+
+        static void schedule(Socket socket, SocketAddress address, long delay) {
+            new Thread(new ScheduledConnector(socket, address, delay)).start();
+        }
+    }
+
+    /**
      * Cancel a fiber after a delay
      */
     static class ScheduledCanceller implements Runnable {