mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8284161: Implementation of Virtual Threads (Preview)
Co-authored-by: Ron Pressler <rpressler@openjdk.org> Co-authored-by: Alan Bateman <alanb@openjdk.org> Co-authored-by: Erik Österlund <eosterlund@openjdk.org> Co-authored-by: Andrew Haley <aph@openjdk.org> Co-authored-by: Rickard Bäckman <rbackman@openjdk.org> Co-authored-by: Markus Grönlund <mgronlun@openjdk.org> Co-authored-by: Leonid Mesnik <lmesnik@openjdk.org> Co-authored-by: Serguei Spitsyn <sspitsyn@openjdk.org> Co-authored-by: Chris Plummer <cjplummer@openjdk.org> Co-authored-by: Coleen Phillimore <coleenp@openjdk.org> Co-authored-by: Robbin Ehn <rehn@openjdk.org> Co-authored-by: Stefan Karlsson <stefank@openjdk.org> Co-authored-by: Thomas Schatzl <tschatzl@openjdk.org> Co-authored-by: Sergey Kuksenko <skuksenko@openjdk.org> Reviewed-by: lancea, eosterlund, rehn, sspitsyn, stefank, tschatzl, dfuchs, lmesnik, dcubed, kevinw, amenkov, dlong, mchung, psandoz, bpb, coleenp, smarks, egahlin, mseledtsov, coffeys, darcy
This commit is contained in:
parent
5212535a27
commit
9583e3657e
1133 changed files with 95935 additions and 8335 deletions
|
@ -29,11 +29,8 @@ import java.io.IOException;
|
|||
import java.io.UncheckedIOException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.MulticastChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import sun.net.NetProperties;
|
||||
import sun.nio.ch.DefaultSelectorProvider;
|
||||
|
||||
/**
|
||||
|
@ -666,17 +663,33 @@ public class DatagramSocket implements java.io.Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Receives a datagram packet from this socket. When this method
|
||||
* returns, the {@code DatagramPacket}'s buffer is filled with
|
||||
* the data received. The datagram packet also contains the sender's
|
||||
* Receives a datagram packet from this socket. This method blocks until a
|
||||
* datagram is received.
|
||||
*
|
||||
* When this method returns, the {@code DatagramPacket}'s buffer is filled
|
||||
* with the data received. The datagram packet also contains the sender's
|
||||
* IP address, and the port number on the sender's machine.
|
||||
* <p>
|
||||
* This method blocks until a datagram is received. The
|
||||
* {@code length} field of the datagram packet object contains
|
||||
* The {@code length} field of the datagram packet object contains
|
||||
* the length of the received message. If the message is longer than
|
||||
* the packet's length, the message is truncated.
|
||||
* <p>
|
||||
* If there is a security manager, and the socket is not currently
|
||||
*
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
* <li> The datagram socket is {@linkplain DatagramChannel#socket() associated}
|
||||
* with a {@link DatagramChannel DatagramChannel}. In that case,
|
||||
* interrupting a thread receiving a datagram packet will close the
|
||||
* underlying channel and cause this method to throw {@link
|
||||
* java.nio.channels.ClosedByInterruptException} with the interrupt
|
||||
* status set.
|
||||
* <li> The datagram socket uses the system-default socket implementation and
|
||||
* a {@linkplain Thread#isVirtual() virtual thread} is receiving a
|
||||
* datagram packet. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. This method will then throw
|
||||
* {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* <p> If there is a security manager, and the socket is not currently
|
||||
* connected to a remote address, a packet cannot be received if the
|
||||
* security manager's {@code checkAccept} method does not allow it.
|
||||
* Datagrams that are not permitted by the security manager are silently
|
||||
|
|
|
@ -55,10 +55,10 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import jdk.internal.access.JavaNetInetAddressAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.net.ResolverProviderConfiguration;
|
||||
import sun.security.action.*;
|
||||
|
@ -972,6 +972,7 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
|
|||
// in cache when the result is obtained
|
||||
private static final class NameServiceAddresses implements Addresses {
|
||||
private final String host;
|
||||
private final ReentrantLock lookupLock = new ReentrantLock();
|
||||
|
||||
NameServiceAddresses(String host) {
|
||||
this.host = host;
|
||||
|
@ -982,7 +983,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
|
|||
Addresses addresses;
|
||||
// only one thread is doing lookup to name service
|
||||
// for particular host at any time.
|
||||
synchronized (this) {
|
||||
lookupLock.lock();
|
||||
try {
|
||||
// re-check that we are still us + re-install us if slot empty
|
||||
addresses = cache.putIfAbsent(host, this);
|
||||
if (addresses == null) {
|
||||
|
@ -1030,6 +1032,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
|
|||
return inetAddresses;
|
||||
}
|
||||
// else addresses != this
|
||||
} finally {
|
||||
lookupLock.unlock();
|
||||
}
|
||||
// delegate to different addresses when we are already replaced
|
||||
// but outside of synchronized block to avoid any chance of dead-locking
|
||||
|
@ -1049,16 +1053,27 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
|
|||
throws UnknownHostException {
|
||||
Objects.requireNonNull(host);
|
||||
Objects.requireNonNull(policy);
|
||||
return Arrays.stream(impl.lookupAllHostAddr(host, policy));
|
||||
InetAddress[] addrs;
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
addrs = impl.lookupAllHostAddr(host, policy);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
return Arrays.stream(addrs);
|
||||
}
|
||||
|
||||
public String lookupByAddress(byte[] addr)
|
||||
throws UnknownHostException {
|
||||
public String lookupByAddress(byte[] addr) throws UnknownHostException {
|
||||
Objects.requireNonNull(addr);
|
||||
if (addr.length != Inet4Address.INADDRSZ && addr.length != Inet6Address.INADDRSZ) {
|
||||
throw new IllegalArgumentException("Invalid address length");
|
||||
}
|
||||
return impl.getHostByAddr(addr);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return impl.getHostByAddr(addr);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2022, 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
|
||||
|
@ -121,11 +121,10 @@ public class MulticastSocket extends DatagramSocket {
|
|||
* Create a MulticastSocket that delegates to the given delegate if not null.
|
||||
* @param delegate the delegate, can be null.
|
||||
*/
|
||||
MulticastSocket(MulticastSocket delegate) {
|
||||
MulticastSocket(MulticastSocket delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a multicast socket and binds it to any available port
|
||||
* on the local host machine. The socket will be bound to the
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2022, 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
|
||||
|
@ -27,6 +27,7 @@ package java.net;
|
|||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -481,7 +482,6 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @see SecurityManager#checkConnect
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
if (!isBound())
|
||||
return null;
|
||||
|
@ -492,7 +492,23 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* Listens for a connection to be made to this socket and accepts
|
||||
* it. The method blocks until a connection is made.
|
||||
*
|
||||
* <p>A new Socket {@code s} is created and, if there
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
* <li> The socket is {@linkplain ServerSocketChannel#socket() associated}
|
||||
* with a {@link ServerSocketChannel ServerSocketChannel}. In that
|
||||
* case, interrupting a thread accepting a connection will close the
|
||||
* underlying channel and cause this method to throw {@link
|
||||
* java.nio.channels.ClosedByInterruptException} with the interrupt
|
||||
* status set.
|
||||
* <li> The socket uses the system-default socket implementation and a
|
||||
* {@linkplain Thread#isVirtual() virtual thread} is accepting a
|
||||
* connection. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. This method will then throw
|
||||
* {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* <p> A new Socket {@code s} is created and, if there
|
||||
* is a security manager,
|
||||
* the security manager's {@code checkAccept} method is called
|
||||
* with {@code s.getInetAddress().getHostAddress()} and
|
||||
|
@ -670,7 +686,18 @@ public class ServerSocket implements java.io.Closeable {
|
|||
assert !(si instanceof DelegatingSocketImpl);
|
||||
|
||||
// accept a connection
|
||||
impl.accept(si);
|
||||
try {
|
||||
impl.accept(si);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw e;
|
||||
} catch (InterruptedIOException e) {
|
||||
Thread thread = Thread.currentThread();
|
||||
if (thread.isVirtual() && thread.isInterrupted()) {
|
||||
close();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// check permission, close SocketImpl/connection if denied
|
||||
@SuppressWarnings("removal")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2022, 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
|
||||
|
@ -28,10 +28,12 @@ package java.net;
|
|||
import sun.security.util.SecurityConstants;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -570,6 +572,21 @@ public class Socket implements java.io.Closeable {
|
|||
/**
|
||||
* Connects this socket to the server.
|
||||
*
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
* <li> The socket is {@linkplain SocketChannel#socket() associated} with
|
||||
* a {@link SocketChannel SocketChannel}.
|
||||
* In that case, interrupting a thread establishing a connection will
|
||||
* close the underlying channel and cause this method to throw
|
||||
* {@link ClosedByInterruptException} with the interrupt status set.
|
||||
* <li> The socket uses the system-default socket implementation and a
|
||||
* {@linkplain Thread#isVirtual() virtual thread} is establishing a
|
||||
* connection. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. This method will then throw
|
||||
* {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* @param endpoint the {@code SocketAddress}
|
||||
* @throws IOException if an error occurs during the connection
|
||||
* @throws java.nio.channels.IllegalBlockingModeException
|
||||
|
@ -588,6 +605,21 @@ public class Socket implements java.io.Closeable {
|
|||
* A timeout of zero is interpreted as an infinite timeout. The connection
|
||||
* will then block until established or an error occurs.
|
||||
*
|
||||
* <p> This method is {@linkplain Thread#interrupt() interruptible} in the
|
||||
* following circumstances:
|
||||
* <ol>
|
||||
* <li> The socket is {@linkplain SocketChannel#socket() associated} with
|
||||
* a {@link SocketChannel SocketChannel}.
|
||||
* In that case, interrupting a thread establishing a connection will
|
||||
* close the underlying channel and cause this method to throw
|
||||
* {@link ClosedByInterruptException} with the interrupt status set.
|
||||
* <li> The socket uses the system-default socket implementation and a
|
||||
* {@linkplain Thread#isVirtual() virtual thread} is establishing a
|
||||
* connection. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. This method will then throw
|
||||
* {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* @param endpoint the {@code SocketAddress}
|
||||
* @param timeout the timeout value to be used in milliseconds.
|
||||
* @throws IOException if an error occurs during the connection
|
||||
|
@ -630,7 +662,18 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
if (!created)
|
||||
createImpl(true);
|
||||
impl.connect(epoint, timeout);
|
||||
try {
|
||||
impl.connect(epoint, timeout);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw e;
|
||||
} catch (InterruptedIOException e) {
|
||||
Thread thread = Thread.currentThread();
|
||||
if (thread.isVirtual() && thread.isInterrupted()) {
|
||||
close();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
connected = true;
|
||||
/*
|
||||
* If the socket was not bound before the connect, it is now because
|
||||
|
@ -886,6 +929,22 @@ public class Socket implements java.io.Closeable {
|
|||
* is in non-blocking mode then the input stream's {@code read} operations
|
||||
* will throw an {@link java.nio.channels.IllegalBlockingModeException}.
|
||||
*
|
||||
* <p> Reading from the input stream is {@linkplain Thread#interrupt()
|
||||
* interruptible} in the following circumstances:
|
||||
* <ol>
|
||||
* <li> The socket is {@linkplain SocketChannel#socket() associated} with
|
||||
* a {@link SocketChannel SocketChannel}.
|
||||
* In that case, interrupting a thread reading from the input stream
|
||||
* will close the underlying channel and cause the read method to
|
||||
* throw {@link ClosedByInterruptException} with the interrupt
|
||||
* status set.
|
||||
* <li> The socket uses the system-default socket implementation and a
|
||||
* {@linkplain Thread#isVirtual() virtual thread} is reading from the
|
||||
* input stream. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. The read method will then
|
||||
* throw {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* <p>Under abnormal conditions the underlying connection may be
|
||||
* broken by the remote host or the network software (for example
|
||||
* a connection reset in the case of TCP connections). When a
|
||||
|
@ -950,7 +1009,6 @@ public class Socket implements java.io.Closeable {
|
|||
private static class SocketInputStream extends InputStream {
|
||||
private final Socket parent;
|
||||
private final InputStream in;
|
||||
|
||||
SocketInputStream(Socket parent, InputStream in) {
|
||||
this.parent = parent;
|
||||
this.in = in;
|
||||
|
@ -963,13 +1021,23 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return in.read(b, off, len);
|
||||
try {
|
||||
return in.read(b, off, len);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw e;
|
||||
} catch (InterruptedIOException e) {
|
||||
Thread thread = Thread.currentThread();
|
||||
if (thread.isVirtual() && thread.isInterrupted()) {
|
||||
close();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return in.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parent.close();
|
||||
|
@ -985,6 +1053,22 @@ public class Socket implements java.io.Closeable {
|
|||
* operations will throw an {@link
|
||||
* java.nio.channels.IllegalBlockingModeException}.
|
||||
*
|
||||
* <p> Writing to the output stream is {@linkplain Thread#interrupt()
|
||||
* interruptible} in the following circumstances:
|
||||
* <ol>
|
||||
* <li> The socket is {@linkplain SocketChannel#socket() associated} with
|
||||
* a {@link SocketChannel SocketChannel}.
|
||||
* In that case, interrupting a thread writing to the output stream
|
||||
* will close the underlying channel and cause the write method to
|
||||
* throw {@link ClosedByInterruptException} with the interrupt status
|
||||
* set.
|
||||
* <li> The socket uses the system-default socket implementation and a
|
||||
* {@linkplain Thread#isVirtual() virtual thread} is writing to the
|
||||
* output stream. In that case, interrupting the virtual thread will
|
||||
* cause it to wakeup and close the socket. The write method will then
|
||||
* throw {@code SocketException} with the interrupt status set.
|
||||
* </ol>
|
||||
*
|
||||
* <p> Closing the returned {@link java.io.OutputStream OutputStream}
|
||||
* will close the associated socket.
|
||||
*
|
||||
|
@ -1032,9 +1116,17 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
try {
|
||||
out.write(b, off, len);
|
||||
} catch (InterruptedIOException e) {
|
||||
Thread thread = Thread.currentThread();
|
||||
if (thread.isVirtual() && thread.isInterrupted()) {
|
||||
close();
|
||||
throw new SocketException("Closed by interrupt");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parent.close();
|
||||
|
|
|
@ -45,6 +45,7 @@ import java.util.ServiceLoader;
|
|||
|
||||
import jdk.internal.access.JavaNetURLAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.ThreadTracker;
|
||||
import jdk.internal.misc.VM;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
@ -1342,15 +1343,24 @@ public final class URL implements java.io.Serializable {
|
|||
};
|
||||
}
|
||||
|
||||
// Thread-local gate to prevent recursive provider lookups
|
||||
private static ThreadLocal<Object> gate = new ThreadLocal<>();
|
||||
private static class ThreadTrackHolder {
|
||||
static final ThreadTracker TRACKER = new ThreadTracker();
|
||||
}
|
||||
|
||||
private static Object tryBeginLookup() {
|
||||
return ThreadTrackHolder.TRACKER.tryBegin();
|
||||
}
|
||||
|
||||
private static void endLookup(Object key) {
|
||||
ThreadTrackHolder.TRACKER.end(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static URLStreamHandler lookupViaProviders(final String protocol) {
|
||||
if (gate.get() != null)
|
||||
Object key = tryBeginLookup();
|
||||
if (key == null) {
|
||||
throw new Error("Circular loading of URL stream handler providers detected");
|
||||
|
||||
gate.set(gate);
|
||||
}
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
|
@ -1366,7 +1376,7 @@ public final class URL implements java.io.Serializable {
|
|||
}
|
||||
});
|
||||
} finally {
|
||||
gate.set(null);
|
||||
endLookup(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue