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) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -25,6 +25,10 @@
package java.io;
import java.util.Arrays;
import java.util.Objects;
import jdk.internal.misc.InternalLock;
import jdk.internal.misc.VM;
/**
* Writes text to a character-output stream, buffering characters so as to
@ -64,13 +68,40 @@ package java.io;
*/
public class BufferedWriter extends Writer {
private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
private static final int DEFAULT_MAX_BUFFER_SIZE = 8192;
private Writer out;
private char cb[];
private int nChars, nextChar;
private final int maxChars; // maximum number of buffers chars
private static int defaultCharBufferSize = 8192;
/**
* Returns the buffer size to use when no output buffer size specified
*/
private static int initialBufferSize() {
if (VM.isBooted() && Thread.currentThread().isVirtual()) {
return DEFAULT_INITIAL_BUFFER_SIZE;
} else {
return DEFAULT_MAX_BUFFER_SIZE;
}
}
/**
* Creates a buffered character-output stream.
*/
private BufferedWriter(Writer out, int initialSize, int maxSize) {
super(out);
if (initialSize <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
this.out = out;
this.cb = new char[initialSize];
this.nChars = initialSize;
this.maxChars = maxSize;
}
/**
* Creates a buffered character-output stream that uses a default-sized
@ -79,7 +110,7 @@ public class BufferedWriter extends Writer {
* @param out A Writer
*/
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
this(out, initialBufferSize(), DEFAULT_MAX_BUFFER_SIZE);
}
/**
@ -92,13 +123,7 @@ public class BufferedWriter extends Writer {
* @throws IllegalArgumentException If {@code sz <= 0}
*/
public BufferedWriter(Writer out, int sz) {
super(out);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.out = out;
cb = new char[sz];
nChars = sz;
nextChar = 0;
this(out, sz, sz);
}
/** Checks to make sure that the stream has not been closed */
@ -107,35 +132,82 @@ public class BufferedWriter extends Writer {
throw new IOException("Stream closed");
}
/**
* Grow char array to fit an additional len characters if needed.
* If possible, it grows by len+1 to avoid flushing when len chars
* are added.
*
* This method should only be called while holding the lock.
*/
private void growIfNeeded(int len) {
int neededSize = nextChar + len + 1;
if (neededSize < 0)
neededSize = Integer.MAX_VALUE;
if (neededSize > nChars && nChars < maxChars) {
int newSize = min(neededSize, maxChars);
cb = Arrays.copyOf(cb, newSize);
nChars = newSize;
}
}
/**
* Flushes the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
*/
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implFlushBuffer();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implFlushBuffer();
}
}
}
private void implFlushBuffer() throws IOException {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
/**
* Writes a single character.
*
* @throws IOException If an I/O error occurs
*/
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implWrite(c);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implWrite(c);
}
}
}
private void implWrite(int c) throws IOException {
ensureOpen();
growIfNeeded(1);
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
/**
* Our own little min method, to avoid loading java.lang.Math if we've run
* out of file descriptors and we're trying to print a stack trace.
@ -167,32 +239,46 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs
*/
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 {
implWrite(cbuf, off, len);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implWrite(cbuf, off, len);
}
}
}
if (len >= nChars) {
/* If the request length exceeds the size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
private void implWrite(char[] cbuf, int off, int len) throws IOException {
ensureOpen();
Objects.checkFromIndexSize(off, len, cbuf.length);
if (len == 0) {
return;
}
if (len >= maxChars) {
/* If the request length exceeds the max size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
flushBuffer();
out.write(cbuf, off, len);
return;
}
growIfNeeded(len);
int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
System.arraycopy(cbuf, b, cb, nextChar, d);
b += d;
nextChar += d;
if (nextChar >= nChars) {
flushBuffer();
out.write(cbuf, off, len);
return;
}
int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
System.arraycopy(cbuf, b, cb, nextChar, d);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
}
}
}
@ -220,18 +306,32 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs
*/
public void write(String s, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implWrite(s, off, len);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implWrite(s, off, len);
}
}
}
private void implWrite(String s, int off, int len) throws IOException {
ensureOpen();
growIfNeeded(len);
int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
}
}
@ -252,24 +352,52 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs
*/
public void flush() throws IOException {
synchronized (lock) {
flushBuffer();
out.flush();
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implFlush();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implFlush();
}
}
}
private void implFlush() throws IOException {
flushBuffer();
out.flush();
}
public void close() throws IOException {
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
implClose();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
implClose();
}
}
}
@SuppressWarnings("try")
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try (Writer w = out) {
flushBuffer();
} finally {
out = null;
cb = null;
}
private void implClose() throws IOException {
if (out == null) {
return;
}
try (Writer w = out) {
flushBuffer();
} finally {
out = null;
cb = null;
}
}
}