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:
Alan Bateman 2022-05-07 08:06:16 +00:00
parent 5212535a27
commit 9583e3657e
1133 changed files with 95935 additions and 8335 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -42,6 +42,7 @@ import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import jdk.internal.misc.InternalLock;
public class StreamDecoder extends Reader {
@ -122,89 +123,145 @@ public class StreamDecoder extends Reader {
return read0();
}
@SuppressWarnings("fallthrough")
private int read0() throws IOException {
synchronized (lock) {
// Return the leftover char, if there is one
if (haveLeftoverChar) {
haveLeftoverChar = false;
return leftoverChar;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
return lockedRead0();
} finally {
locker.unlock();
}
// Convert more bytes
char[] cb = new char[2];
int n = read(cb, 0, 2);
switch (n) {
case -1:
return -1;
case 2:
leftoverChar = cb[1];
haveLeftoverChar = true;
// FALL THROUGH
case 1:
return cb[0];
default:
assert false : n;
return -1;
} else {
synchronized (lock) {
return lockedRead0();
}
}
}
@SuppressWarnings("fallthrough")
private int lockedRead0() throws IOException {
// Return the leftover char, if there is one
if (haveLeftoverChar) {
haveLeftoverChar = false;
return leftoverChar;
}
// Convert more bytes
char[] cb = new char[2];
int n = read(cb, 0, 2);
switch (n) {
case -1:
return -1;
case 2:
leftoverChar = cb[1];
haveLeftoverChar = true;
// FALL THROUGH
case 1:
return cb[0];
default:
assert false : n;
return -1;
}
}
public int read(char[] cbuf, int offset, int length) throws IOException {
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
return lockedRead(cbuf, offset, length);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return lockedRead(cbuf, offset, length);
}
}
}
private int lockedRead(char[] cbuf, int offset, int length) throws IOException {
int off = offset;
int len = length;
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
return n + implRead(cbuf, off, off + len);
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
return n + implRead(cbuf, off, off + len);
}
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return haveLeftoverChar || implReady();
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
return lockedReady();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return lockedReady();
}
}
}
private boolean lockedReady() throws IOException {
ensureOpen();
return haveLeftoverChar || implReady();
}
public void close() throws IOException {
synchronized (lock) {
if (closed)
return;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implClose();
lockedClose();
} finally {
closed = true;
locker.unlock();
}
} else {
synchronized (lock) {
lockedClose();
}
}
}
private void lockedClose() throws IOException {
if (closed)
return;
try {
implClose();
} finally {
closed = true;
}
}
@ -236,7 +293,7 @@ public class StreamDecoder extends Reader {
this.decoder = dec;
this.in = in;
this.ch = null;
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
bb.flip(); // So that bb is initially empty
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -38,11 +38,12 @@ import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import jdk.internal.misc.InternalLock;
public class StreamEncoder extends Writer
{
public final class StreamEncoder extends Writer {
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
private static final int INITIAL_BYTE_BUFFER_CAPACITY = 512;
private static final int MAX_BYTE_BUFFER_CAPACITY = 8192;
private volatile boolean closed;
@ -106,14 +107,28 @@ public class StreamEncoder extends Writer
}
public void flushBuffer() throws IOException {
synchronized (lock) {
if (isOpen())
implFlushBuffer();
else
throw new IOException("Stream closed");
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
lockedFlushBuffer();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedFlushBuffer();
}
}
}
private void lockedFlushBuffer() throws IOException {
if (isOpen())
implFlushBuffer();
else
throw new IOException("Stream closed");
}
public void write(int c) throws IOException {
char[] cbuf = new char[1];
cbuf[0] = (char) c;
@ -121,18 +136,32 @@ public class StreamEncoder extends Writer
}
public void write(char[] cbuf, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
lockedWrite(cbuf, off, len);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedWrite(cbuf, off, len);
}
implWrite(cbuf, off, len);
}
}
private void lockedWrite(char[] cbuf, int off, int len) throws IOException {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
implWrite(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
/* Check the len before creating a char buffer */
if (len < 0)
@ -145,31 +174,73 @@ public class StreamEncoder extends Writer
public void write(CharBuffer cb) throws IOException {
int position = cb.position();
try {
synchronized (lock) {
ensureOpen();
implWrite(cb);
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
lockedWrite(cb);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedWrite(cb);
}
}
} finally {
cb.position(position);
}
}
private void lockedWrite(CharBuffer cb) throws IOException {
ensureOpen();
implWrite(cb);
}
public void flush() throws IOException {
synchronized (lock) {
ensureOpen();
implFlush();
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
lockedFlush();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedFlush();
}
}
}
private void lockedFlush() throws IOException {
ensureOpen();
implFlush();
}
public void close() throws IOException {
synchronized (lock) {
if (closed)
return;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implClose();
lockedClose();
} finally {
closed = true;
locker.unlock();
}
} else {
synchronized (lock) {
lockedClose();
}
}
}
private void lockedClose() throws IOException {
if (closed)
return;
try {
implClose();
} finally {
closed = true;
}
}
@ -182,7 +253,8 @@ public class StreamEncoder extends Writer
private final Charset cs;
private final CharsetEncoder encoder;
private final ByteBuffer bb;
private ByteBuffer bb;
private final int maxBufferCapacity;
// Exactly one of these is non-null
private final OutputStream out;
@ -206,7 +278,9 @@ public class StreamEncoder extends Writer
this.ch = null;
this.cs = enc.charset();
this.encoder = enc;
this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
}
private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
@ -214,9 +288,14 @@ public class StreamEncoder extends Writer
this.ch = ch;
this.cs = enc.charset();
this.encoder = enc;
this.bb = ByteBuffer.allocate(mbc < 0
? DEFAULT_BYTE_BUFFER_SIZE
: mbc);
if (mbc > 0) {
this.bb = ByteBuffer.allocate(mbc);
this.maxBufferCapacity = mbc;
} else {
this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
}
}
private void writeBytes() throws IOException {
@ -289,6 +368,8 @@ public class StreamEncoder extends Writer
flushLeftoverChar(cb, false);
}
growByteBufferIfNeeded(cb.remaining());
while (cb.hasRemaining()) {
CoderResult cr = encoder.encode(cb, bb, false);
if (cr.isUnderflow()) {
@ -308,6 +389,21 @@ public class StreamEncoder extends Writer
}
}
/**
* Grows bb to a capacity to allow len characters be encoded.
*/
void growByteBufferIfNeeded(int len) throws IOException {
int cap = bb.capacity();
if (cap < maxBufferCapacity) {
int maxBytes = len * Math.round(encoder.maxBytesPerChar());
int newCap = Math.min(maxBytes, maxBufferCapacity);
if (newCap > cap) {
implFlushBuffer();
bb = ByteBuffer.allocate(newCap);
}
}
}
void implFlushBuffer() throws IOException {
if (bb.position() > 0) {
writeBytes();