8309120: java/net/httpclient/AsyncShutdownNow.java fails intermittently

Reviewed-by: jpai
This commit is contained in:
Daniel Fuchs 2023-05-31 10:49:20 +00:00
parent a990322429
commit 4aea7dab15
3 changed files with 26 additions and 13 deletions
src/java.net.http/share/classes/jdk/internal/net/http
test/jdk/java/net/httpclient

@ -38,6 +38,7 @@ import java.security.PrivilegedExceptionAction;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import jdk.internal.net.http.common.FlowTube;
@ -59,6 +60,7 @@ class PlainHttpConnection extends HttpConnection {
private volatile boolean closed;
private volatile ConnectTimerEvent connectTimerEvent; // may be null
private volatile int unsuccessfulAttempts;
private final ReentrantLock stateLock = new ReentrantLock();
// Indicates whether a connection attempt has succeeded or should be retried.
// If the attempt failed, and shouldn't be retried, there will be an exception
@ -240,11 +242,17 @@ class PlainHttpConnection extends HttpConnection {
boolean connectionOpened() {
boolean closed = this.closed;
if (closed) return false;
synchronized (this) {
stateLock.lock();
try {
closed = this.closed;
}
if (!closed) {
client().connectionOpened(this);
if (!closed) {
client().connectionOpened(this);
}
// connectionOpened might call close() if the client
// is shutting down.
closed = this.closed;
} finally {
stateLock.unlock();
}
return !closed;
}
@ -398,16 +406,16 @@ class PlainHttpConnection extends HttpConnection {
*/
@Override
public void close() {
synchronized (this) {
if (closed) {
return;
}
closed = true;
}
var closed = this.closed;
if (closed) return;
stateLock.lock();
try {
if (closed = this.closed) return;
closed = this.closed = true;
Log.logTrace("Closing: " + toString());
if (debug.on())
debug.log("Closing channel: " + client().debugInterestOps(chan));
var connectTimerEvent = this.connectTimerEvent;
if (connectTimerEvent != null)
client().cancelTimer(connectTimerEvent);
if (Log.channel()) {
@ -420,7 +428,10 @@ class PlainHttpConnection extends HttpConnection {
client().connectionClosed(this);
}
} catch (IOException e) {
debug.log("Closing resulted in " + e);
Log.logTrace("Closing resulted in " + e);
} finally {
stateLock.unlock();
}
}
@ -431,7 +442,7 @@ class PlainHttpConnection extends HttpConnection {
}
@Override
synchronized boolean connected() {
boolean connected() {
return connected;
}

@ -23,7 +23,7 @@
/*
* @test
* @bug 8267140
* @bug 8267140 8309120
* @summary Test HttpClient::shutdownNow. Any running operation will
* be aborted and the client should eventually exit.
* This test tests shutdownNow, awaitTermination, and
@ -139,6 +139,8 @@ public class AsyncShutdownNow implements HttpServerAdapters {
if (message.equals("closed")) return true;
// exception from selmgr.abort
if (message.equals("shutdownNow")) return true;
// exception from cancelling an HTTP/2 stream
if (message.matches("Stream [0-9]+ cancelled")) return true;
return false;
}

@ -135,7 +135,7 @@ public class ShutdownNow implements HttpServerAdapters {
// exception from selmgr.abort
if (message.equals("shutdownNow")) return true;
// exception from cancelling an HTTP/2 stream
if (message.matches("stream [0-9]+ cancelled")) return true;
if (message.matches("Stream [0-9]+ cancelled")) return true;
return false;
}