8345181: (ch) Windows asynchronous channels may return temporary direct buffers to the buffer cache twice (win)

Reviewed-by: alanb, michaelm
This commit is contained in:
Brian Burkhalter 2024-12-04 20:59:14 +00:00
parent ee0f88c901
commit ea73e05852
2 changed files with 34 additions and 10 deletions

View File

@ -25,6 +25,8 @@
package sun.nio.ch;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.nio.ByteBuffer;
@ -34,6 +36,7 @@ import java.io.FileDescriptor;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.event.FileForceEvent;
import jdk.internal.invoke.MhUtil;
/**
* Windows implementation of AsynchronousFileChannel using overlapped I/O.
@ -383,10 +386,13 @@ public class WindowsAsynchronousFileChannelImpl
* Task that initiates read operation and handles completion result.
*/
private class ReadTask<A> implements Runnable, Iocp.ResultHandler {
private static final VarHandle RELEASED = MhUtil.findVarHandle(MethodHandles.lookup(),
"released", boolean.class);
private final ByteBuffer dst;
private final int pos, rem; // buffer position/remaining
private final long position; // file position
private final PendingFuture<Integer,A> result;
private volatile boolean released;
// set to dst if direct; otherwise set to substituted direct buffer
private volatile ByteBuffer buf;
@ -405,8 +411,9 @@ public class WindowsAsynchronousFileChannelImpl
}
void releaseBufferIfSubstituted() {
if (buf != dst)
if (buf != dst && RELEASED.compareAndSet(this, false, true)) {
Util.releaseTemporaryDirectBuffer(buf);
}
}
void updatePosition(int bytesTransferred) {
@ -569,10 +576,13 @@ public class WindowsAsynchronousFileChannelImpl
* Task that initiates write operation and handles completion result.
*/
private class WriteTask<A> implements Runnable, Iocp.ResultHandler {
private static final VarHandle RELEASED = MhUtil.findVarHandle(MethodHandles.lookup(),
"released", boolean.class);
private final ByteBuffer src;
private final int pos, rem; // buffer position/remaining
private final long position; // file position
private final PendingFuture<Integer,A> result;
private volatile boolean released;
// set to src if direct; otherwise set to substituted direct buffer
private volatile ByteBuffer buf;
@ -591,8 +601,9 @@ public class WindowsAsynchronousFileChannelImpl
}
void releaseBufferIfSubstituted() {
if (buf != src)
if (buf != src && RELEASED.compareAndSet(this, false, true)) {
Util.releaseTemporaryDirectBuffer(buf);
}
}
void updatePosition(int bytesTransferred) {

View File

@ -25,12 +25,15 @@
package sun.nio.ch;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.channels.*;
import java.nio.ByteBuffer;
import java.nio.BufferOverflowException;
import java.net.*;
import java.util.concurrent.*;
import java.io.IOException;
import jdk.internal.invoke.MhUtil;
import jdk.internal.misc.Unsafe;
import sun.net.util.SocketExceptions;
@ -367,10 +370,13 @@ class WindowsAsynchronousSocketChannelImpl
* result when the read completes.
*/
private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler {
private static final VarHandle RELEASED = MhUtil.findVarHandle(MethodHandles.lookup(),
"released", boolean.class);
private final ByteBuffer[] bufs;
private final int numBufs;
private final boolean scatteringRead;
private final PendingFuture<V,A> result;
private volatile boolean released;
// set by run method
private ByteBuffer[] shadow;
@ -461,12 +467,14 @@ class WindowsAsynchronousSocketChannelImpl
}
void releaseBuffers() {
for (int i=0; i<numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
if (RELEASED.compareAndSet(this, false, true)) {
for (int i = 0; i < numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
}
}
IOUtil.releaseScopes(scopeHandleReleasers);
}
IOUtil.releaseScopes(scopeHandleReleasers);
}
@Override
@ -641,10 +649,13 @@ class WindowsAsynchronousSocketChannelImpl
* result when the write completes.
*/
private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler {
private static final VarHandle RELEASED = MhUtil.findVarHandle(MethodHandles.lookup(),
"released", boolean.class);
private final ByteBuffer[] bufs;
private final int numBufs;
private final boolean gatheringWrite;
private final PendingFuture<V,A> result;
private volatile boolean released;
// set by run method
private ByteBuffer[] shadow;
@ -728,12 +739,14 @@ class WindowsAsynchronousSocketChannelImpl
}
void releaseBuffers() {
for (int i=0; i<numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
if (RELEASED.compareAndSet(this, false, true)) {
for (int i = 0; i < numBufs; i++) {
if (!(bufs[i] instanceof DirectBuffer)) {
Util.releaseTemporaryDirectBuffer(shadow[i]);
}
}
IOUtil.releaseScopes(scopeHandleReleasers);
}
IOUtil.releaseScopes(scopeHandleReleasers);
}
@Override