diff -r b43cc3b9ef40 -r 13b67c1420b8 src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java --- a/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java Thu Apr 25 09:12:40 2019 +0200 +++ b/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java Thu Apr 25 10:41:49 2019 +0100 @@ -35,6 +35,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.spi.SelectorProvider; import java.util.Objects; +import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; class SinkChannelImpl @@ -53,7 +54,8 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final Object stateLock = new Object(); + private final ReentrantLock stateLock = new ReentrantLock(); + private final Condition stateCondition = stateLock.newCondition(); // -- The following fields are protected by stateLock @@ -95,15 +97,19 @@ boolean blocking; // set state to ST_CLOSING - synchronized (stateLock) { + stateLock.lock(); + try { assert state < ST_CLOSING; state = ST_CLOSING; blocking = isBlocking(); + } finally { + stateLock.unlock(); } // wait for any outstanding write to complete if (blocking) { - synchronized (stateLock) { + stateLock.lock(); + try { assert state == ST_CLOSING; long th = thread; if (th != 0) { @@ -113,12 +119,14 @@ // wait for write operation to end while (thread != 0) { try { - stateLock.wait(); + stateCondition.await(); } catch (InterruptedException e) { interrupted = true; } } } + } finally { + stateLock.unlock(); } } else { // non-blocking mode: wait for write to complete @@ -127,9 +135,12 @@ } // set state to ST_KILLPENDING - synchronized (stateLock) { + stateLock.lock(); + try { assert state == ST_CLOSING; state = ST_KILLPENDING; + } finally { + stateLock.unlock(); } // close socket if not registered with Selector @@ -143,12 +154,15 @@ @Override public void kill() throws IOException { - synchronized (stateLock) { + stateLock.lock(); + try { assert thread == 0; if (state == ST_KILLPENDING) { state = ST_KILLED; nd.close(fd); } + } finally { + stateLock.unlock(); } } @@ -156,8 +170,11 @@ protected void implConfigureBlocking(boolean block) throws IOException { writeLock.lock(); try { - synchronized (stateLock) { + stateLock.lock(); + try { IOUtil.configureBlocking(fd, block); + } finally { + stateLock.unlock(); } } finally { writeLock.unlock(); @@ -212,11 +229,14 @@ // set hook for Thread.interrupt begin(); } - synchronized (stateLock) { + stateLock.lock(); + try { if (!isOpen()) throw new ClosedChannelException(); if (blocking) thread = NativeThread.current(); + } finally { + stateLock.unlock(); } } @@ -230,12 +250,15 @@ throws AsynchronousCloseException { if (blocking) { - synchronized (stateLock) { + stateLock.lock(); + try { thread = 0; // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateLock.notifyAll(); + stateCondition.signalAll(); } + } finally { + stateLock.unlock(); } // remove hook for Thread.interrupt end(completed); @@ -252,9 +275,13 @@ int n = 0; try { beginWrite(blocking); - do { - n = IOUtil.write(fd, src, -1, nd); - } while ((n == IOStatus.INTERRUPTED) && isOpen()); + n = IOUtil.write(fd, src, -1, nd); + if (blocking) { + while (IOStatus.okayToRetry(n) && isOpen()) { + park(Net.POLLOUT); + n = IOUtil.write(fd, src, -1, nd); + } + } } finally { endWrite(blocking, n > 0); assert IOStatus.check(n); @@ -275,9 +302,13 @@ long n = 0; try { beginWrite(blocking); - do { - n = IOUtil.write(fd, srcs, offset, length, nd); - } while ((n == IOStatus.INTERRUPTED) && isOpen()); + n = IOUtil.write(fd, srcs, offset, length, nd); + if (blocking) { + while (IOStatus.okayToRetry(n) && isOpen()) { + park(Net.POLLOUT); + n = IOUtil.write(fd, srcs, offset, length, nd); + } + } } finally { endWrite(blocking, n > 0); assert IOStatus.check(n);