mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +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) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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,7 @@
|
|||
|
||||
package java.io;
|
||||
|
||||
import jdk.internal.misc.InternalLock;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
|
@ -63,6 +64,9 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
private static final long BUF_OFFSET
|
||||
= U.objectFieldOffset(BufferedInputStream.class, "buf");
|
||||
|
||||
// initialized to null when BufferedInputStream is sub-classed
|
||||
private final InternalLock lock;
|
||||
|
||||
/**
|
||||
* The internal buffer array where the data is stored. When necessary,
|
||||
* it may be replaced by another array of
|
||||
|
@ -199,12 +203,19 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
throw new IllegalArgumentException("Buffer size <= 0");
|
||||
}
|
||||
buf = new byte[size];
|
||||
|
||||
// use monitors when BufferedInputStream is sub-classed
|
||||
if (getClass() == BufferedInputStream.class) {
|
||||
lock = InternalLock.newLockOrNull();
|
||||
} else {
|
||||
lock = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the buffer with more data, taking into account
|
||||
* shuffling and other tricks for dealing with marks.
|
||||
* Assumes that it is being called by a synchronized method.
|
||||
* Assumes that it is being called by a locked method.
|
||||
* This method also assumes that all data has already been read in,
|
||||
* hence pos > count.
|
||||
*/
|
||||
|
@ -258,7 +269,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* or an I/O error occurs.
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public synchronized int read() throws IOException {
|
||||
public int read() throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
return implRead();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
return implRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int implRead() throws IOException {
|
||||
if (pos >= count) {
|
||||
fill();
|
||||
if (pos >= count)
|
||||
|
@ -328,9 +354,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* invoking its {@link #close()} method,
|
||||
* or an I/O error occurs.
|
||||
*/
|
||||
public synchronized int read(byte[] b, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
return implRead(b, off, len);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
return implRead(b, off, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int implRead(byte[] b, int off, int len) throws IOException {
|
||||
getBufIfOpen(); // Check for closed stream
|
||||
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
@ -362,7 +401,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* {@code in.skip(n)} throws an IOException,
|
||||
* or an I/O error occurs.
|
||||
*/
|
||||
public synchronized long skip(long n) throws IOException {
|
||||
public long skip(long n) throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
return implSkip(n);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
return implSkip(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long implSkip(long n) throws IOException {
|
||||
getBufIfOpen(); // Check for closed stream
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
|
@ -403,7 +457,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* invoking its {@link #close()} method,
|
||||
* or an I/O error occurs.
|
||||
*/
|
||||
public synchronized int available() throws IOException {
|
||||
public int available() throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
return implAvailable();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
return implAvailable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int implAvailable() throws IOException {
|
||||
int n = count - pos;
|
||||
int avail = getInIfOpen().available();
|
||||
return n > (Integer.MAX_VALUE - avail)
|
||||
|
@ -419,7 +488,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* the mark position becomes invalid.
|
||||
* @see java.io.BufferedInputStream#reset()
|
||||
*/
|
||||
public synchronized void mark(int readlimit) {
|
||||
public void mark(int readlimit) {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implMark(readlimit);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implMark(readlimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implMark(int readlimit) {
|
||||
marklimit = readlimit;
|
||||
markpos = pos;
|
||||
}
|
||||
|
@ -440,7 +524,22 @@ public class BufferedInputStream extends FilterInputStream {
|
|||
* method, or an I/O error occurs.
|
||||
* @see java.io.BufferedInputStream#mark(int)
|
||||
*/
|
||||
public synchronized void reset() throws IOException {
|
||||
public void reset() throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implReset();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implReset() throws IOException {
|
||||
getBufIfOpen(); // Cause exception if closed
|
||||
if (markpos < 0)
|
||||
throw new IOException("Resetting to invalid mark");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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 jdk.internal.misc.InternalLock;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
/**
|
||||
* The class implements a buffered output stream. By setting up such
|
||||
* an output stream, an application can write bytes to the underlying
|
||||
|
@ -35,6 +39,12 @@ package java.io;
|
|||
* @since 1.0
|
||||
*/
|
||||
public class BufferedOutputStream extends FilterOutputStream {
|
||||
private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
|
||||
private static final int DEFAULT_MAX_BUFFER_SIZE = 8192;
|
||||
|
||||
// initialized to null when BufferedOutputStream is sub-classed
|
||||
private final InternalLock lock;
|
||||
|
||||
/**
|
||||
* The internal buffer where data is stored.
|
||||
*/
|
||||
|
@ -48,6 +58,44 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
*/
|
||||
protected int count;
|
||||
|
||||
/**
|
||||
* Max size of the internal buffer.
|
||||
*/
|
||||
private final int maxBufSize;
|
||||
|
||||
/**
|
||||
* 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 new buffered output stream.
|
||||
*/
|
||||
private BufferedOutputStream(OutputStream out, int initialSize, int maxSize) {
|
||||
super(out);
|
||||
|
||||
if (initialSize <= 0) {
|
||||
throw new IllegalArgumentException("Buffer size <= 0");
|
||||
}
|
||||
|
||||
if (getClass() == BufferedOutputStream.class) {
|
||||
// use InternalLock and resizable buffer when not sub-classed
|
||||
this.lock = InternalLock.newLockOrNull();
|
||||
this.buf = new byte[initialSize]; // resizable
|
||||
} else {
|
||||
// use monitors and no resizing when sub-classed
|
||||
this.lock = null;
|
||||
this.buf = new byte[maxSize];
|
||||
}
|
||||
this.maxBufSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new buffered output stream to write data to the
|
||||
* specified underlying output stream.
|
||||
|
@ -55,7 +103,7 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
* @param out the underlying output stream.
|
||||
*/
|
||||
public BufferedOutputStream(OutputStream out) {
|
||||
this(out, 8192);
|
||||
this(out, initialBufferSize(), DEFAULT_MAX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,11 +116,7 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
* @throws IllegalArgumentException if size <= 0.
|
||||
*/
|
||||
public BufferedOutputStream(OutputStream out, int size) {
|
||||
super(out);
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("Buffer size <= 0");
|
||||
}
|
||||
buf = new byte[size];
|
||||
this(out, size, size);
|
||||
}
|
||||
|
||||
/** Flush the internal buffer */
|
||||
|
@ -83,6 +127,24 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow buf to fit an additional len bytes if needed.
|
||||
* If possible, it grows by len+1 to avoid flushing when len bytes
|
||||
* are added. A no-op if the buffer is not resizable.
|
||||
*
|
||||
* This method should only be called while holding the lock.
|
||||
*/
|
||||
private void growIfNeeded(int len) {
|
||||
int neededSize = count + len + 1;
|
||||
if (neededSize < 0)
|
||||
neededSize = Integer.MAX_VALUE;
|
||||
int bufSize = buf.length;
|
||||
if (neededSize > bufSize && bufSize < maxBufSize) {
|
||||
int newSize = Math.min(neededSize, maxBufSize);
|
||||
buf = Arrays.copyOf(buf, newSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this buffered output stream.
|
||||
*
|
||||
|
@ -90,7 +152,23 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void write(int b) throws IOException {
|
||||
public void write(int b) throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(b);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implWrite(int b) throws IOException {
|
||||
growIfNeeded(1);
|
||||
if (count >= buf.length) {
|
||||
flushBuffer();
|
||||
}
|
||||
|
@ -114,15 +192,31 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void write(byte[] b, int off, int len) throws IOException {
|
||||
if (len >= buf.length) {
|
||||
/* If the request length exceeds the size of the output buffer,
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(b, off, len);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(b, off, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implWrite(byte[] b, int off, int len) throws IOException {
|
||||
if (len >= maxBufSize) {
|
||||
/* If the request length exceeds the max size of the output buffer,
|
||||
flush the output buffer and then write the data directly.
|
||||
In this way buffered streams will cascade harmlessly. */
|
||||
flushBuffer();
|
||||
out.write(b, off, len);
|
||||
return;
|
||||
}
|
||||
growIfNeeded(len);
|
||||
if (len > buf.length - count) {
|
||||
flushBuffer();
|
||||
}
|
||||
|
@ -138,7 +232,22 @@ public class BufferedOutputStream extends FilterOutputStream {
|
|||
* @see java.io.FilterOutputStream#out
|
||||
*/
|
||||
@Override
|
||||
public synchronized void flush() throws IOException {
|
||||
public void flush() throws IOException {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implFlush();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implFlush() throws IOException {
|
||||
flushBuffer();
|
||||
out.flush();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2021, 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,7 +25,6 @@
|
|||
|
||||
package java.io;
|
||||
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
@ -33,6 +32,7 @@ import java.util.Spliterator;
|
|||
import java.util.Spliterators;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* Reads text from a character-input stream, buffering characters so as to
|
||||
|
@ -69,7 +69,6 @@ import java.util.stream.StreamSupport;
|
|||
*/
|
||||
|
||||
public class BufferedReader extends Reader {
|
||||
|
||||
private Reader in;
|
||||
|
||||
private char[] cb;
|
||||
|
@ -176,23 +175,37 @@ public class BufferedReader extends Reader {
|
|||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
for (;;) {
|
||||
if (nextChar >= nChars) {
|
||||
fill();
|
||||
if (nextChar >= nChars)
|
||||
return -1;
|
||||
}
|
||||
if (skipLF) {
|
||||
skipLF = false;
|
||||
if (cb[nextChar] == '\n') {
|
||||
nextChar++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return cb[nextChar++];
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implRead();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int implRead() throws IOException {
|
||||
ensureOpen();
|
||||
for (;;) {
|
||||
if (nextChar >= nChars) {
|
||||
fill();
|
||||
if (nextChar >= nChars)
|
||||
return -1;
|
||||
}
|
||||
if (skipLF) {
|
||||
skipLF = false;
|
||||
if (cb[nextChar] == '\n') {
|
||||
nextChar++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return cb[nextChar++];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,24 +290,38 @@ public class BufferedReader extends Reader {
|
|||
* @throws IOException {@inheritDoc}
|
||||
*/
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
Objects.checkFromIndexSize(off, len, cbuf.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implRead(cbuf, off, len);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
|
||||
int n = read1(cbuf, off, len);
|
||||
if (n <= 0) return n;
|
||||
while ((n < len) && in.ready()) {
|
||||
int n1 = read1(cbuf, off + n, len - n);
|
||||
if (n1 <= 0) break;
|
||||
n += n1;
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implRead(cbuf, off, len);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
private int implRead(char[] cbuf, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
Objects.checkFromIndexSize(off, len, cbuf.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = read1(cbuf, off, len);
|
||||
if (n <= 0) return n;
|
||||
while ((n < len) && in.ready()) {
|
||||
int n1 = read1(cbuf, off + n, len - n);
|
||||
if (n1 <= 0) break;
|
||||
n += n1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line of text. A line is considered to be terminated by any one
|
||||
* of a line feed ('\n'), a carriage return ('\r'), a carriage return
|
||||
|
@ -314,67 +341,81 @@ public class BufferedReader extends Reader {
|
|||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
String readLine(boolean ignoreLF, boolean[] term) throws IOException {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implReadLine(ignoreLF, term);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implReadLine(ignoreLF, term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String implReadLine(boolean ignoreLF, boolean[] term) throws IOException {
|
||||
StringBuilder s = null;
|
||||
int startChar;
|
||||
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
boolean omitLF = ignoreLF || skipLF;
|
||||
if (term != null) term[0] = false;
|
||||
ensureOpen();
|
||||
boolean omitLF = ignoreLF || skipLF;
|
||||
if (term != null) term[0] = false;
|
||||
|
||||
bufferLoop:
|
||||
for (;;) {
|
||||
bufferLoop:
|
||||
for (;;) {
|
||||
|
||||
if (nextChar >= nChars)
|
||||
fill();
|
||||
if (nextChar >= nChars) { /* EOF */
|
||||
if (s != null && s.length() > 0)
|
||||
return s.toString();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
boolean eol = false;
|
||||
char c = 0;
|
||||
int i;
|
||||
|
||||
/* Skip a leftover '\n', if necessary */
|
||||
if (omitLF && (cb[nextChar] == '\n'))
|
||||
nextChar++;
|
||||
skipLF = false;
|
||||
omitLF = false;
|
||||
|
||||
charLoop:
|
||||
for (i = nextChar; i < nChars; i++) {
|
||||
c = cb[i];
|
||||
if ((c == '\n') || (c == '\r')) {
|
||||
if (term != null) term[0] = true;
|
||||
eol = true;
|
||||
break charLoop;
|
||||
}
|
||||
}
|
||||
|
||||
startChar = nextChar;
|
||||
nextChar = i;
|
||||
|
||||
if (eol) {
|
||||
String str;
|
||||
if (s == null) {
|
||||
str = new String(cb, startChar, i - startChar);
|
||||
} else {
|
||||
s.append(cb, startChar, i - startChar);
|
||||
str = s.toString();
|
||||
}
|
||||
nextChar++;
|
||||
if (c == '\r') {
|
||||
skipLF = true;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
if (s == null)
|
||||
s = new StringBuilder(defaultExpectedLineLength);
|
||||
s.append(cb, startChar, i - startChar);
|
||||
if (nextChar >= nChars)
|
||||
fill();
|
||||
if (nextChar >= nChars) { /* EOF */
|
||||
if (s != null && s.length() > 0)
|
||||
return s.toString();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
boolean eol = false;
|
||||
char c = 0;
|
||||
int i;
|
||||
|
||||
/* Skip a leftover '\n', if necessary */
|
||||
if (omitLF && (cb[nextChar] == '\n'))
|
||||
nextChar++;
|
||||
skipLF = false;
|
||||
omitLF = false;
|
||||
|
||||
charLoop:
|
||||
for (i = nextChar; i < nChars; i++) {
|
||||
c = cb[i];
|
||||
if ((c == '\n') || (c == '\r')) {
|
||||
if (term != null) term[0] = true;
|
||||
eol = true;
|
||||
break charLoop;
|
||||
}
|
||||
}
|
||||
|
||||
startChar = nextChar;
|
||||
nextChar = i;
|
||||
|
||||
if (eol) {
|
||||
String str;
|
||||
if (s == null) {
|
||||
str = new String(cb, startChar, i - startChar);
|
||||
} else {
|
||||
s.append(cb, startChar, i - startChar);
|
||||
str = s.toString();
|
||||
}
|
||||
nextChar++;
|
||||
if (c == '\r') {
|
||||
skipLF = true;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
if (s == null)
|
||||
s = new StringBuilder(defaultExpectedLineLength);
|
||||
s.append(cb, startChar, i - startChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,33 +444,47 @@ public class BufferedReader extends Reader {
|
|||
if (n < 0L) {
|
||||
throw new IllegalArgumentException("skip value is negative");
|
||||
}
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
long r = n;
|
||||
while (r > 0) {
|
||||
if (nextChar >= nChars)
|
||||
fill();
|
||||
if (nextChar >= nChars) /* EOF */
|
||||
break;
|
||||
if (skipLF) {
|
||||
skipLF = false;
|
||||
if (cb[nextChar] == '\n') {
|
||||
nextChar++;
|
||||
}
|
||||
}
|
||||
long d = nChars - nextChar;
|
||||
if (r <= d) {
|
||||
nextChar += r;
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
r -= d;
|
||||
nextChar = nChars;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implSkip(n);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implSkip(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long implSkip(long n) throws IOException {
|
||||
ensureOpen();
|
||||
long r = n;
|
||||
while (r > 0) {
|
||||
if (nextChar >= nChars)
|
||||
fill();
|
||||
if (nextChar >= nChars) /* EOF */
|
||||
break;
|
||||
if (skipLF) {
|
||||
skipLF = false;
|
||||
if (cb[nextChar] == '\n') {
|
||||
nextChar++;
|
||||
}
|
||||
}
|
||||
return n - r;
|
||||
long d = nChars - nextChar;
|
||||
if (r <= d) {
|
||||
nextChar += r;
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
r -= d;
|
||||
nextChar = nChars;
|
||||
}
|
||||
}
|
||||
return n - r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,30 +495,44 @@ public class BufferedReader extends Reader {
|
|||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
public boolean ready() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
|
||||
/*
|
||||
* If newline needs to be skipped and the next char to be read
|
||||
* is a newline character, then just skip it right away.
|
||||
*/
|
||||
if (skipLF) {
|
||||
/* Note that in.ready() will return true if and only if the next
|
||||
* read on the stream will not block.
|
||||
*/
|
||||
if (nextChar >= nChars && in.ready()) {
|
||||
fill();
|
||||
}
|
||||
if (nextChar < nChars) {
|
||||
if (cb[nextChar] == '\n')
|
||||
nextChar++;
|
||||
skipLF = false;
|
||||
}
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implReady();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implReady();
|
||||
}
|
||||
return (nextChar < nChars) || in.ready();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean implReady() throws IOException {
|
||||
ensureOpen();
|
||||
|
||||
/*
|
||||
* If newline needs to be skipped and the next char to be read
|
||||
* is a newline character, then just skip it right away.
|
||||
*/
|
||||
if (skipLF) {
|
||||
/* Note that in.ready() will return true if and only if the next
|
||||
* read on the stream will not block.
|
||||
*/
|
||||
if (nextChar >= nChars && in.ready()) {
|
||||
fill();
|
||||
}
|
||||
if (nextChar < nChars) {
|
||||
if (cb[nextChar] == '\n')
|
||||
nextChar++;
|
||||
skipLF = false;
|
||||
}
|
||||
}
|
||||
return (nextChar < nChars) || in.ready();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether this stream supports the mark() operation, which it does.
|
||||
*/
|
||||
|
@ -491,14 +560,28 @@ public class BufferedReader extends Reader {
|
|||
if (readAheadLimit < 0) {
|
||||
throw new IllegalArgumentException("Read-ahead limit < 0");
|
||||
}
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
this.readAheadLimit = readAheadLimit;
|
||||
markedChar = nextChar;
|
||||
markedSkipLF = skipLF;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implMark(readAheadLimit);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implMark(readAheadLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implMark(int readAheadLimit) throws IOException {
|
||||
ensureOpen();
|
||||
this.readAheadLimit = readAheadLimit;
|
||||
markedChar = nextChar;
|
||||
markedSkipLF = skipLF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stream to the most recent mark.
|
||||
*
|
||||
|
@ -506,27 +589,55 @@ public class BufferedReader extends Reader {
|
|||
* or if the mark has been invalidated
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if (markedChar < 0)
|
||||
throw new IOException((markedChar == INVALIDATED)
|
||||
? "Mark invalid"
|
||||
: "Stream not marked");
|
||||
nextChar = markedChar;
|
||||
skipLF = markedSkipLF;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implReset();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implReset() throws IOException {
|
||||
ensureOpen();
|
||||
if (markedChar < 0)
|
||||
throw new IOException((markedChar == INVALIDATED)
|
||||
? "Mark invalid"
|
||||
: "Stream not marked");
|
||||
nextChar = markedChar;
|
||||
skipLF = markedSkipLF;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (in == null)
|
||||
return;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
in.close();
|
||||
implClose();
|
||||
} finally {
|
||||
in = null;
|
||||
cb = null;
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implClose() throws IOException {
|
||||
if (in == null)
|
||||
return;
|
||||
try {
|
||||
in.close();
|
||||
} finally {
|
||||
in = null;
|
||||
cb = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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.io;
|
|||
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Arrays;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
|
||||
|
@ -213,7 +214,12 @@ public class FileInputStream extends InputStream
|
|||
* @param name the name of the file
|
||||
*/
|
||||
private void open(String name) throws FileNotFoundException {
|
||||
open0(name);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
open0(name);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,7 +231,12 @@ public class FileInputStream extends InputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
return read0();
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return read0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native int read0() throws IOException;
|
||||
|
@ -251,7 +262,12 @@ public class FileInputStream extends InputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public int read(byte[] b) throws IOException {
|
||||
return readBytes(b, 0, b.length);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return readBytes(b, 0, b.length);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,7 +289,12 @@ public class FileInputStream extends InputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return readBytes(b, off, len);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return readBytes(b, off, len);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readAllBytes() throws IOException {
|
||||
|
@ -373,12 +394,22 @@ public class FileInputStream extends InputStream
|
|||
}
|
||||
|
||||
private long length() throws IOException {
|
||||
return length0();
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return length0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
private native long length0() throws IOException;
|
||||
|
||||
private long position() throws IOException {
|
||||
return position0();
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return position0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
private native long position0() throws IOException;
|
||||
|
||||
|
@ -407,7 +438,12 @@ public class FileInputStream extends InputStream
|
|||
* support seek, or if an I/O error occurs.
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
return skip0(n);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return skip0(n);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native long skip0(long n) throws IOException;
|
||||
|
@ -430,7 +466,12 @@ public class FileInputStream extends InputStream
|
|||
* {@code close} or an I/O error occurs.
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
return available0();
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return available0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native int available0() throws IOException;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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,6 +28,7 @@ package java.io;
|
|||
import java.nio.channels.FileChannel;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.access.JavaIOFileDescriptorAccess;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
|
||||
|
||||
|
@ -288,9 +289,13 @@ public class FileOutputStream extends OutputStream
|
|||
* @param name name of file to be opened
|
||||
* @param append whether the file is to be opened in append mode
|
||||
*/
|
||||
private void open(String name, boolean append)
|
||||
throws FileNotFoundException {
|
||||
open0(name, append);
|
||||
private void open(String name, boolean append) throws FileNotFoundException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
open0(name, append);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -310,7 +315,13 @@ public class FileOutputStream extends OutputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
write(b, fdAccess.getAppend(fd));
|
||||
boolean append = fdAccess.getAppend(fd);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
write(b, append);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -333,7 +344,13 @@ public class FileOutputStream extends OutputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void write(byte[] b) throws IOException {
|
||||
writeBytes(b, 0, b.length, fdAccess.getAppend(fd));
|
||||
boolean append = fdAccess.getAppend(fd);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
writeBytes(b, 0, b.length, append);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,7 +363,13 @@ public class FileOutputStream extends OutputStream
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
writeBytes(b, off, len, fdAccess.getAppend(fd));
|
||||
boolean append = fdAccess.getAppend(fd);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
writeBytes(b, off, len, append);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2021, 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
|
||||
|
@ -28,9 +28,9 @@ package java.io;
|
|||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
import sun.nio.cs.StreamDecoder;
|
||||
|
||||
|
||||
/**
|
||||
* An InputStreamReader is a bridge from byte streams to character streams: It
|
||||
* reads bytes and decodes them into characters using a specified {@link
|
||||
|
@ -61,9 +61,22 @@ import sun.nio.cs.StreamDecoder;
|
|||
*/
|
||||
|
||||
public class InputStreamReader extends Reader {
|
||||
|
||||
private final StreamDecoder sd;
|
||||
|
||||
/**
|
||||
* Return the lock object for the given reader's stream decoder.
|
||||
* If the reader type is trusted then an internal lock can be used. If the
|
||||
* reader type is not trusted then the reader object is the lock.
|
||||
*/
|
||||
private static Object lockFor(InputStreamReader reader) {
|
||||
Class<?> clazz = reader.getClass();
|
||||
if (clazz == InputStreamReader.class || clazz == FileReader.class) {
|
||||
return InternalLock.newLockOr(reader);
|
||||
} else {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InputStreamReader that uses the
|
||||
* {@link Charset#defaultCharset() default charset}.
|
||||
|
@ -74,8 +87,8 @@ public class InputStreamReader extends Reader {
|
|||
*/
|
||||
public InputStreamReader(InputStream in) {
|
||||
super(in);
|
||||
sd = StreamDecoder.forInputStreamReader(in, this,
|
||||
Charset.defaultCharset()); // ## check lock object
|
||||
Charset cs = Charset.defaultCharset();
|
||||
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,7 +109,7 @@ public class InputStreamReader extends Reader {
|
|||
super(in);
|
||||
if (charsetName == null)
|
||||
throw new NullPointerException("charsetName");
|
||||
sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
|
||||
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), charsetName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,7 +124,7 @@ public class InputStreamReader extends Reader {
|
|||
super(in);
|
||||
if (cs == null)
|
||||
throw new NullPointerException("charset");
|
||||
sd = StreamDecoder.forInputStreamReader(in, this, cs);
|
||||
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +139,7 @@ public class InputStreamReader extends Reader {
|
|||
super(in);
|
||||
if (dec == null)
|
||||
throw new NullPointerException("charset decoder");
|
||||
sd = StreamDecoder.forInputStreamReader(in, this, dec);
|
||||
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), dec);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2021, 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
|
||||
|
@ -28,9 +28,9 @@ package java.io;
|
|||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
import sun.nio.cs.StreamEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* An OutputStreamWriter is a bridge from character streams to byte streams:
|
||||
* Characters written to it are encoded into bytes using a specified {@link
|
||||
|
@ -74,9 +74,22 @@ import sun.nio.cs.StreamEncoder;
|
|||
*/
|
||||
|
||||
public class OutputStreamWriter extends Writer {
|
||||
|
||||
private final StreamEncoder se;
|
||||
|
||||
/**
|
||||
* Return the lock object for the given writer's stream encoder.
|
||||
* If the writer type is trusted then an internal lock can be used. If the
|
||||
* writer type is not trusted then the writer object is the lock.
|
||||
*/
|
||||
private static Object lockFor(OutputStreamWriter writer) {
|
||||
Class<?> clazz = writer.getClass();
|
||||
if (clazz == OutputStreamWriter.class || clazz == FileWriter.class) {
|
||||
return InternalLock.newLockOr(writer);
|
||||
} else {
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OutputStreamWriter that uses the named charset.
|
||||
*
|
||||
|
@ -95,7 +108,7 @@ public class OutputStreamWriter extends Writer {
|
|||
super(out);
|
||||
if (charsetName == null)
|
||||
throw new NullPointerException("charsetName");
|
||||
se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
|
||||
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), charsetName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +121,7 @@ public class OutputStreamWriter extends Writer {
|
|||
*/
|
||||
public OutputStreamWriter(OutputStream out) {
|
||||
super(out);
|
||||
se = StreamEncoder.forOutputStreamWriter(out, this,
|
||||
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this),
|
||||
out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());
|
||||
}
|
||||
|
||||
|
@ -127,7 +140,7 @@ public class OutputStreamWriter extends Writer {
|
|||
super(out);
|
||||
if (cs == null)
|
||||
throw new NullPointerException("charset");
|
||||
se = StreamEncoder.forOutputStreamWriter(out, this, cs);
|
||||
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,7 +158,7 @@ public class OutputStreamWriter extends Writer {
|
|||
super(out);
|
||||
if (enc == null)
|
||||
throw new NullPointerException("charset encoder");
|
||||
se = StreamEncoder.forOutputStreamWriter(out, this, enc);
|
||||
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), enc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,9 @@ import java.util.Locale;
|
|||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import jdk.internal.access.JavaIOPrintStreamAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* A {@code PrintStream} adds functionality to another output stream,
|
||||
|
@ -64,6 +67,8 @@ import java.nio.charset.UnsupportedCharsetException;
|
|||
public class PrintStream extends FilterOutputStream
|
||||
implements Appendable, Closeable
|
||||
{
|
||||
// initialized to null when PrintStream is sub-classed
|
||||
private final InternalLock lock;
|
||||
|
||||
private final boolean autoFlush;
|
||||
private boolean trouble = false;
|
||||
|
@ -112,6 +117,13 @@ public class PrintStream extends FilterOutputStream
|
|||
this.charset = out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset();
|
||||
this.charOut = new OutputStreamWriter(this, charset);
|
||||
this.textOut = new BufferedWriter(charOut);
|
||||
|
||||
// use monitors when PrintStream is sub-classed
|
||||
if (getClass() == PrintStream.class) {
|
||||
lock = InternalLock.newLockOrNull();
|
||||
} else {
|
||||
lock = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Variant of the private constructor so that the given charset name
|
||||
|
@ -206,6 +218,13 @@ public class PrintStream extends FilterOutputStream
|
|||
this.charOut = new OutputStreamWriter(this, charset);
|
||||
this.textOut = new BufferedWriter(charOut);
|
||||
this.charset = charset;
|
||||
|
||||
// use monitors when PrintStream is sub-classed
|
||||
if (getClass() == PrintStream.class) {
|
||||
lock = InternalLock.newLockOrNull();
|
||||
} else {
|
||||
lock = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,17 +444,30 @@ public class PrintStream extends FilterOutputStream
|
|||
*/
|
||||
@Override
|
||||
public void flush() {
|
||||
synchronized (this) {
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
ensureOpen();
|
||||
out.flush();
|
||||
implFlush();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
catch (IOException x) {
|
||||
trouble = true;
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implFlush() {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean closing = false; /* To avoid recursive closing */
|
||||
|
||||
/**
|
||||
|
@ -446,20 +478,33 @@ public class PrintStream extends FilterOutputStream
|
|||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (this) {
|
||||
if (! closing) {
|
||||
closing = true;
|
||||
try {
|
||||
textOut.close();
|
||||
out.close();
|
||||
}
|
||||
catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
textOut = null;
|
||||
charOut = null;
|
||||
out = null;
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implClose();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implClose() {
|
||||
if (!closing) {
|
||||
closing = true;
|
||||
try {
|
||||
textOut.close();
|
||||
out.close();
|
||||
}
|
||||
catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
textOut = null;
|
||||
charOut = null;
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,11 +571,17 @@ public class PrintStream extends FilterOutputStream
|
|||
@Override
|
||||
public void write(int b) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
out.write(b);
|
||||
if ((b == '\n') && autoFlush)
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(b);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -541,6 +592,13 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWrite(int b) throws IOException {
|
||||
ensureOpen();
|
||||
out.write(b);
|
||||
if ((b == '\n') && autoFlush)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes {@code len} bytes from the specified byte array starting at
|
||||
* offset {@code off} to this stream. If automatic flushing is
|
||||
|
@ -558,11 +616,17 @@ public class PrintStream extends FilterOutputStream
|
|||
@Override
|
||||
public void write(byte[] buf, int off, int len) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
out.write(buf, off, len);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(buf, off, len);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(buf, off, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -573,6 +637,14 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWrite(byte[] buf, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
out.write(buf, off, len);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes all bytes from the specified byte array to this stream. If
|
||||
* automatic flushing is enabled then the {@code flush} method will be
|
||||
|
@ -639,17 +711,16 @@ public class PrintStream extends FilterOutputStream
|
|||
|
||||
private void write(char[] buf) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
textOut.write(buf);
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush) {
|
||||
for (int i = 0; i < buf.length; i++)
|
||||
if (buf[i] == '\n') {
|
||||
out.flush();
|
||||
break;
|
||||
}
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(buf);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(buf);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException x) {
|
||||
|
@ -659,20 +730,37 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWrite(char[] buf) throws IOException {
|
||||
ensureOpen();
|
||||
textOut.write(buf);
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush) {
|
||||
for (int i = 0; i < buf.length; i++)
|
||||
if (buf[i] == '\n') {
|
||||
out.flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to optimize away back-to-back flushing and synchronization when
|
||||
// using println, but since subclasses could exist which depend on
|
||||
// observing a call to print followed by newLine() we only use this if
|
||||
// getClass() == PrintStream.class to avoid compatibility issues.
|
||||
private void writeln(char[] buf) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
textOut.write(buf);
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWriteln(buf);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWriteln(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -683,15 +771,29 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWriteln(char[] buf) throws IOException {
|
||||
ensureOpen();
|
||||
textOut.write(buf);
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void write(String s) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
textOut.write(s);
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush && (s.indexOf('\n') >= 0))
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWrite(s);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWrite(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -702,20 +804,32 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWrite(String s) throws IOException {
|
||||
ensureOpen();
|
||||
textOut.write(s);
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush && (s.indexOf('\n') >= 0))
|
||||
out.flush();
|
||||
}
|
||||
|
||||
// Used to optimize away back-to-back flushing and synchronization when
|
||||
// using println, but since subclasses could exist which depend on
|
||||
// observing a call to print followed by newLine we only use this if
|
||||
// getClass() == PrintStream.class to avoid compatibility issues.
|
||||
private void writeln(String s) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
textOut.write(s);
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implWriteln(s);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implWriteln(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -726,15 +840,29 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implWriteln(String s) throws IOException {
|
||||
ensureOpen();
|
||||
textOut.write(s);
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void newLine() {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implNewLine();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implNewLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
|
@ -745,6 +873,15 @@ public class PrintStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
private void implNewLine() throws IOException {
|
||||
ensureOpen();
|
||||
textOut.newLine();
|
||||
textOut.flushBuffer();
|
||||
charOut.flushBuffer();
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/* Methods that do not terminate lines */
|
||||
|
||||
/**
|
||||
|
@ -1202,14 +1339,17 @@ public class PrintStream extends FilterOutputStream
|
|||
*/
|
||||
public PrintStream format(String format, Object ... args) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
if ((formatter == null)
|
||||
|| (formatter.locale() !=
|
||||
Locale.getDefault(Locale.Category.FORMAT)))
|
||||
formatter = new Formatter((Appendable) this);
|
||||
formatter.format(Locale.getDefault(Locale.Category.FORMAT),
|
||||
format, args);
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implFormat(format, args);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implFormat(format, args);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
@ -1219,6 +1359,13 @@ public class PrintStream extends FilterOutputStream
|
|||
return this;
|
||||
}
|
||||
|
||||
private void implFormat(String format, Object ... args) throws IOException {
|
||||
ensureOpen();
|
||||
if ((formatter == null) || (formatter.locale() != Locale.getDefault(Locale.Category.FORMAT)))
|
||||
formatter = new Formatter((Appendable) this);
|
||||
formatter.format(Locale.getDefault(Locale.Category.FORMAT), format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a formatted string to this output stream using the specified
|
||||
* format string and arguments.
|
||||
|
@ -1261,12 +1408,17 @@ public class PrintStream extends FilterOutputStream
|
|||
*/
|
||||
public PrintStream format(Locale l, String format, Object ... args) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
ensureOpen();
|
||||
if ((formatter == null)
|
||||
|| (formatter.locale() != l))
|
||||
formatter = new Formatter(this, l);
|
||||
formatter.format(l, format, args);
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
implFormat(l, format, args);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implFormat(l, format, args);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
@ -1276,6 +1428,13 @@ public class PrintStream extends FilterOutputStream
|
|||
return this;
|
||||
}
|
||||
|
||||
private void implFormat(Locale l, String format, Object ... args) throws IOException {
|
||||
ensureOpen();
|
||||
if ((formatter == null) || (formatter.locale() != l))
|
||||
formatter = new Formatter(this, l);
|
||||
formatter.format(l, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified character sequence to this output stream.
|
||||
*
|
||||
|
@ -1376,4 +1535,13 @@ public class PrintStream extends FilterOutputStream
|
|||
public Charset charset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
static {
|
||||
SharedSecrets.setJavaIOCPrintStreamAccess(new JavaIOPrintStreamAccess() {
|
||||
public Object lock(PrintStream ps) {
|
||||
Object lock = ps.lock;
|
||||
return (lock != null) ? lock : ps;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ import java.util.Locale;
|
|||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import jdk.internal.access.JavaIOPrintWriterAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* Prints formatted representations of objects to a text-output stream. This
|
||||
|
@ -95,7 +98,7 @@ public class PrintWriter extends Writer {
|
|||
*
|
||||
* @param out A character-output stream
|
||||
*/
|
||||
public PrintWriter (Writer out) {
|
||||
public PrintWriter(Writer out) {
|
||||
this(out, false);
|
||||
}
|
||||
|
||||
|
@ -107,8 +110,7 @@ public class PrintWriter extends Writer {
|
|||
* {@code printf}, or {@code format} methods will
|
||||
* flush the output buffer
|
||||
*/
|
||||
public PrintWriter(Writer out,
|
||||
boolean autoFlush) {
|
||||
public PrintWriter(Writer out, boolean autoFlush) {
|
||||
super(out);
|
||||
this.out = out;
|
||||
this.autoFlush = autoFlush;
|
||||
|
@ -394,13 +396,26 @@ public class PrintWriter extends Writer {
|
|||
* @see #checkError()
|
||||
*/
|
||||
public void flush() {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implFlush();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
out.flush();
|
||||
implFlush();
|
||||
}
|
||||
}
|
||||
catch (IOException x) {
|
||||
}
|
||||
|
||||
private void implFlush() {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.flush();
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -412,15 +427,28 @@ public class PrintWriter extends Writer {
|
|||
* @see #checkError()
|
||||
*/
|
||||
public void close() {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implClose();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
if (out == null)
|
||||
return;
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implClose() {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -478,16 +506,28 @@ public class PrintWriter extends Writer {
|
|||
* @param c int specifying a character to be written.
|
||||
*/
|
||||
public void write(int c) {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implWrite(c);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
out.write(c);
|
||||
implWrite(c);
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
}
|
||||
|
||||
private void implWrite(int c) {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.write(c);
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -504,16 +544,28 @@ public class PrintWriter extends Writer {
|
|||
* to throw an {@code IndexOutOfBoundsException}
|
||||
*/
|
||||
public void write(char[] buf, int off, int len) {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implWrite(buf, off, len);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
out.write(buf, off, len);
|
||||
implWrite(buf, off, len);
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
}
|
||||
|
||||
private void implWrite(char[] buf, int off, int len) {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.write(buf, off, len);
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -539,16 +591,28 @@ public class PrintWriter extends Writer {
|
|||
* to throw an {@code IndexOutOfBoundsException}
|
||||
*/
|
||||
public void write(String s, int off, int len) {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implWrite(s, off, len);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
out.write(s, off, len);
|
||||
implWrite(s, off, len);
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
}
|
||||
|
||||
private void implWrite(String s, int off, int len) {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.write(s, off, len);
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -563,18 +627,30 @@ public class PrintWriter extends Writer {
|
|||
}
|
||||
|
||||
private void newLine() {
|
||||
try {
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implNewLine();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
out.write(System.lineSeparator());
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
implNewLine();
|
||||
}
|
||||
}
|
||||
catch (InterruptedIOException x) {
|
||||
}
|
||||
|
||||
private void implNewLine() {
|
||||
try {
|
||||
ensureOpen();
|
||||
out.write(System.lineSeparator());
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
}
|
||||
|
@ -731,9 +807,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code boolean} value to be printed
|
||||
*/
|
||||
public void println(boolean x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,9 +832,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code char} value to be printed
|
||||
*/
|
||||
public void println(char x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,9 +857,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code int} value to be printed
|
||||
*/
|
||||
public void println(int x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,9 +882,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code long} value to be printed
|
||||
*/
|
||||
public void println(long x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,9 +907,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code float} value to be printed
|
||||
*/
|
||||
public void println(float x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -801,9 +932,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code double} value to be printed
|
||||
*/
|
||||
public void println(double x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -815,9 +957,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the array of {@code char} values to be printed
|
||||
*/
|
||||
public void println(char[] x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -829,9 +982,20 @@ public class PrintWriter extends Writer {
|
|||
* @param x the {@code String} value to be printed
|
||||
*/
|
||||
public void println(String x) {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(x);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(x);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -846,9 +1010,20 @@ public class PrintWriter extends Writer {
|
|||
*/
|
||||
public void println(Object x) {
|
||||
String s = String.valueOf(x);
|
||||
synchronized (lock) {
|
||||
print(s);
|
||||
println();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
print(s);
|
||||
println();
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
print(s);
|
||||
println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,22 +1169,36 @@ public class PrintWriter extends Writer {
|
|||
* @since 1.5
|
||||
*/
|
||||
public PrintWriter format(String format, Object ... args) {
|
||||
try {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if ((formatter == null)
|
||||
|| (formatter.locale() != Locale.getDefault()))
|
||||
formatter = new Formatter(this);
|
||||
formatter.format(Locale.getDefault(), format, args);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implFormat(format, args);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implFormat(format, args);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void implFormat(String format, Object ... args) {
|
||||
try {
|
||||
ensureOpen();
|
||||
if ((formatter == null)
|
||||
|| (formatter.locale() != Locale.getDefault()))
|
||||
formatter = new Formatter(this);
|
||||
formatter.format(Locale.getDefault(), format, args);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1054,21 +1243,35 @@ public class PrintWriter extends Writer {
|
|||
* @since 1.5
|
||||
*/
|
||||
public PrintWriter format(Locale l, String format, Object ... args) {
|
||||
try {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if ((formatter == null) || (formatter.locale() != l))
|
||||
formatter = new Formatter(this, l);
|
||||
formatter.format(l, format, args);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implFormat(l, format, args);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implFormat(l, format, args);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void implFormat(Locale l, String format, Object ... args) {
|
||||
try {
|
||||
ensureOpen();
|
||||
if ((formatter == null) || (formatter.locale() != l))
|
||||
formatter = new Formatter(this, l);
|
||||
formatter.format(l, format, args);
|
||||
if (autoFlush)
|
||||
out.flush();
|
||||
} catch (InterruptedIOException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException x) {
|
||||
trouble = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1161,4 +1364,12 @@ public class PrintWriter extends Writer {
|
|||
write(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
static {
|
||||
SharedSecrets.setJavaIOCPrintWriterAccess(new JavaIOPrintWriterAccess() {
|
||||
public Object lock(PrintWriter pw) {
|
||||
return pw.lock;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package java.io;
|
||||
|
||||
import java.util.Objects;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* A {@code PushbackInputStream} adds
|
||||
|
@ -52,6 +53,8 @@ import java.util.Objects;
|
|||
* @since 1.0
|
||||
*/
|
||||
public class PushbackInputStream extends FilterInputStream {
|
||||
private final InternalLock closeLock;
|
||||
|
||||
/**
|
||||
* The pushback buffer.
|
||||
* @since 1.1
|
||||
|
@ -95,6 +98,13 @@ public class PushbackInputStream extends FilterInputStream {
|
|||
}
|
||||
this.buf = new byte[size];
|
||||
this.pos = size;
|
||||
|
||||
// use monitors when PushbackInputStream is sub-classed
|
||||
if (getClass() == PushbackInputStream.class) {
|
||||
closeLock = InternalLock.newLockOrNull();
|
||||
} else {
|
||||
closeLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -373,11 +383,26 @@ public class PushbackInputStream extends FilterInputStream {
|
|||
*
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
if (in == null)
|
||||
return;
|
||||
in.close();
|
||||
in = null;
|
||||
buf = null;
|
||||
public void close() throws IOException {
|
||||
if (closeLock != null) {
|
||||
closeLock.lock();
|
||||
try {
|
||||
implClose();
|
||||
} finally {
|
||||
closeLock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (this) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void implClose() throws IOException {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
in = null;
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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
|
||||
|
@ -29,6 +29,7 @@ import java.nio.channels.FileChannel;
|
|||
|
||||
import jdk.internal.access.JavaIORandomAccessFileAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
|
||||
|
||||
|
@ -339,9 +340,13 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @param mode the mode flags, a combination of the O_ constants
|
||||
* defined above
|
||||
*/
|
||||
private void open(String name, int mode)
|
||||
throws FileNotFoundException {
|
||||
open0(name, mode);
|
||||
private void open(String name, int mode) throws FileNotFoundException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
open0(name, mode);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
// 'Read' primitives
|
||||
|
@ -362,7 +367,12 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* end-of-file has been reached.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
return read0();
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return read0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native int read0() throws IOException;
|
||||
|
@ -374,7 +384,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @param len the number of bytes to read.
|
||||
* @throws IOException If an I/O error has occurred.
|
||||
*/
|
||||
private native int readBytes(byte[] b, int off, int len) throws IOException;
|
||||
private int readBytes(byte[] b, int off, int len) throws IOException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return readBytes0(b, off, len);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native int readBytes0(byte[] b, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Reads up to {@code len} bytes of data from this file into an
|
||||
|
@ -519,7 +538,12 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
write0(b);
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
write0(b);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native void write0(int b) throws IOException;
|
||||
|
@ -532,7 +556,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @param len the number of bytes that are written
|
||||
* @throws IOException If an I/O error has occurred.
|
||||
*/
|
||||
private native void writeBytes(byte[] b, int off, int len) throws IOException;
|
||||
private void writeBytes(byte[] b, int off, int len) throws IOException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
writeBytes0(b, off, len);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native void writeBytes0(byte[] b, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes {@code b.length} bytes from the specified byte array
|
||||
|
@ -587,8 +620,12 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
public void seek(long pos) throws IOException {
|
||||
if (pos < 0) {
|
||||
throw new IOException("Negative seek offset");
|
||||
} else {
|
||||
}
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
seek0(pos);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -600,7 +637,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @return the length of this file, measured in bytes.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public native long length() throws IOException;
|
||||
public long length() throws IOException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return length0();
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native long length0() throws IOException;
|
||||
|
||||
/**
|
||||
* Sets the length of this file.
|
||||
|
@ -621,7 +667,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||
* @throws IOException If an I/O error occurs
|
||||
* @since 1.2
|
||||
*/
|
||||
public native void setLength(long newLength) throws IOException;
|
||||
public void setLength(long newLength) throws IOException {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
setLength0(newLength);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private native void setLength0(long newLength) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes this random access file stream and releases any system
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2021, 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,10 +25,10 @@
|
|||
|
||||
package java.io;
|
||||
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* Abstract class for reading character streams. The only methods that a
|
||||
|
@ -170,6 +170,21 @@ public abstract class Reader implements Readable, Closeable {
|
|||
this.lock = lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use by BufferedReader to create a character-stream reader that uses an
|
||||
* internal lock when BufferedReader is not extended and the given reader is
|
||||
* trusted, otherwise critical sections will synchronize on the given reader.
|
||||
*/
|
||||
Reader(Reader in) {
|
||||
Class<?> clazz = in.getClass();
|
||||
if (getClass() == BufferedReader.class &&
|
||||
(clazz == InputStreamReader.class || clazz == FileReader.class)) {
|
||||
this.lock = InternalLock.newLockOr(in);
|
||||
} else {
|
||||
this.lock = in;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read characters into the specified character buffer.
|
||||
* The buffer is used as a repository of characters as-is: the only
|
||||
|
@ -297,21 +312,35 @@ public abstract class Reader implements Readable, Closeable {
|
|||
public long skip(long n) throws IOException {
|
||||
if (n < 0L)
|
||||
throw new IllegalArgumentException("skip value is negative");
|
||||
int nn = (int) Math.min(n, maxSkipBufferSize);
|
||||
synchronized (lock) {
|
||||
if ((skipBuffer == null) || (skipBuffer.length < nn))
|
||||
skipBuffer = new char[nn];
|
||||
long r = n;
|
||||
while (r > 0) {
|
||||
int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
|
||||
if (nc == -1)
|
||||
break;
|
||||
r -= nc;
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
return implSkip(n);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
return implSkip(n);
|
||||
}
|
||||
return n - r;
|
||||
}
|
||||
}
|
||||
|
||||
private long implSkip(long n) throws IOException {
|
||||
int nn = (int) Math.min(n, maxSkipBufferSize);
|
||||
if ((skipBuffer == null) || (skipBuffer.length < nn))
|
||||
skipBuffer = new char[nn];
|
||||
long r = n;
|
||||
while (r > 0) {
|
||||
int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
|
||||
if (nc == -1)
|
||||
break;
|
||||
r -= nc;
|
||||
}
|
||||
return n - r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether this stream is ready to be read.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2018, 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,8 +25,8 @@
|
|||
|
||||
package java.io;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import jdk.internal.misc.InternalLock;
|
||||
|
||||
/**
|
||||
* Abstract class for writing to character streams. The only methods that a
|
||||
|
@ -162,6 +162,21 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
|
|||
this.lock = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use by BufferedWriter to create a character-stream writer that uses an
|
||||
* internal lock when BufferedWriter is not extended and the given writer is
|
||||
* trusted, otherwise critical sections will synchronize on the given writer.
|
||||
*/
|
||||
Writer(Writer writer) {
|
||||
Class<?> clazz = writer.getClass();
|
||||
if (getClass() == BufferedWriter.class &&
|
||||
(clazz == OutputStreamWriter.class || clazz == FileWriter.class)) {
|
||||
this.lock = InternalLock.newLockOr(writer);
|
||||
} else {
|
||||
this.lock = writer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new character-stream writer whose critical sections will
|
||||
* synchronize on the given object.
|
||||
|
@ -191,15 +206,29 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
|
|||
* If an I/O error occurs
|
||||
*/
|
||||
public void write(int c) throws IOException {
|
||||
synchronized (lock) {
|
||||
if (writeBuffer == null){
|
||||
writeBuffer = new char[WRITE_BUFFER_SIZE];
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implWrite(c);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implWrite(c);
|
||||
}
|
||||
writeBuffer[0] = (char) c;
|
||||
write(writeBuffer, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void implWrite(int c) throws IOException {
|
||||
if (writeBuffer == null){
|
||||
writeBuffer = new char[WRITE_BUFFER_SIZE];
|
||||
}
|
||||
writeBuffer[0] = (char) c;
|
||||
write(writeBuffer, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of characters.
|
||||
*
|
||||
|
@ -276,21 +305,35 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
|
|||
* If an I/O error occurs
|
||||
*/
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
char cbuf[];
|
||||
if (len <= WRITE_BUFFER_SIZE) {
|
||||
if (writeBuffer == null) {
|
||||
writeBuffer = new char[WRITE_BUFFER_SIZE];
|
||||
}
|
||||
cbuf = writeBuffer;
|
||||
} else { // Don't permanently allocate very large buffers.
|
||||
cbuf = new char[len];
|
||||
Object lock = this.lock;
|
||||
if (lock instanceof InternalLock locker) {
|
||||
locker.lock();
|
||||
try {
|
||||
implWrite(str, off, len);
|
||||
} finally {
|
||||
locker.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
implWrite(str, off, len);
|
||||
}
|
||||
str.getChars(off, (off + len), cbuf, 0);
|
||||
write(cbuf, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
private void implWrite(String str, int off, int len) throws IOException {
|
||||
char cbuf[];
|
||||
if (len <= WRITE_BUFFER_SIZE) {
|
||||
if (writeBuffer == null) {
|
||||
writeBuffer = new char[WRITE_BUFFER_SIZE];
|
||||
}
|
||||
cbuf = writeBuffer;
|
||||
} else { // Don't permanently allocate very large buffers.
|
||||
cbuf = new char[len];
|
||||
}
|
||||
str.getChars(off, (off + len), cbuf, 0);
|
||||
write(cbuf, 0, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified character sequence to this writer.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue