8343039: Remove jdk.internal.misc.InternalLock and usages from java.io

Reviewed-by: liach, alanb
This commit is contained in:
Brian Burkhalter 2024-11-15 16:11:34 +00:00
parent 3c38ed4128
commit 0b9b82af03
19 changed files with 548 additions and 1789 deletions

View file

@ -28,7 +28,6 @@ package java.io;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import jdk.internal.misc.InternalLock;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
import jdk.internal.util.ArraysSupport; import jdk.internal.util.ArraysSupport;
@ -74,9 +73,6 @@ public class BufferedInputStream extends FilterInputStream {
private static final long BUF_OFFSET private static final long BUF_OFFSET
= U.objectFieldOffset(BufferedInputStream.class, "buf"); = U.objectFieldOffset(BufferedInputStream.class, "buf");
// initialized to null when BufferedInputStream is sub-classed
private final InternalLock lock;
// initial buffer size (DEFAULT_BUFFER_SIZE or size specified to constructor) // initial buffer size (DEFAULT_BUFFER_SIZE or size specified to constructor)
private final int initialSize; private final int initialSize;
@ -243,12 +239,9 @@ public class BufferedInputStream extends FilterInputStream {
} }
initialSize = size; initialSize = size;
if (getClass() == BufferedInputStream.class) { if (getClass() == BufferedInputStream.class) {
// use internal lock and lazily create buffer when not subclassed // lazily create buffer when not subclassed
lock = InternalLock.newLockOrNull();
buf = EMPTY; buf = EMPTY;
} else { } else {
// use monitors and eagerly create buffer when subclassed
lock = null;
buf = new byte[size]; buf = new byte[size];
} }
} }
@ -256,7 +249,7 @@ public class BufferedInputStream extends FilterInputStream {
/** /**
* Fills the buffer with more data, taking into account * Fills the buffer with more data, taking into account
* shuffling and other tricks for dealing with marks. * shuffling and other tricks for dealing with marks.
* Assumes that it is being called by a locked method. * Assumes that it is being called by a synchronized method.
* This method also assumes that all data has already been read in, * This method also assumes that all data has already been read in,
* hence pos > count. * hence pos > count.
*/ */
@ -310,22 +303,7 @@ public class BufferedInputStream extends FilterInputStream {
* or an I/O error occurs. * or an I/O error occurs.
* @see java.io.FilterInputStream#in * @see java.io.FilterInputStream#in
*/ */
public int read() throws IOException { public synchronized 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) { if (pos >= count) {
fill(); fill();
if (pos >= count) if (pos >= count)
@ -397,22 +375,7 @@ public class BufferedInputStream extends FilterInputStream {
* or an I/O error occurs. * or an I/O error occurs.
* @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc}
*/ */
public int read(byte[] b, int off, int len) throws IOException { public synchronized 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 {
ensureOpen(); ensureOpen();
if ((off | len | (off + len) | (b.length - (off + len))) < 0) { if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
@ -444,22 +407,7 @@ public class BufferedInputStream extends FilterInputStream {
* {@code in.skip(n)} throws an IOException, * {@code in.skip(n)} throws an IOException,
* or an I/O error occurs. * or an I/O error occurs.
*/ */
public long skip(long n) throws IOException { public synchronized 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 {
ensureOpen(); ensureOpen();
if (n <= 0) { if (n <= 0) {
return 0; return 0;
@ -500,22 +448,7 @@ public class BufferedInputStream extends FilterInputStream {
* invoking its {@link #close()} method, * invoking its {@link #close()} method,
* or an I/O error occurs. * or an I/O error occurs.
*/ */
public int available() throws IOException { public synchronized 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 n = count - pos;
int avail = getInIfOpen().available(); int avail = getInIfOpen().available();
return n > (Integer.MAX_VALUE - avail) return n > (Integer.MAX_VALUE - avail)
@ -531,22 +464,7 @@ public class BufferedInputStream extends FilterInputStream {
* the mark position becomes invalid. * the mark position becomes invalid.
* @see java.io.BufferedInputStream#reset() * @see java.io.BufferedInputStream#reset()
*/ */
public void mark(int readlimit) { public synchronized 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; marklimit = readlimit;
markpos = pos; markpos = pos;
} }
@ -567,22 +485,7 @@ public class BufferedInputStream extends FilterInputStream {
* method, or an I/O error occurs. * method, or an I/O error occurs.
* @see java.io.BufferedInputStream#mark(int) * @see java.io.BufferedInputStream#mark(int)
*/ */
public void reset() throws IOException { public synchronized void reset() throws IOException {
if (lock != null) {
lock.lock();
try {
implReset();
} finally {
lock.unlock();
}
} else {
synchronized (this) {
implReset();
}
}
}
private void implReset() throws IOException {
ensureOpen(); ensureOpen();
if (markpos < 0) if (markpos < 0)
throw new IOException("Resetting to invalid mark"); throw new IOException("Resetting to invalid mark");
@ -628,23 +531,8 @@ public class BufferedInputStream extends FilterInputStream {
} }
@Override @Override
public long transferTo(OutputStream out) throws IOException { public synchronized long transferTo(OutputStream out) throws IOException {
Objects.requireNonNull(out, "out"); Objects.requireNonNull(out, "out");
if (lock != null) {
lock.lock();
try {
return implTransferTo(out);
} finally {
lock.unlock();
}
} else {
synchronized (this) {
return implTransferTo(out);
}
}
}
private long implTransferTo(OutputStream out) throws IOException {
if (getClass() == BufferedInputStream.class && markpos == -1) { if (getClass() == BufferedInputStream.class && markpos == -1) {
int avail = count - pos; int avail = count - pos;
if (avail > 0) { if (avail > 0) {

View file

@ -26,7 +26,6 @@
package java.io; package java.io;
import java.util.Arrays; import java.util.Arrays;
import jdk.internal.misc.InternalLock;
import jdk.internal.misc.VM; import jdk.internal.misc.VM;
/** /**
@ -47,9 +46,6 @@ public class BufferedOutputStream extends FilterOutputStream {
private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512; private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
private static final int DEFAULT_MAX_BUFFER_SIZE = 8192; 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. * The internal buffer where data is stored.
*/ */
@ -90,12 +86,9 @@ public class BufferedOutputStream extends FilterOutputStream {
} }
if (getClass() == BufferedOutputStream.class) { if (getClass() == BufferedOutputStream.class) {
// use InternalLock and resizable buffer when not sub-classed // resizable when not sub-classed
this.lock = InternalLock.newLockOrNull(); this.buf = new byte[initialSize];
this.buf = new byte[initialSize]; // resizable
} else { } else {
// use monitors and no resizing when sub-classed
this.lock = null;
this.buf = new byte[maxSize]; this.buf = new byte[maxSize];
} }
this.maxBufSize = maxSize; this.maxBufSize = maxSize;
@ -136,8 +129,6 @@ public class BufferedOutputStream extends FilterOutputStream {
* Grow buf to fit an additional len bytes if needed. * Grow buf to fit an additional len bytes if needed.
* If possible, it grows by len+1 to avoid flushing when len bytes * If possible, it grows by len+1 to avoid flushing when len bytes
* are added. A no-op if the buffer is not resizable. * 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) { private void growIfNeeded(int len) {
int neededSize = count + len + 1; int neededSize = count + len + 1;
@ -157,22 +148,7 @@ public class BufferedOutputStream extends FilterOutputStream {
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@Override @Override
public void write(int b) throws IOException { public synchronized 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); growIfNeeded(1);
if (count >= buf.length) { if (count >= buf.length) {
flushBuffer(); flushBuffer();
@ -198,22 +174,7 @@ public class BufferedOutputStream extends FilterOutputStream {
* @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc}
*/ */
@Override @Override
public void write(byte[] b, int off, int len) throws IOException { public synchronized 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 (len >= maxBufSize) {
/* If the request length exceeds the max size of the output buffer, /* If the request length exceeds the max size of the output buffer,
flush the output buffer and then write the data directly. flush the output buffer and then write the data directly.
@ -238,22 +199,7 @@ public class BufferedOutputStream extends FilterOutputStream {
* @see java.io.FilterOutputStream#out * @see java.io.FilterOutputStream#out
*/ */
@Override @Override
public void flush() throws IOException { public synchronized void flush() throws IOException {
if (lock != null) {
lock.lock();
try {
implFlush();
} finally {
lock.unlock();
}
} else {
synchronized (this) {
implFlush();
}
}
}
private void implFlush() throws IOException {
flushBuffer(); flushBuffer();
out.flush(); out.flush();
} }

View file

@ -32,7 +32,6 @@ import java.util.Spliterator;
import java.util.Spliterators; import java.util.Spliterators;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import jdk.internal.misc.InternalLock;
/** /**
* Reads text from a character-input stream, buffering characters so as to * Reads text from a character-input stream, buffering characters so as to
@ -181,37 +180,23 @@ public class BufferedReader extends Reader {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public int read() throws IOException { public int read() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); for (;;) {
try { if (nextChar >= nChars) {
return implRead(); fill();
} finally { if (nextChar >= nChars)
locker.unlock(); return -1;
}
} 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;
} }
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
return cb[nextChar++];
} }
return cb[nextChar++];
} }
} }
@ -296,38 +281,24 @@ public class BufferedReader extends Reader {
* @throws IOException {@inheritDoc} * @throws IOException {@inheritDoc}
*/ */
public int read(char[] cbuf, int off, int len) throws IOException { public int read(char[] cbuf, int off, int len) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); Objects.checkFromIndexSize(off, len, cbuf.length);
try { if (len == 0) {
return implRead(cbuf, off, len); return 0;
} finally {
locker.unlock();
} }
} else {
synchronized (lock) { int n = read1(cbuf, off, len);
return implRead(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;
} }
} }
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 * 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 * of a line feed ('\n'), a carriage return ('\r'), a carriage return
@ -347,81 +318,67 @@ public class BufferedReader extends Reader {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
String readLine(boolean ignoreLF, boolean[] term) throws IOException { String readLine(boolean ignoreLF, boolean[] term) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { StringBuilder s = null;
locker.lock(); int startChar;
try {
return implReadLine(ignoreLF, term);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return implReadLine(ignoreLF, term);
}
}
}
private String implReadLine(boolean ignoreLF, boolean[] term) throws IOException { ensureOpen();
StringBuilder s = null; boolean omitLF = ignoreLF || skipLF;
int startChar; if (term != null) term[0] = false;
ensureOpen(); bufferLoop:
boolean omitLF = ignoreLF || skipLF; for (;;) {
if (term != null) term[0] = false;
bufferLoop: if (nextChar >= nChars)
for (;;) { fill();
if (nextChar >= nChars) { /* EOF */
if (nextChar >= nChars) if (s != null && s.length() > 0)
fill(); return s.toString();
if (nextChar >= nChars) { /* EOF */ else
if (s != null && s.length() > 0) return null;
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;
} }
} boolean eol = false;
char c = 0;
int i;
startChar = nextChar; /* Skip a leftover '\n', if necessary */
nextChar = i; if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
if (eol) { charLoop:
String str; for (i = nextChar; i < nChars; i++) {
if (s == null) { c = cb[i];
str = new String(cb, startChar, i - startChar); if ((c == '\n') || (c == '\r')) {
} else { if (term != null) term[0] = true;
s.append(cb, startChar, i - startChar); eol = true;
str = s.toString(); break charLoop;
}
} }
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null) startChar = nextChar;
s = new StringBuilder(DEFAULT_EXPECTED_LINE_LENGTH); nextChar = i;
s.append(cb, startChar, i - startChar);
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(DEFAULT_EXPECTED_LINE_LENGTH);
s.append(cb, startChar, i - startChar);
}
} }
} }
@ -450,47 +407,33 @@ public class BufferedReader extends Reader {
if (n < 0L) { if (n < 0L) {
throw new IllegalArgumentException("skip value is negative"); throw new IllegalArgumentException("skip value is negative");
} }
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); long r = n;
try { while (r > 0) {
return implSkip(n); if (nextChar >= nChars)
} finally { fill();
locker.unlock(); if (nextChar >= nChars) /* EOF */
} break;
} else { if (skipLF) {
synchronized (lock) { skipLF = false;
return implSkip(n); if (cb[nextChar] == '\n') {
} nextChar++;
} }
} }
long d = nChars - nextChar;
private long implSkip(long n) throws IOException { if (r <= d) {
ensureOpen(); nextChar += (int)r;
long r = n; r = 0;
while (r > 0) { break;
if (nextChar >= nChars) }
fill(); else {
if (nextChar >= nChars) /* EOF */ r -= d;
break; nextChar = nChars;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
} }
} }
long d = nChars - nextChar; return n - r;
if (r <= d) {
nextChar += (int)r;
r = 0;
break;
}
else {
r -= d;
nextChar = nChars;
}
} }
return n - r;
} }
/** /**
@ -501,42 +444,28 @@ public class BufferedReader extends Reader {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public boolean ready() throws IOException { public boolean ready() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock();
try {
return implReady();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return implReady();
}
}
}
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 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()) { if (skipLF) {
fill(); /* Note that in.ready() will return true if and only if the next
} * read on the stream will not block.
if (nextChar < nChars) { */
if (cb[nextChar] == '\n') if (nextChar >= nChars && in.ready()) {
nextChar++; fill();
skipLF = false; }
if (nextChar < nChars) {
if (cb[nextChar] == '\n')
nextChar++;
skipLF = false;
}
} }
return (nextChar < nChars) || in.ready();
} }
return (nextChar < nChars) || in.ready();
} }
/** /**
@ -566,28 +495,14 @@ public class BufferedReader extends Reader {
if (readAheadLimit < 0) { if (readAheadLimit < 0) {
throw new IllegalArgumentException("Read-ahead limit < 0"); throw new IllegalArgumentException("Read-ahead limit < 0");
} }
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); this.readAheadLimit = readAheadLimit;
try { markedChar = nextChar;
implMark(readAheadLimit); markedSkipLF = skipLF;
} 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. * Resets the stream to the most recent mark.
* *
@ -595,55 +510,27 @@ public class BufferedReader extends Reader {
* or if the mark has been invalidated * or if the mark has been invalidated
*/ */
public void reset() throws IOException { public void reset() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); if (markedChar < 0)
try { throw new IOException((markedChar == INVALIDATED)
implReset(); ? "Mark invalid"
} finally { : "Stream not marked");
locker.unlock(); nextChar = markedChar;
} skipLF = markedSkipLF;
} 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 { public void close() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { if (in == null)
locker.lock(); return;
try { try {
implClose(); in.close();
} finally { } finally {
locker.unlock(); in = null;
cb = null;
} }
} else {
synchronized (lock) {
implClose();
}
}
}
private void implClose() throws IOException {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
} }
} }

View file

@ -27,7 +27,6 @@ package java.io;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import jdk.internal.misc.InternalLock;
import jdk.internal.misc.VM; import jdk.internal.misc.VM;
/** /**
@ -162,58 +161,30 @@ public class BufferedWriter extends Writer {
* may be invoked by PrintStream. * may be invoked by PrintStream.
*/ */
void flushBuffer() throws IOException { void flushBuffer() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); if (nextChar == 0)
try { return;
implFlushBuffer(); out.write(cb, 0, nextChar);
} finally { nextChar = 0;
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. * Writes a single character.
* *
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public void write(int c) throws IOException { public void write(int c) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); growIfNeeded(1);
try { if (nextChar >= nChars)
implWrite(c); flushBuffer();
} finally { cb[nextChar++] = (char) c;
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 * 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. * out of file descriptors and we're trying to print a stack trace.
@ -245,46 +216,32 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public void write(char[] cbuf, int off, int len) throws IOException { public void write(char[] cbuf, int off, int len) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); Objects.checkFromIndexSize(off, len, cbuf.length);
try { if (len == 0) {
implWrite(cbuf, off, len); return;
} finally {
locker.unlock();
} }
} else {
synchronized (lock) {
implWrite(cbuf, off, len);
}
}
}
private void implWrite(char[] cbuf, int off, int len) throws IOException { if (len >= maxChars) {
ensureOpen(); /* If the request length exceeds the max size of the output buffer,
Objects.checkFromIndexSize(off, len, cbuf.length); flush the buffer and then write the data directly. In this
if (len == 0) { way buffered streams will cascade harmlessly. */
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(); 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();
}
} }
} }
} }
@ -312,32 +269,18 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public void write(String s, int off, int len) throws IOException { public void write(String s, int off, int len) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); growIfNeeded(len);
try { int b = off, t = off + len;
implWrite(s, off, len); while (b < t) {
} finally { int d = min(nChars - nextChar, t - b);
locker.unlock(); s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
} }
} 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();
} }
} }
@ -358,52 +301,24 @@ public class BufferedWriter extends Writer {
* @throws IOException If an I/O error occurs * @throws IOException If an I/O error occurs
*/ */
public void flush() throws IOException { public void flush() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { flushBuffer();
locker.lock(); out.flush();
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") @SuppressWarnings("try")
private void implClose() throws IOException { public void close() throws IOException {
if (out == null) { synchronized (lock) {
return; if (out == null) {
} return;
try (Writer w = out) { }
flushBuffer(); try (Writer w = out) {
} finally { flushBuffer();
out = null; } finally {
cb = null; out = null;
cb = null;
}
} }
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,6 @@ package java.io;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetDecoder;
import jdk.internal.misc.InternalLock;
import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamDecoder;
/** /**
@ -62,20 +61,6 @@ import sun.nio.cs.StreamDecoder;
public class InputStreamReader extends Reader { public class InputStreamReader extends Reader {
private final StreamDecoder sd; 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 * Creates an InputStreamReader that uses the
* {@link Charset#defaultCharset() default charset}. * {@link Charset#defaultCharset() default charset}.
@ -88,7 +73,7 @@ public class InputStreamReader extends Reader {
public InputStreamReader(InputStream in) { public InputStreamReader(InputStream in) {
super(in); super(in);
Charset cs = Charset.defaultCharset(); Charset cs = Charset.defaultCharset();
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), cs); sd = StreamDecoder.forInputStreamReader(in, this, cs);
} }
/** /**
@ -110,7 +95,7 @@ public class InputStreamReader extends Reader {
super(in); super(in);
if (charsetName == null) if (charsetName == null)
throw new NullPointerException("charsetName"); throw new NullPointerException("charsetName");
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), charsetName); sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
} }
/** /**
@ -126,7 +111,7 @@ public class InputStreamReader extends Reader {
super(in); super(in);
if (cs == null) if (cs == null)
throw new NullPointerException("charset"); throw new NullPointerException("charset");
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), cs); sd = StreamDecoder.forInputStreamReader(in, this, cs);
} }
/** /**
@ -142,7 +127,7 @@ public class InputStreamReader extends Reader {
super(in); super(in);
if (dec == null) if (dec == null)
throw new NullPointerException("charset decoder"); throw new NullPointerException("charset decoder");
sd = StreamDecoder.forInputStreamReader(in, lockFor(this), dec); sd = StreamDecoder.forInputStreamReader(in, this, dec);
} }
/** /**

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,6 @@ package java.io;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import jdk.internal.misc.InternalLock;
import sun.nio.cs.StreamEncoder; import sun.nio.cs.StreamEncoder;
/** /**
@ -75,20 +74,6 @@ import sun.nio.cs.StreamEncoder;
public class OutputStreamWriter extends Writer { public class OutputStreamWriter extends Writer {
private final StreamEncoder se; 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. * Creates an OutputStreamWriter that uses the named charset.
* *
@ -108,7 +93,7 @@ public class OutputStreamWriter extends Writer {
super(out); super(out);
if (charsetName == null) if (charsetName == null)
throw new NullPointerException("charsetName"); throw new NullPointerException("charsetName");
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), charsetName); se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
} }
/** /**
@ -122,7 +107,7 @@ public class OutputStreamWriter extends Writer {
@SuppressWarnings("this-escape") @SuppressWarnings("this-escape")
public OutputStreamWriter(OutputStream out) { public OutputStreamWriter(OutputStream out) {
super(out); super(out);
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), se = StreamEncoder.forOutputStreamWriter(out, this,
out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset()); out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());
} }
@ -142,7 +127,7 @@ public class OutputStreamWriter extends Writer {
super(out); super(out);
if (cs == null) if (cs == null)
throw new NullPointerException("charset"); throw new NullPointerException("charset");
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), cs); se = StreamEncoder.forOutputStreamWriter(out, this, cs);
} }
/** /**
@ -161,7 +146,7 @@ public class OutputStreamWriter extends Writer {
super(out); super(out);
if (enc == null) if (enc == null)
throw new NullPointerException("charset encoder"); throw new NullPointerException("charset encoder");
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this), enc); se = StreamEncoder.forOutputStreamWriter(out, this, enc);
} }
/** /**

View file

@ -30,9 +30,6 @@ import java.util.Locale;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException; 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, * A {@code PrintStream} adds functionality to another output stream,
@ -67,9 +64,6 @@ import jdk.internal.misc.InternalLock;
public class PrintStream extends FilterOutputStream public class PrintStream extends FilterOutputStream
implements Appendable, Closeable implements Appendable, Closeable
{ {
// initialized to null when PrintStream is sub-classed
private final InternalLock lock;
private final boolean autoFlush; private final boolean autoFlush;
private boolean trouble = false; private boolean trouble = false;
private Formatter formatter; private Formatter formatter;
@ -117,13 +111,6 @@ public class PrintStream extends FilterOutputStream
this.charset = out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset(); this.charset = out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset();
this.charOut = new OutputStreamWriter(this, charset); this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut); 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 /* Variant of the private constructor so that the given charset name
@ -220,13 +207,6 @@ public class PrintStream extends FilterOutputStream
this.charOut = new OutputStreamWriter(this, charset); this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut); this.textOut = new BufferedWriter(charOut);
this.charset = charset; this.charset = charset;
// use monitors when PrintStream is sub-classed
if (getClass() == PrintStream.class) {
lock = InternalLock.newLockOrNull();
} else {
lock = null;
}
} }
/** /**
@ -420,30 +400,17 @@ public class PrintStream extends FilterOutputStream
*/ */
@Override @Override
public void flush() { public void flush() {
if (lock != null) { synchronized (this) {
lock.lock();
try { try {
implFlush(); ensureOpen();
} finally { out.flush();
lock.unlock();
} }
} else { catch (IOException x) {
synchronized (this) { trouble = true;
implFlush();
} }
} }
} }
private void implFlush() {
try {
ensureOpen();
out.flush();
}
catch (IOException x) {
trouble = true;
}
}
private boolean closing = false; /* To avoid recursive closing */ private boolean closing = false; /* To avoid recursive closing */
/** /**
@ -454,33 +421,20 @@ public class PrintStream extends FilterOutputStream
*/ */
@Override @Override
public void close() { public void close() {
if (lock != null) { synchronized (this) {
lock.lock(); if (!closing) {
try { closing = true;
implClose(); try {
} finally { textOut.close();
lock.unlock(); out.close();
}
catch (IOException x) {
trouble = true;
}
textOut = null;
charOut = null;
out = null;
} }
} 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;
} }
} }
@ -547,17 +501,11 @@ public class PrintStream extends FilterOutputStream
@Override @Override
public void write(int b) { public void write(int b) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { out.write(b);
implWrite(b); if ((b == '\n') && autoFlush)
} finally { out.flush();
lock.unlock();
}
} else {
synchronized (this) {
implWrite(b);
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -568,13 +516,6 @@ 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 * Writes {@code len} bytes from the specified byte array starting at
* offset {@code off} to this stream. If automatic flushing is * offset {@code off} to this stream. If automatic flushing is
@ -593,17 +534,11 @@ public class PrintStream extends FilterOutputStream
@Override @Override
public void write(byte[] buf, int off, int len) { public void write(byte[] buf, int off, int len) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { out.write(buf, off, len);
implWrite(buf, off, len); if (autoFlush)
} finally { out.flush();
lock.unlock();
}
} else {
synchronized (this) {
implWrite(buf, off, len);
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -614,14 +549,6 @@ 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 * Writes all bytes from the specified byte array to this stream. If
* automatic flushing is enabled then the {@code flush} method will be * automatic flushing is enabled then the {@code flush} method will be
@ -686,16 +613,17 @@ public class PrintStream extends FilterOutputStream
private void write(char[] buf) { private void write(char[] buf) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { textOut.write(buf);
implWrite(buf); textOut.flushBuffer();
} finally { charOut.flushBuffer();
lock.unlock(); if (autoFlush) {
} for (int i = 0; i < buf.length; i++)
} else { if (buf[i] == '\n') {
synchronized (this) { out.flush();
implWrite(buf); break;
}
} }
} }
} catch (InterruptedIOException x) { } catch (InterruptedIOException x) {
@ -705,37 +633,20 @@ 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 // Used to optimize away back-to-back flushing and synchronization when
// using println, but since subclasses could exist which depend on // using println, but since subclasses could exist which depend on
// observing a call to print followed by newLine() we only use this if // observing a call to print followed by newLine() we only use this if
// getClass() == PrintStream.class to avoid compatibility issues. // getClass() == PrintStream.class to avoid compatibility issues.
private void writeln(char[] buf) { private void writeln(char[] buf) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { textOut.write(buf);
implWriteln(buf); textOut.newLine();
} finally { textOut.flushBuffer();
lock.unlock(); charOut.flushBuffer();
} if (autoFlush)
} else { out.flush();
synchronized (this) {
implWriteln(buf);
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -746,29 +657,15 @@ 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) { private void write(String s) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { textOut.write(s);
implWrite(s); textOut.flushBuffer();
} finally { charOut.flushBuffer();
lock.unlock(); if (autoFlush && (s.indexOf('\n') >= 0))
} out.flush();
} else {
synchronized (this) {
implWrite(s);
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -779,32 +676,20 @@ 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 // Used to optimize away back-to-back flushing and synchronization when
// using println, but since subclasses could exist which depend on // using println, but since subclasses could exist which depend on
// observing a call to print followed by newLine we only use this if // observing a call to print followed by newLine we only use this if
// getClass() == PrintStream.class to avoid compatibility issues. // getClass() == PrintStream.class to avoid compatibility issues.
private void writeln(String s) { private void writeln(String s) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { textOut.write(s);
implWriteln(s); textOut.newLine();
} finally { textOut.flushBuffer();
lock.unlock(); charOut.flushBuffer();
} if (autoFlush)
} else { out.flush();
synchronized (this) {
implWriteln(s);
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -815,29 +700,15 @@ 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() { private void newLine() {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { textOut.newLine();
implNewLine(); textOut.flushBuffer();
} finally { charOut.flushBuffer();
lock.unlock(); if (autoFlush)
} out.flush();
} else {
synchronized (this) {
implNewLine();
}
} }
} }
catch (InterruptedIOException x) { catch (InterruptedIOException x) {
@ -848,15 +719,6 @@ 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 */ /* Methods that do not terminate lines */
/** /**
@ -1314,17 +1176,11 @@ public class PrintStream extends FilterOutputStream
*/ */
public PrintStream format(String format, Object ... args) { public PrintStream format(String format, Object ... args) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { if ((formatter == null) || (formatter.locale() != Locale.getDefault(Locale.Category.FORMAT)))
implFormat(format, args); formatter = new Formatter((Appendable) this);
} finally { formatter.format(Locale.getDefault(Locale.Category.FORMAT), format, args);
lock.unlock();
}
} else {
synchronized (this) {
implFormat(format, args);
}
} }
} catch (InterruptedIOException x) { } catch (InterruptedIOException x) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -1334,13 +1190,6 @@ public class PrintStream extends FilterOutputStream
return this; 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 * Writes a formatted string to this output stream using the specified
* format string and arguments. * format string and arguments.
@ -1383,17 +1232,11 @@ public class PrintStream extends FilterOutputStream
*/ */
public PrintStream format(Locale l, String format, Object ... args) { public PrintStream format(Locale l, String format, Object ... args) {
try { try {
if (lock != null) { synchronized (this) {
lock.lock(); ensureOpen();
try { if ((formatter == null) || (formatter.locale() != l))
implFormat(l, format, args); formatter = new Formatter(this, l);
} finally { formatter.format(l, format, args);
lock.unlock();
}
} else {
synchronized (this) {
implFormat(l, format, args);
}
} }
} catch (InterruptedIOException x) { } catch (InterruptedIOException x) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -1403,13 +1246,6 @@ public class PrintStream extends FilterOutputStream
return this; 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. * Appends the specified character sequence to this output stream.
* *
@ -1511,13 +1347,4 @@ public class PrintStream extends FilterOutputStream
public Charset charset() { public Charset charset() {
return charset; return charset;
} }
static {
SharedSecrets.setJavaIOCPrintStreamAccess(new JavaIOPrintStreamAccess() {
public Object lock(PrintStream ps) {
Object lock = ps.lock;
return (lock != null) ? lock : ps;
}
});
}
} }

View file

@ -31,9 +31,6 @@ import java.util.Locale;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException; 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 * Prints formatted representations of objects to a text-output stream. This
@ -377,27 +374,13 @@ public class PrintWriter extends Writer {
* @see #checkError() * @see #checkError()
*/ */
public void flush() { public void flush() {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implFlush(); ensureOpen();
} finally { out.flush();
locker.unlock(); } catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implFlush();
}
}
}
private void implFlush() {
try {
ensureOpen();
out.flush();
} catch (IOException x) {
trouble = true;
} }
} }
@ -408,29 +391,15 @@ public class PrintWriter extends Writer {
* @see #checkError() * @see #checkError()
*/ */
public void close() { public void close() {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implClose(); if (out != null) {
} finally { out.close();
locker.unlock(); out = null;
}
} catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implClose();
}
}
}
private void implClose() {
try {
if (out != null) {
out.close();
out = null;
}
} catch (IOException x) {
trouble = true;
} }
} }
@ -487,29 +456,15 @@ public class PrintWriter extends Writer {
* @param c int specifying a character to be written. * @param c int specifying a character to be written.
*/ */
public void write(int c) { public void write(int c) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implWrite(c); ensureOpen();
} finally { out.write(c);
locker.unlock(); } catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implWrite(c);
}
}
}
private void implWrite(int c) {
try {
ensureOpen();
out.write(c);
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} }
@ -525,29 +480,15 @@ public class PrintWriter extends Writer {
* to throw an {@code IndexOutOfBoundsException} * to throw an {@code IndexOutOfBoundsException}
*/ */
public void write(char[] buf, int off, int len) { public void write(char[] buf, int off, int len) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implWrite(buf, off, len); ensureOpen();
} finally { out.write(buf, off, len);
locker.unlock(); } catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implWrite(buf, off, len);
}
}
}
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) {
trouble = true;
} }
} }
@ -572,29 +513,15 @@ public class PrintWriter extends Writer {
* to throw an {@code IndexOutOfBoundsException} * to throw an {@code IndexOutOfBoundsException}
*/ */
public void write(String s, int off, int len) { public void write(String s, int off, int len) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implWrite(s, off, len); ensureOpen();
} finally { out.write(s, off, len);
locker.unlock(); } catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implWrite(s, off, len);
}
}
}
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) {
trouble = true;
} }
} }
@ -608,31 +535,17 @@ public class PrintWriter extends Writer {
} }
private void newLine() { private void newLine() {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implNewLine(); ensureOpen();
} finally { out.write(System.lineSeparator());
locker.unlock(); if (autoFlush)
out.flush();
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} else {
synchronized (lock) {
implNewLine();
}
}
}
private void implNewLine() {
try {
ensureOpen();
out.write(System.lineSeparator());
if (autoFlush)
out.flush();
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} }
@ -788,20 +701,9 @@ public class PrintWriter extends Writer {
* @param x the {@code boolean} value to be printed * @param x the {@code boolean} value to be printed
*/ */
public void println(boolean x) { public void println(boolean x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -813,20 +715,9 @@ public class PrintWriter extends Writer {
* @param x the {@code char} value to be printed * @param x the {@code char} value to be printed
*/ */
public void println(char x) { public void println(char x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -838,20 +729,9 @@ public class PrintWriter extends Writer {
* @param x the {@code int} value to be printed * @param x the {@code int} value to be printed
*/ */
public void println(int x) { public void println(int x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -863,20 +743,9 @@ public class PrintWriter extends Writer {
* @param x the {@code long} value to be printed * @param x the {@code long} value to be printed
*/ */
public void println(long x) { public void println(long x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -888,20 +757,9 @@ public class PrintWriter extends Writer {
* @param x the {@code float} value to be printed * @param x the {@code float} value to be printed
*/ */
public void println(float x) { public void println(float x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -913,20 +771,9 @@ public class PrintWriter extends Writer {
* @param x the {@code double} value to be printed * @param x the {@code double} value to be printed
*/ */
public void println(double x) { public void println(double x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -938,20 +785,9 @@ public class PrintWriter extends Writer {
* @param x the array of {@code char} values to be printed * @param x the array of {@code char} values to be printed
*/ */
public void println(char[] x) { public void println(char[] x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -963,20 +799,9 @@ public class PrintWriter extends Writer {
* @param x the {@code String} value to be printed * @param x the {@code String} value to be printed
*/ */
public void println(String x) { public void println(String x) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(x);
locker.lock(); println();
try {
print(x);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(x);
println();
}
} }
} }
@ -991,20 +816,9 @@ public class PrintWriter extends Writer {
*/ */
public void println(Object x) { public void println(Object x) {
String s = String.valueOf(x); String s = String.valueOf(x);
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { print(s);
locker.lock(); println();
try {
print(s);
println();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
print(s);
println();
}
} }
} }
@ -1150,38 +964,24 @@ public class PrintWriter extends Writer {
* @since 1.5 * @since 1.5
*/ */
public PrintWriter format(String format, Object ... args) { public PrintWriter format(String format, Object ... args) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implFormat(format, args); ensureOpen();
} finally { if ((formatter == null)
locker.unlock(); || (formatter.locale() != Locale.getDefault()))
} formatter = new Formatter(this);
} else { formatter.format(Locale.getDefault(), format, args);
synchronized (lock) { if (autoFlush)
implFormat(format, args); out.flush();
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} }
return this; 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;
}
}
/** /**
* Writes a formatted string to this writer using the specified format * Writes a formatted string to this writer using the specified format
* string and arguments. If automatic flushing is enabled, calls to this * string and arguments. If automatic flushing is enabled, calls to this
@ -1224,37 +1024,23 @@ public class PrintWriter extends Writer {
* @since 1.5 * @since 1.5
*/ */
public PrintWriter format(Locale l, String format, Object ... args) { public PrintWriter format(Locale l, String format, Object ... args) {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) {
locker.lock();
try { try {
implFormat(l, format, args); ensureOpen();
} finally { if ((formatter == null) || (formatter.locale() != l))
locker.unlock(); formatter = new Formatter(this, l);
} formatter.format(l, format, args);
} else { if (autoFlush)
synchronized (lock) { out.flush();
implFormat(l, format, args); } catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
} catch (IOException x) {
trouble = true;
} }
} }
return this; 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;
}
}
/** /**
* Appends the specified character sequence to this writer. * Appends the specified character sequence to this writer.
* *
@ -1346,12 +1132,4 @@ public class PrintWriter extends Writer {
write(c); write(c);
return this; return this;
} }
static {
SharedSecrets.setJavaIOCPrintWriterAccess(new JavaIOPrintWriterAccess() {
public Object lock(PrintWriter pw) {
return pw.lock;
}
});
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,6 @@ package java.io;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import jdk.internal.misc.InternalLock;
/** /**
* A {@code PushbackInputStream} adds * A {@code PushbackInputStream} adds
@ -54,10 +53,6 @@ import jdk.internal.misc.InternalLock;
* @since 1.0 * @since 1.0
*/ */
public class PushbackInputStream extends FilterInputStream { public class PushbackInputStream extends FilterInputStream {
// initialized to null when PushbackInputStream is sub-classed
private final InternalLock closeLock;
/** /**
* The pushback buffer. * The pushback buffer.
* @since 1.1 * @since 1.1
@ -101,13 +96,6 @@ public class PushbackInputStream extends FilterInputStream {
} }
this.buf = new byte[size]; this.buf = new byte[size];
this.pos = size; this.pos = size;
// use monitors when PushbackInputStream is sub-classed
if (getClass() == PushbackInputStream.class) {
closeLock = InternalLock.newLockOrNull();
} else {
closeLock = null;
}
} }
/** /**
@ -386,27 +374,12 @@ public class PushbackInputStream extends FilterInputStream {
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
public void close() throws IOException { public synchronized void close() throws IOException {
if (closeLock != null) { if (in == null)
closeLock.lock(); return;
try { in.close();
implClose(); in = null;
} finally { buf = null;
closeLock.unlock();
}
} else {
synchronized (this) {
implClose();
}
}
}
private void implClose() throws IOException {
if (in != null) {
in.close();
in = null;
buf = null;
}
} }
@Override @Override

View file

@ -28,7 +28,6 @@ package java.io;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.ReadOnlyBufferException; import java.nio.ReadOnlyBufferException;
import java.util.Objects; import java.util.Objects;
import jdk.internal.misc.InternalLock;
/** /**
* Abstract class for reading character streams. The only methods that a * Abstract class for reading character streams. The only methods that a
@ -283,21 +282,6 @@ public abstract class Reader implements Readable, Closeable {
this.lock = lock; 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. * Attempts to read characters into the specified character buffer.
* The buffer is used as a repository of characters as-is: the only * The buffer is used as a repository of characters as-is: the only
@ -429,35 +413,21 @@ public abstract class Reader implements Readable, Closeable {
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
if (n < 0L) if (n < 0L)
throw new IllegalArgumentException("skip value is negative"); throw new IllegalArgumentException("skip value is negative");
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { int nn = (int) Math.min(n, maxSkipBufferSize);
locker.lock(); if ((skipBuffer == null) || (skipBuffer.length < nn))
try { skipBuffer = new char[nn];
return implSkip(n); long r = n;
} finally { while (r > 0) {
locker.unlock(); int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
} if (nc == -1)
} else { break;
synchronized (lock) { r -= nc;
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. * Tells whether this stream is ready to be read.
* *

View file

@ -26,7 +26,6 @@
package java.io; package java.io;
import java.util.Objects; import java.util.Objects;
import jdk.internal.misc.InternalLock;
/** /**
* Abstract class for writing to character streams. The only methods that a * Abstract class for writing to character streams. The only methods that a
@ -162,21 +161,6 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
this.lock = this; 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 * Creates a new character-stream writer whose critical sections will
* synchronize on the given object. * synchronize on the given object.
@ -206,29 +190,15 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* If an I/O error occurs * If an I/O error occurs
*/ */
public void write(int c) throws IOException { public void write(int c) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { if (writeBuffer == null){
locker.lock(); writeBuffer = new char[WRITE_BUFFER_SIZE];
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. * Writes an array of characters.
* *
@ -305,35 +275,21 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* If an I/O error occurs * If an I/O error occurs
*/ */
public void write(String str, int off, int len) throws IOException { public void write(String str, int off, int len) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { char cbuf[];
locker.lock(); if (len <= WRITE_BUFFER_SIZE) {
try { if (writeBuffer == null) {
implWrite(str, off, len); writeBuffer = new char[WRITE_BUFFER_SIZE];
} finally { }
locker.unlock(); cbuf = writeBuffer;
} } else { // Don't permanently allocate very large buffers.
} else { cbuf = new char[len];
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. * Appends the specified character sequence to this writer.
* *

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,9 +27,7 @@ package java.lang;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import jdk.internal.access.SharedSecrets;
import jdk.internal.event.ThrowableTracer; import jdk.internal.event.ThrowableTracer;
import jdk.internal.misc.InternalLock;
/** /**
* The {@code Throwable} class is the superclass of all errors and * The {@code Throwable} class is the superclass of all errors and
@ -689,39 +687,27 @@ public class Throwable implements Serializable {
} }
private void printStackTrace(PrintStreamOrWriter s) { private void printStackTrace(PrintStreamOrWriter s) {
Object lock = s.lock();
if (lock instanceof InternalLock locker) {
locker.lock();
try {
lockedPrintStackTrace(s);
} finally {
locker.unlock();
}
} else synchronized (lock) {
lockedPrintStackTrace(s);
}
}
private void lockedPrintStackTrace(PrintStreamOrWriter s) {
// Guard against malicious overrides of Throwable.equals by // Guard against malicious overrides of Throwable.equals by
// using a Set with identity equality semantics. // using a Set with identity equality semantics.
Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>()); Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
dejaVu.add(this); dejaVu.add(this);
// Print our stack trace synchronized(s.lock()) {
s.println(this); // Print our stack trace
StackTraceElement[] trace = getOurStackTrace(); s.println(this);
for (StackTraceElement traceElement : trace) StackTraceElement[] trace = getOurStackTrace();
s.println("\tat " + traceElement); for (StackTraceElement traceElement : trace)
s.println("\tat " + traceElement);
// Print suppressed exceptions, if any // Print suppressed exceptions, if any
for (Throwable se : getSuppressed()) for (Throwable se : getSuppressed())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
// Print cause, if any // Print cause, if any
Throwable ourCause = getCause(); Throwable ourCause = getCause();
if (ourCause != null) if (ourCause != null)
ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu); ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
}
} }
/** /**
@ -733,7 +719,7 @@ public class Throwable implements Serializable {
String caption, String caption,
String prefix, String prefix,
Set<Throwable> dejaVu) { Set<Throwable> dejaVu) {
assert s.isLockedByCurrentThread(); assert Thread.holdsLock(s.lock());
if (dejaVu.contains(this)) { if (dejaVu.contains(this)) {
s.println(prefix + caption + "[CIRCULAR REFERENCE: " + this + "]"); s.println(prefix + caption + "[CIRCULAR REFERENCE: " + this + "]");
} else { } else {
@ -785,15 +771,6 @@ public class Throwable implements Serializable {
/** Returns the object to be locked when using this StreamOrWriter */ /** Returns the object to be locked when using this StreamOrWriter */
abstract Object lock(); abstract Object lock();
boolean isLockedByCurrentThread() {
Object lock = lock();
if (lock instanceof InternalLock locker) {
return locker.isHeldByCurrentThread();
} else {
return Thread.holdsLock(lock);
}
}
/** Prints the specified string as a line on this StreamOrWriter */ /** Prints the specified string as a line on this StreamOrWriter */
abstract void println(Object o); abstract void println(Object o);
} }
@ -806,7 +783,7 @@ public class Throwable implements Serializable {
} }
Object lock() { Object lock() {
return SharedSecrets.getJavaIOPrintStreamAccess().lock(printStream); return printStream;
} }
void println(Object o) { void println(Object o) {
@ -822,7 +799,7 @@ public class Throwable implements Serializable {
} }
Object lock() { Object lock() {
return SharedSecrets.getJavaIOPrintWriterAccess().lock(printWriter); return printWriter;
} }
void println(Object o) { void println(Object o) {

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.access;
import java.io.PrintStream;
public interface JavaIOPrintStreamAccess {
Object lock(PrintStream ps);
}

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.access;
import java.io.PrintWriter;
public interface JavaIOPrintWriterAccess {
Object lock(PrintWriter pw);
}

View file

@ -71,8 +71,6 @@ public class SharedSecrets {
private static JavaLangRefAccess javaLangRefAccess; private static JavaLangRefAccess javaLangRefAccess;
private static JavaLangReflectAccess javaLangReflectAccess; private static JavaLangReflectAccess javaLangReflectAccess;
private static JavaIOAccess javaIOAccess; private static JavaIOAccess javaIOAccess;
private static JavaIOPrintStreamAccess javaIOPrintStreamAccess;
private static JavaIOPrintWriterAccess javaIOPrintWriterAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaIOFilePermissionAccess javaIOFilePermissionAccess; private static JavaIOFilePermissionAccess javaIOFilePermissionAccess;
private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess; private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess;
@ -288,32 +286,6 @@ public class SharedSecrets {
return access; return access;
} }
public static void setJavaIOCPrintWriterAccess(JavaIOPrintWriterAccess a) {
javaIOPrintWriterAccess = a;
}
public static JavaIOPrintWriterAccess getJavaIOPrintWriterAccess() {
var access = javaIOPrintWriterAccess;
if (access == null) {
ensureClassInitialized(PrintWriter.class);
access = javaIOPrintWriterAccess;
}
return access;
}
public static void setJavaIOCPrintStreamAccess(JavaIOPrintStreamAccess a) {
javaIOPrintStreamAccess = a;
}
public static JavaIOPrintStreamAccess getJavaIOPrintStreamAccess() {
var access = javaIOPrintStreamAccess;
if (access == null) {
ensureClassInitialized(PrintStream.class);
access = javaIOPrintStreamAccess;
}
return access;
}
public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) { public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) {
javaIOFileDescriptorAccess = jiofda; javaIOFileDescriptorAccess = jiofda;
} }

View file

@ -1,84 +0,0 @@
/*
* Copyright (c) 2021, 2024, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.misc;
import java.util.concurrent.locks.ReentrantLock;
/**
* A reentrant mutual exclusion lock for internal use. The lock does not
* implement {@link java.util.concurrent.locks.Lock} or extend {@link
* java.util.concurrent.locks.ReentrantLock} so that it can be distinguished
* from lock objects accessible to subclasses of {@link java.io.Reader} and
* {@link java.io.Writer} (it is possible to create a Reader that uses a
* lock object of type ReentrantLock for example).
*/
public class InternalLock {
private static final boolean CAN_USE_INTERNAL_LOCK;
static {
String s = System.getProperty("jdk.io.useMonitors");
if (s != null && s.equals("false")) {
CAN_USE_INTERNAL_LOCK = true;
} else {
CAN_USE_INTERNAL_LOCK = false;
}
}
private final ReentrantLock lock;
private InternalLock() {
this.lock = new ReentrantLock();
}
/**
* Returns a new InternalLock or null.
*/
public static InternalLock newLockOrNull() {
return (CAN_USE_INTERNAL_LOCK) ? new InternalLock() : null;
}
/**
* Returns a new InternalLock or the given object.
*/
public static Object newLockOr(Object obj) {
return (CAN_USE_INTERNAL_LOCK) ? new InternalLock() : obj;
}
public boolean tryLock() {
return lock.tryLock();
}
public void lock() {
lock.lock();
}
public void unlock() {
lock.unlock();
}
public boolean isHeldByCurrentThread() {
return lock.isHeldByCurrentThread();
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -44,8 +44,6 @@ import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays; import java.util.Arrays;
import jdk.internal.misc.InternalLock;
public class StreamDecoder extends Reader { public class StreamDecoder extends Reader {
private static final int MIN_BYTE_BUFFER_SIZE = 32; private static final int MIN_BYTE_BUFFER_SIZE = 32;
@ -121,151 +119,95 @@ public class StreamDecoder extends Reader {
return read0(); return read0();
} }
private int read0() throws IOException {
Object lock = this.lock;
if (lock instanceof InternalLock locker) {
locker.lock();
try {
return lockedRead0();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return lockedRead0();
}
}
}
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
private int lockedRead0() throws IOException { private int read0() throws IOException {
// Return the leftover char, if there is one synchronized (lock) {
if (haveLeftoverChar) { // Return the leftover char, if there is one
haveLeftoverChar = false; if (haveLeftoverChar) {
return leftoverChar; haveLeftoverChar = false;
} return leftoverChar;
}
// Convert more bytes // Convert more bytes
char[] cb = new char[2]; char[] cb = new char[2];
int n = read(cb, 0, 2); int n = read(cb, 0, 2);
switch (n) { switch (n) {
case -1: case -1:
return -1; return -1;
case 2: case 2:
leftoverChar = cb[1]; leftoverChar = cb[1];
haveLeftoverChar = true; haveLeftoverChar = true;
// FALL THROUGH // FALL THROUGH
case 1: case 1:
return cb[0]; return cb[0];
default: default:
assert false : n; assert false : n;
return -1; return -1;
}
} }
} }
public int read(char[] cbuf, int offset, int length) throws IOException { public int read(char[] cbuf, int offset, int length) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { int off = offset;
locker.lock(); int len = length;
try {
return lockedRead(cbuf, offset, length); ensureOpen();
} finally { if ((off < 0) || (off > cbuf.length) || (len < 0) ||
locker.unlock(); ((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} }
} else { if (len == 0)
synchronized (lock) { return 0;
return lockedRead(cbuf, offset, length);
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
} }
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
// Read remaining characters
int nr = implRead(cbuf, off, off + len);
// At this point, n is either 1 if a leftover character was read,
// or 0 if no leftover character was read. If n is 1 and nr is -1,
// indicating EOF, then we don't return their sum as this loses data.
return (nr < 0) ? (n == 1 ? 1 : nr) : (n + nr);
} }
} }
private int lockedRead(char[] cbuf, int offset, int length) throws IOException {
int off = offset;
int len = length;
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
// Read remaining characters
int nr = implRead(cbuf, off, off + len);
// At this point, n is either 1 if a leftover character was read,
// or 0 if no leftover character was read. If n is 1 and nr is -1,
// indicating EOF, then we don't return their sum as this loses data.
return (nr < 0) ? (n == 1 ? 1 : nr) : (n + nr);
}
public boolean ready() throws IOException { public boolean ready() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); return haveLeftoverChar || implReady();
try {
return lockedReady();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
return lockedReady();
}
} }
} }
private boolean lockedReady() throws IOException {
ensureOpen();
return haveLeftoverChar || implReady();
}
public void close() throws IOException { public void close() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { if (closed)
locker.lock(); return;
try { try {
lockedClose(); implClose();
} finally { } finally {
locker.unlock(); closed = true;
} }
} else {
synchronized (lock) {
lockedClose();
}
}
}
private void lockedClose() throws IOException {
if (closed)
return;
try {
implClose();
} finally {
closed = true;
} }
} }
@ -274,25 +216,12 @@ public class StreamDecoder extends Reader {
} }
public void fillZeroToPosition() throws IOException { public void fillZeroToPosition() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { Arrays.fill(bb.array(), bb.arrayOffset(),
locker.lock(); bb.arrayOffset() + bb.position(), (byte)0);
try {
lockedFillZeroToPosition();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedFillZeroToPosition();
}
} }
} }
private void lockedFillZeroToPosition() {
Arrays.fill(bb.array(), bb.arrayOffset(), bb.arrayOffset() + bb.position(), (byte)0);
}
// -- Charset-based stream decoder impl -- // -- Charset-based stream decoder impl --
private final Charset cs; private final Charset cs;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -37,7 +37,6 @@ import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction; import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import jdk.internal.misc.InternalLock;
public final class StreamEncoder extends Writer { public final class StreamEncoder extends Writer {
@ -97,28 +96,14 @@ public final class StreamEncoder extends Writer {
} }
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { if (isOpen())
locker.lock(); implFlushBuffer();
try { else
lockedFlushBuffer(); throw new IOException("Stream closed");
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedFlushBuffer();
}
} }
} }
private void lockedFlushBuffer() throws IOException {
if (isOpen())
implFlushBuffer();
else
throw new IOException("Stream closed");
}
public void write(int c) throws IOException { public void write(int c) throws IOException {
char[] cbuf = new char[1]; char[] cbuf = new char[1];
cbuf[0] = (char) c; cbuf[0] = (char) c;
@ -126,30 +111,16 @@ public final class StreamEncoder extends Writer {
} }
public void write(char[] cbuf, int off, int len) throws IOException { public void write(char[] cbuf, int off, int len) throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); if ((off < 0) || (off > cbuf.length) || (len < 0) ||
try {
lockedWrite(cbuf, off, len);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedWrite(cbuf, off, len);
}
}
}
private void lockedWrite(char[] cbuf, int off, int len) throws IOException {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) { ((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} else if (len == 0) { } else if (len == 0) {
return; return;
}
implWrite(cbuf, off, len);
} }
implWrite(cbuf, off, len);
} }
public void write(String str, int off, int len) throws IOException { public void write(String str, int off, int len) throws IOException {
@ -164,73 +135,31 @@ public final class StreamEncoder extends Writer {
public void write(CharBuffer cb) throws IOException { public void write(CharBuffer cb) throws IOException {
int position = cb.position(); int position = cb.position();
try { try {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); implWrite(cb);
try {
lockedWrite(cb);
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedWrite(cb);
}
} }
} finally { } finally {
cb.position(position); cb.position(position);
} }
} }
private void lockedWrite(CharBuffer cb) throws IOException {
ensureOpen();
implWrite(cb);
}
public void flush() throws IOException { public void flush() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { ensureOpen();
locker.lock(); implFlush();
try {
lockedFlush();
} finally {
locker.unlock();
}
} else {
synchronized (lock) {
lockedFlush();
}
} }
} }
private void lockedFlush() throws IOException {
ensureOpen();
implFlush();
}
public void close() throws IOException { public void close() throws IOException {
Object lock = this.lock; synchronized (lock) {
if (lock instanceof InternalLock locker) { if (closed)
locker.lock(); return;
try { try {
lockedClose(); implClose();
} finally { } finally {
locker.unlock(); closed = true;
} }
} else {
synchronized (lock) {
lockedClose();
}
}
}
private void lockedClose() throws IOException {
if (closed)
return;
try {
implClose();
} finally {
closed = true;
} }
} }

View file

@ -32,7 +32,6 @@
* @summary Basic tests for Process and Environment Variable code * @summary Basic tests for Process and Environment Variable code
* @modules java.base/java.lang:open * @modules java.base/java.lang:open
* java.base/java.io:open * java.base/java.io:open
* java.base/jdk.internal.misc
* @requires !vm.musl * @requires !vm.musl
* @requires vm.flagless * @requires vm.flagless
* @library /test/lib * @library /test/lib
@ -2676,17 +2675,6 @@ public class Basic {
else unexpected(t);}} else unexpected(t);}}
static boolean isLocked(BufferedInputStream bis) throws Exception { static boolean isLocked(BufferedInputStream bis) throws Exception {
Field lockField = BufferedInputStream.class.getDeclaredField("lock");
lockField.setAccessible(true);
var lock = (jdk.internal.misc.InternalLock) lockField.get(bis);
if (lock != null) {
if (lock.tryLock()) {
lock.unlock();
return false;
} else {
return true;
}
}
return new Thread() { return new Thread() {
volatile boolean unlocked; volatile boolean unlocked;