mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-23 08:45:33 +00:00
8372159: HttpClient SelectorManager thread could be a VirtualThread
Reviewed-by: djelinski
This commit is contained in:
parent
0a963b612d
commit
aec54726df
@ -98,6 +98,7 @@ import jdk.internal.net.http.common.OperationTrackers.Trackable;
|
||||
import jdk.internal.net.http.common.OperationTrackers.Tracker;
|
||||
import jdk.internal.net.http.common.Utils.SafeExecutor;
|
||||
import jdk.internal.net.http.common.Utils.SafeExecutorService;
|
||||
import jdk.internal.net.http.common.Utils.UseVTForSelector;
|
||||
import jdk.internal.net.http.websocket.BuilderImpl;
|
||||
|
||||
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
|
||||
@ -126,6 +127,16 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
static final long IDLE_CONNECTION_TIMEOUT_H2 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h2", KEEP_ALIVE_TIMEOUT);
|
||||
static final long IDLE_CONNECTION_TIMEOUT_H3 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h3", IDLE_CONNECTION_TIMEOUT_H2);
|
||||
|
||||
static final UseVTForSelector USE_VT_FOR_SELECTOR =
|
||||
Utils.useVTForSelector("jdk.internal.httpclient.tcp.selector.useVirtualThreads", "default");
|
||||
private static boolean useVtForSelector() {
|
||||
return switch (USE_VT_FOR_SELECTOR) {
|
||||
case ALWAYS -> true;
|
||||
case NEVER -> false;
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
// Define the default factory as a static inner class
|
||||
// that embeds all the necessary logic to avoid
|
||||
// the risk of using a lambda that might keep a reference on the
|
||||
@ -293,7 +304,6 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
if (pending.cf.isDone()) return res;
|
||||
|
||||
var client = pending.client;
|
||||
var cf = pending.cf;
|
||||
var id = pending.id;
|
||||
boolean added = client.pendingRequests.add(pending);
|
||||
// this may immediately remove `pending` from the set is the cf is already completed
|
||||
@ -342,6 +352,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
private final boolean isDefaultExecutor;
|
||||
private final SSLContext sslContext;
|
||||
private final SSLParameters sslParams;
|
||||
private final Thread selmgrThread;
|
||||
private final SelectorManager selmgr;
|
||||
private final FilterFactory filters;
|
||||
private final Http2ClientImpl client2;
|
||||
@ -509,7 +520,11 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
// unlikely
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
selmgr.setDaemon(true);
|
||||
selmgrThread = useVtForSelector()
|
||||
? Thread.ofVirtual().name("HttpClient-" + id + "-SelectorManager")
|
||||
.inheritInheritableThreadLocals(false).unstarted(selmgr)
|
||||
: Thread.ofPlatform().name("HttpClient-" + id + "-SelectorManager")
|
||||
.inheritInheritableThreadLocals(false).daemon().unstarted(selmgr);
|
||||
filters = new FilterFactory();
|
||||
initFilters();
|
||||
assert facadeRef.get() != null;
|
||||
@ -528,7 +543,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
|
||||
private void start() {
|
||||
try {
|
||||
selmgr.start();
|
||||
selmgrThread.start();
|
||||
} catch (Throwable t) {
|
||||
isStarted.set(true);
|
||||
throw t;
|
||||
@ -635,7 +650,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
@Override
|
||||
public boolean awaitTermination(Duration duration) throws InterruptedException {
|
||||
// Implicit NPE will be thrown if duration is null
|
||||
return selmgr.join(duration);
|
||||
return selmgrThread.join(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -927,7 +942,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
}
|
||||
|
||||
boolean isSelectorThread() {
|
||||
return Thread.currentThread() == selmgr;
|
||||
return Thread.currentThread() == selmgrThread;
|
||||
}
|
||||
|
||||
AltServicesRegistry registry() { return registry; }
|
||||
@ -1157,7 +1172,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
}
|
||||
|
||||
// Main loop for this client's selector
|
||||
private static final class SelectorManager extends Thread {
|
||||
private static final class SelectorManager implements Runnable {
|
||||
|
||||
// For testing purposes we have an internal System property that
|
||||
// can control the frequency at which the selector manager will wake
|
||||
@ -1196,9 +1211,6 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
SelectorManager(HttpClientImpl ref) throws IOException {
|
||||
super(null, null,
|
||||
"HttpClient-" + ref.id + "-SelectorManager",
|
||||
0, false);
|
||||
owner = ref;
|
||||
debug = ref.debug;
|
||||
debugtimeout = ref.debugtimeout;
|
||||
@ -1221,7 +1233,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
}
|
||||
|
||||
void eventUpdated(AsyncEvent e) throws ClosedChannelException {
|
||||
if (Thread.currentThread() == this) {
|
||||
if (owner.isSelectorThread()) {
|
||||
SelectionKey key = e.channel().keyFor(selector);
|
||||
if (key != null && key.isValid()) {
|
||||
SelectorAttachment sa = (SelectorAttachment) key.attachment();
|
||||
@ -1315,6 +1327,10 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
if (!inSelectorThread) selector.wakeup();
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return owner.selmgrThread.getName();
|
||||
}
|
||||
|
||||
// Only called by the selector manager thread
|
||||
private void shutdown() {
|
||||
try {
|
||||
|
||||
@ -242,6 +242,15 @@ public final class Utils {
|
||||
return true;
|
||||
};
|
||||
|
||||
public enum UseVTForSelector { ALWAYS, NEVER, DEFAULT }
|
||||
|
||||
public static UseVTForSelector useVTForSelector(String property, String defval) {
|
||||
String useVtForSelector = System.getProperty(property, defval);
|
||||
return Stream.of(UseVTForSelector.values())
|
||||
.filter((v) -> v.name().equalsIgnoreCase(useVtForSelector))
|
||||
.findFirst().orElse(UseVTForSelector.DEFAULT);
|
||||
}
|
||||
|
||||
public static <T extends Throwable> T addSuppressed(T x, Throwable suppressed) {
|
||||
if (x != suppressed && suppressed != null) {
|
||||
var sup = x.getSuppressed();
|
||||
|
||||
@ -143,8 +143,9 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator {
|
||||
Log.logError("{0}: stateless reset from peer ({1})", connection.logTag(),
|
||||
(peerIsServer ? "server" : "client"));
|
||||
}
|
||||
var label = "quic:" + connection.uniqueId();
|
||||
final SilentTermination st = forSilentTermination("stateless reset from peer ("
|
||||
+ (peerIsServer ? "server" : "client") + ")");
|
||||
+ (peerIsServer ? "server" : "client") + ") on " + label);
|
||||
terminate(st);
|
||||
}
|
||||
|
||||
|
||||
@ -346,8 +346,10 @@ final class IdleTimeoutManager {
|
||||
}
|
||||
}
|
||||
// silently close the connection and discard all its state
|
||||
final TerminationCause cause = forSilentTermination("connection idle timed out ("
|
||||
+ timeoutMillis + " milli seconds)");
|
||||
var type = connection.isClientConnection() ? "client" : "server";
|
||||
var label = "quic:" + connection.uniqueId();
|
||||
final TerminationCause cause = forSilentTermination(type + " connection idle timed out ("
|
||||
+ timeoutMillis + " milli seconds) on " + label);
|
||||
connection.terminator.terminate(cause);
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@ import jdk.internal.net.http.common.SequentialScheduler;
|
||||
import jdk.internal.net.http.common.TimeLine;
|
||||
import jdk.internal.net.http.common.TimeSource;
|
||||
import jdk.internal.net.http.common.Utils;
|
||||
import jdk.internal.net.http.common.Utils.UseVTForSelector;
|
||||
import jdk.internal.net.http.quic.QuicSelector.QuicNioSelector;
|
||||
import jdk.internal.net.http.quic.QuicSelector.QuicVirtualThreadPoller;
|
||||
import jdk.internal.net.http.quic.packets.QuicPacket.HeadersType;
|
||||
@ -116,7 +117,6 @@ public abstract sealed class QuicEndpoint implements AutoCloseable
|
||||
static final boolean DGRAM_SEND_ASYNC;
|
||||
static final int MAX_BUFFERED_HIGH;
|
||||
static final int MAX_BUFFERED_LOW;
|
||||
enum UseVTForSelector { ALWAYS, NEVER, DEFAULT }
|
||||
static final UseVTForSelector USE_VT_FOR_SELECTOR;
|
||||
static {
|
||||
// This default value is the maximum payload size of
|
||||
@ -144,11 +144,8 @@ public abstract sealed class QuicEndpoint implements AutoCloseable
|
||||
if (maxBufferLow >= maxBufferHigh) maxBufferLow = maxBufferHigh >> 1;
|
||||
MAX_BUFFERED_HIGH = maxBufferHigh;
|
||||
MAX_BUFFERED_LOW = maxBufferLow;
|
||||
String useVtForSelector =
|
||||
System.getProperty("jdk.internal.httpclient.quic.selector.useVirtualThreads", "default");
|
||||
USE_VT_FOR_SELECTOR = Stream.of(UseVTForSelector.values())
|
||||
.filter((v) -> v.name().equalsIgnoreCase(useVtForSelector))
|
||||
.findFirst().orElse(UseVTForSelector.DEFAULT);
|
||||
var property = "jdk.internal.httpclient.quic.selector.useVirtualThreads";
|
||||
USE_VT_FOR_SELECTOR = Utils.useVTForSelector(property, "default");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -45,9 +45,9 @@ import jdk.internal.net.http.common.Logger;
|
||||
import jdk.internal.net.http.common.TimeLine;
|
||||
import jdk.internal.net.http.common.TimeSource;
|
||||
import jdk.internal.net.http.common.Utils;
|
||||
import jdk.internal.net.http.common.Utils.UseVTForSelector;
|
||||
import jdk.internal.net.http.quic.QuicEndpoint.QuicVirtualThreadedEndpoint;
|
||||
import jdk.internal.net.http.quic.QuicEndpoint.QuicSelectableEndpoint;
|
||||
import jdk.internal.net.http.quic.QuicEndpoint.UseVTForSelector;
|
||||
|
||||
import static jdk.internal.net.http.quic.QuicEndpoint.USE_VT_FOR_SELECTOR;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2025, 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
|
||||
@ -390,12 +390,6 @@ public class ReferenceTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSelectorManager(Thread t) {
|
||||
String name = t.getName();
|
||||
if (name == null) return false;
|
||||
return name.contains("SelectorManager");
|
||||
}
|
||||
|
||||
// This is a slightly more permissive check than the default checks,
|
||||
// it only verifies that all CFs returned by send/sendAsync have been
|
||||
// completed, and that all opened channels have been closed, and that
|
||||
|
||||
228
test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java
Normal file
228
test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import jdk.httpclient.test.lib.common.HttpServerAdapters;
|
||||
import jdk.test.lib.net.SimpleSSLContext;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import static java.net.http.HttpClient.Builder.NO_PROXY;
|
||||
import static java.net.http.HttpClient.Version.HTTP_2;
|
||||
|
||||
/*
|
||||
* @test id=default
|
||||
* @bug 8372159
|
||||
* @summary Verifies whether `SelectorManager` uses virtual threads
|
||||
* as expected when no explicit configuration is provided
|
||||
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
||||
* @build jdk.test.lib.net.SimpleSSLContext
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* @run junit/othervm
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors
|
||||
* H2SelectorVTTest
|
||||
*/
|
||||
/*
|
||||
* @test id=never
|
||||
* @bug 8372159
|
||||
* @summary Verifies that `SelectorManager` does *not* use virtual threads
|
||||
when explicitly configured to "never" use them
|
||||
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
||||
* @build jdk.test.lib.net.SimpleSSLContext
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* @run junit/othervm
|
||||
* -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=never
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors
|
||||
* H2SelectorVTTest
|
||||
*/
|
||||
/*
|
||||
* @test id=always
|
||||
* @bug 8372159
|
||||
* @summary Verifies that `SelectorManager` does *always* use virtual threads
|
||||
when explicitly configured to "always" use them
|
||||
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
||||
* @build jdk.test.lib.net.SimpleSSLContext
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* @run junit/othervm
|
||||
* -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=always
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors
|
||||
* H2SelectorVTTest
|
||||
*/
|
||||
/*
|
||||
* @test id=explicit-default
|
||||
* @bug 8372159
|
||||
* @summary Verifies whether `SelectorManager` uses virtual threads
|
||||
* as expected when `default` is explicitly configured
|
||||
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
||||
* @build jdk.test.lib.net.SimpleSSLContext
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* @run junit/othervm
|
||||
* -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=default
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors
|
||||
* H2SelectorVTTest
|
||||
*/
|
||||
/*
|
||||
* @test id=garbage
|
||||
* @bug 8372159
|
||||
* @summary Verifies whether `SelectorManager` uses virtual threads when
|
||||
it is configured using an invalid value
|
||||
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
||||
* @build jdk.test.lib.net.SimpleSSLContext
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* @run junit/othervm
|
||||
* -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=garbage
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors
|
||||
* H2SelectorVTTest
|
||||
*/
|
||||
// -Djava.security.debug=all
|
||||
class H2SelectorVTTest implements HttpServerAdapters {
|
||||
|
||||
private static SSLContext sslContext;
|
||||
private static HttpTestServer h2Server;
|
||||
private static String requestURI;
|
||||
|
||||
enum UseVTForSelector { ALWAYS, NEVER, DEFAULT }
|
||||
private static final String PROP_NAME = "jdk.internal.httpclient.tcp.selector.useVirtualThreads";
|
||||
private static final UseVTForSelector USE_VT_FOR_SELECTOR;
|
||||
static {
|
||||
String useVtForSelector =
|
||||
System.getProperty(PROP_NAME, "default");
|
||||
USE_VT_FOR_SELECTOR = Stream.of(UseVTForSelector.values())
|
||||
.filter((v) -> v.name().equalsIgnoreCase(useVtForSelector))
|
||||
.findFirst().orElse(UseVTForSelector.DEFAULT);
|
||||
}
|
||||
|
||||
private static boolean isTCPSelectorThreadVirtual() {
|
||||
return switch (USE_VT_FOR_SELECTOR) {
|
||||
case ALWAYS -> true;
|
||||
case NEVER -> false;
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void beforeClass() throws Exception {
|
||||
sslContext = new SimpleSSLContext().get();
|
||||
if (sslContext == null) {
|
||||
throw new AssertionError("Unexpected null sslContext");
|
||||
}
|
||||
// create a h2 server
|
||||
h2Server = HttpTestServer.create(HTTP_2, sslContext);
|
||||
h2Server.addHandler((exchange) -> exchange.sendResponseHeaders(200, 0), "/hello");
|
||||
h2Server.start();
|
||||
System.out.println("Server started at " + h2Server.getAddress());
|
||||
requestURI = "https://" + h2Server.serverAuthority() + "/hello";
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterClass() throws Exception {
|
||||
if (h2Server != null) {
|
||||
System.out.println("Stopping server " + h2Server.getAddress());
|
||||
h2Server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues various HTTP/2 requests and verifies the responses are received
|
||||
*/
|
||||
@Test
|
||||
void testBasicRequests() throws Exception {
|
||||
try (final HttpClient client = HttpClient.newBuilder()
|
||||
.proxy(NO_PROXY)
|
||||
.sslContext(sslContext).build()) {
|
||||
final URI reqURI = new URI(requestURI);
|
||||
final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(reqURI);
|
||||
|
||||
// GET
|
||||
final HttpRequest req1 = reqBuilder.copy().GET().build();
|
||||
System.out.println("\nIssuing request: " + req1);
|
||||
final HttpResponse<?> resp1 = client.send(req1, BodyHandlers.ofString());
|
||||
Assertions.assertEquals(200, resp1.statusCode(), "unexpected response code for GET request");
|
||||
assertSelectorThread(client);
|
||||
|
||||
// POST
|
||||
final HttpRequest req2 = reqBuilder.copy().POST(BodyPublishers.ofString("foo")).build();
|
||||
System.out.println("\nIssuing request: " + req2);
|
||||
final HttpResponse<?> resp2 = client.send(req2, BodyHandlers.ofString());
|
||||
Assertions.assertEquals(200, resp2.statusCode(), "unexpected response code for POST request");
|
||||
assertSelectorThread(client);
|
||||
|
||||
// HEAD
|
||||
final HttpRequest req3 = reqBuilder.copy().HEAD().build();
|
||||
System.out.println("\nIssuing request: " + req3);
|
||||
final HttpResponse<?> resp3 = client.send(req3, BodyHandlers.ofString());
|
||||
Assertions.assertEquals(200, resp3.statusCode(), "unexpected response code for HEAD request");
|
||||
assertSelectorThread(client);
|
||||
}
|
||||
}
|
||||
|
||||
// This method attempts to determine whether the selector thread
|
||||
// is a platform thread or a virtual thread, and throws if expectations
|
||||
// ar not met.
|
||||
// Since we don't have access to the selector thread, the method
|
||||
// uses a roundabout way to figure this out: it enumerates all
|
||||
// platform threads, and if it finds a thread whose name matches
|
||||
// the expected name of the selector thread it concludes that the
|
||||
// selector thread is a platform thread. Otherwise, it assumes
|
||||
// that the thread is virtual.
|
||||
private static void assertSelectorThread(HttpClient client) {
|
||||
String cname = client.toString();
|
||||
String clientId = cname.substring(cname.indexOf('(') + 1, cname.length() -1);
|
||||
String name = "HttpClient-" + clientId + "-SelectorManager";
|
||||
Set<String> threads = new HashSet<>(Thread.getAllStackTraces().keySet().stream()
|
||||
.map(Thread::getName)
|
||||
.toList());
|
||||
boolean found = threads.contains(name);
|
||||
String status = found == isTCPSelectorThreadVirtual() ? "ERROR" : "SUCCESS";
|
||||
String propval = System.getProperty(PROP_NAME);
|
||||
if (propval == null) {
|
||||
System.out.printf("%s not defined, virtual=%s, thread found=%s%n",
|
||||
PROP_NAME, isTCPSelectorThreadVirtual(), found);
|
||||
} else {
|
||||
System.out.printf("%s=%s, virtual=%s, thread found=%s%n",
|
||||
PROP_NAME, propval, isTCPSelectorThreadVirtual(), found);
|
||||
}
|
||||
final String msg;
|
||||
if (found) {
|
||||
msg = "%s found in %s".formatted(name, threads);
|
||||
System.out.printf("%s: %s%n", status, msg);
|
||||
} else {
|
||||
msg = "%s not found in %s".formatted(name, threads);
|
||||
System.out.printf("%s: %s%n", status, msg);
|
||||
}
|
||||
Assertions.assertEquals(!isTCPSelectorThreadVirtual(), found, msg);
|
||||
}
|
||||
}
|
||||
@ -196,6 +196,15 @@ class H3QuicVTTest implements HttpServerAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
// This method attempts to determine whether the quic selector thread
|
||||
// is a platform thread or a virtual thread, and throws if expectations
|
||||
// are not met.
|
||||
// Since we don't have access to the quic selector thread, the method
|
||||
// uses a roundabout way to figure this out: it enumerates all
|
||||
// platform threads, and if it finds a thread whose name matches
|
||||
// the expected name of the quic selector thread it concludes that the
|
||||
// selector thread is a platform thread. Otherwise, it assumes
|
||||
// that the thread is virtual.
|
||||
private static void assertSelectorThread(HttpClient client) {
|
||||
String clientId = client.toString().substring(client.toString().indexOf('('));
|
||||
String name = "Thread(QuicSelector(HttpClientImpl" + clientId + "))";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user