mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue