From ea73e058521dd3139b54aa4e2af474c87ecffa5b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 4 Dec 2024 20:59:14 +0000 Subject: [PATCH] 8345181: (ch) Windows asynchronous channels may return temporary direct buffers to the buffer cache twice (win) Reviewed-by: alanb, michaelm --- .../WindowsAsynchronousFileChannelImpl.java | 15 ++++++++-- .../WindowsAsynchronousSocketChannelImpl.java | 29 ++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index 15ae425850e..e3f65f82f0c 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -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 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 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 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 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) { diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index 9f3916bad8c..f8b5fab4316 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -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 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 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 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 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