< prev index next >

src/java.base/share/classes/java/io/BufferedInputStream.java

Print this page
rev 13994 : 8153334: Replace BufferedInputStreams use of AtomicReferenceFieldUpdater with Unsafe
Reviewed-by: alanb, forax

*** 22,32 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; ! import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to --- 22,33 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; ! ! import jdk.internal.misc.Unsafe; /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to
*** 66,84 **** * a different size. */ protected volatile byte buf[]; /** ! * Atomic updater to provide compareAndSet for buf. This is ! * necessary because closes can be asynchronous. We use nullness * of buf[] as primary indicator that this stream is closed. (The * "in" field is also nulled out on close.) */ ! private static final ! AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = ! AtomicReferenceFieldUpdater.newUpdater ! (BufferedInputStream.class, byte[].class, "buf"); /** * The index one greater than the index of the last valid byte in * the buffer. * This value is always --- 67,91 ---- * a different size. */ protected volatile byte buf[]; /** ! * Get Unsafe and offset of buf to provide compareAndSet functionality. ! * This is necessary because closes can be asynchronous. We use nullness * of buf[] as primary indicator that this stream is closed. (The * "in" field is also nulled out on close.) */ ! private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ! private static final long BUF_OFFSET; ! static { ! try { ! BUF_OFFSET = UNSAFE.objectFieldOffset( ! BufferedInputStream.class.getDeclaredField("buf")); ! } catch (ReflectiveOperationException e) { ! throw new Error(e); ! } ! } /** * The index one greater than the index of the last valid byte in * the buffer. * This value is always
*** 210,222 **** * This method also assumes that all data has already been read in, * hence pos > count. */ private void fill() throws IOException { byte[] buffer = getBufIfOpen(); ! if (markpos < 0) pos = 0; /* no mark: throw away the buffer */ ! else if (pos >= buffer.length) /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0; --- 217,229 ---- * This method also assumes that all data has already been read in, * hence pos > count. */ private void fill() throws IOException { byte[] buffer = getBufIfOpen(); ! if (markpos < 0) { pos = 0; /* no mark: throw away the buffer */ ! } else if (pos >= buffer.length) { /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0;
*** 230,249 **** pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); ! if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; } --- 237,258 ---- pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); ! if (!UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, ! nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } + } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; }
*** 474,484 **** * @exception IOException if an I/O error occurs. */ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { ! if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; --- 483,493 ---- * @exception IOException if an I/O error occurs. */ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { ! if (UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return;
< prev index next >