--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java Fri Apr 26 08:53:46 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java Fri Apr 26 11:31:38 2019 +0100
@@ -69,9 +69,13 @@
* including behavior and exceptions that are not specified by SocketImpl.
*
* The underlying socket used by this SocketImpl is initially configured
- * blocking. If a connect, accept or read is attempted with a timeout then the
- * socket is changed to non-blocking mode. When in non-blocking mode, operations
- * that don't complete immediately will poll the socket.
+ * blocking. If the connect method is used to establish a connection with a
+ * timeout then the socket is configured non-blocking for the connect attempt,
+ * and then restored to blocking mode when the connection is established.
+ * If the accept or read methods are used with a timeout then the socket is
+ * configured non-blocking and is never restored. When in non-blocking mode,
+ * operations that don't complete immediately will poll the socket and preserve
+ * the semantics of blocking operations.
*/
public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl {
@@ -105,7 +109,7 @@
private boolean stream;
private FileDescriptorCloser closer;
- // lazily set to true when the socket is configured non-blocking
+ // set by configureNonBlockingForever when the socket changed to non-blocking
private volatile boolean nonBlocking;
// used by connect/read/write/accept, protected by stateLock
@@ -189,20 +193,41 @@
}
/**
- * Configures the socket to be non-blocking (if not already non-blocking)
- * @throws IOException if there is an I/O error changing the blocking mode
+ * Configures the socket's blocking mode except when socket has been
+ * configured non-blocking by {@code configureNonBlockingForever}.
+ * @throws IOException if closed or there is an I/O error changing the mode
*/
- private void configureNonBlocking(FileDescriptor fd) throws IOException {
+ private void configureBlocking(FileDescriptor fd, boolean block) throws IOException {
+ assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
if (!nonBlocking) {
- assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
+ stateLock.lock();
+ try {
+ if (!nonBlocking) {
+ ensureOpen();
+ IOUtil.configureBlocking(fd, block);
+ }
+ } finally {
+ stateLock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Configures the socket to be non-blocking. Once configured to non-blocking
+ * by this method then the blocking mode cannot be changed back to blocking.
+ * @throws IOException if closed or there is an I/O error changing the mode
+ */
+ private void configureNonBlockingForever(FileDescriptor fd) throws IOException {
+ assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
+ if (!nonBlocking) {
stateLock.lock();
try {
ensureOpen();
IOUtil.configureBlocking(fd, false);
+ nonBlocking = true;
} finally {
stateLock.unlock();
}
- nonBlocking = true;
}
}
@@ -265,7 +290,6 @@
private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos)
throws IOException
{
- assert nonBlocking;
long startNanos = System.nanoTime();
int n = tryRead(fd, b, off, len);
while (n == IOStatus.UNAVAILABLE && isOpen()) {
@@ -296,7 +320,7 @@
int timeout = this.timeout;
if (timeout > 0) {
// read with timeout
- configureNonBlocking(fd);
+ configureNonBlockingForever(fd);
n = timedRead(fd, b, off, len, MILLISECONDS.toNanos(timeout));
} else {
// read, no timeout
@@ -584,8 +608,12 @@
boolean connected = false;
FileDescriptor fd = beginConnect(address, port);
try {
- if (millis > 0)
- configureNonBlocking(fd);
+
+ // configure socket to non-blocking mode when there is a timeout
+ if (millis > 0) {
+ configureBlocking(fd, false);
+ }
+
int n = Net.connect(fd, address, port);
if (n > 0) {
// connection established
@@ -606,6 +634,12 @@
connected = polled && isOpen();
}
}
+
+ // restore socket to blocking mode
+ if (connected && millis > 0) {
+ configureBlocking(fd, true);
+ }
+
} finally {
endConnect(fd, connected);
}
@@ -707,7 +741,6 @@
long nanos)
throws IOException
{
- assert nonBlocking;
long startNanos = System.nanoTime();
int n = Net.accept(fd, newfd, isaa);
while (n == IOStatus.UNAVAILABLE && isOpen()) {
@@ -756,7 +789,7 @@
try {
if (remainingNanos > 0) {
// accept with timeout
- configureNonBlocking(fd);
+ configureNonBlockingForever(fd);
n = timedAccept(fd, newfd, isaa, remainingNanos);
} else {
// accept, no timeout
@@ -886,7 +919,7 @@
}
} catch (IOException ignore) { }
- // interrupt and wait for kernel threads to complete I/O operations
+ // interrupt and wait for threads to complete I/O operations
long reader = readerThread;
long writer = writerThread;
if (reader != 0 || writer != 0) {
--- a/test/jdk/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java Fri Apr 26 08:53:46 2019 +0100
+++ b/test/jdk/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java Fri Apr 26 11:31:38 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, 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
--- a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java Fri Apr 26 08:53:46 2019 +0100
+++ b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java Fri Apr 26 11:31:38 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/test/jdk/java/net/Socket/asyncClose/AsyncClose.java Fri Apr 26 08:53:46 2019 +0100
+++ b/test/jdk/java/net/Socket/asyncClose/AsyncClose.java Fri Apr 26 11:31:38 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, 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
--- a/test/jdk/java/net/SocketImpl/BadUsages.java Fri Apr 26 08:53:46 2019 +0100
+++ b/test/jdk/java/net/SocketImpl/BadUsages.java Fri Apr 26 11:31:38 2019 +0100
@@ -23,9 +23,10 @@
/*
* @test
+ * @bug 8221481
* @compile/module=java.base java/net/PlatformSocketImpl.java
* @run testng/othervm BadUsages
- * @summary Test the platform SocketImpl in illegal state/bad input scenarios
+ * @summary Test the platform SocketImpl when used in unintended ways
*/
import java.io.IOException;
--- a/test/jdk/java/net/ipv6tests/TcpTest.java Fri Apr 26 08:53:46 2019 +0100
+++ b/test/jdk/java/net/ipv6tests/TcpTest.java Fri Apr 26 11:31:38 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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