[PATCH] 6350055: Atomic SelectionKey operations
David Lloyd
david.lloyd at redhat.com
Mon Apr 16 22:34:05 UTC 2018
On Fri, Mar 30, 2018 at 7:50 AM, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> Once the queuing of updates is changed (to drop updateEvents) then this will
> be a lot simpler.
Since some of the SelectionKey stuff has settled down a bit, I
re-rebased this small patch. I've also located an old bug ID [1]
which covers this functionality, though it would have to be reopened.
Given our previous discussion I feel pretty confident that this can be
done without too much controversy.
The patch is attached and also available online here [2]. This time
I'm opting to keep my local patch version number in sync with the
patch version number I post and see how that works out.
No tests or anything yet (just compile-tested so far); I want to
validate the proposed API, and also my understanding of the selection
key implementation's new behavior.
[1] https://bugs.openjdk.java.net/browse/JDK-6350055
[2] https://github.com/dmlloyd/openjdk/commit/atomic-nio-ops-v4
--
- DML
-------------- next part --------------
commit 770020a6af5ec88b4ee67c0ffa3db903a3004444
Author: David M. Lloyd <david.lloyd at redhat.com>
Date: Wed Mar 28 13:13:44 2018 -0500
[JDK-6350055] Add atomic interest op methods to SelectionKey
diff --git a/src/java.base/share/classes/java/nio/channels/SelectionKey.java b/src/java.base/share/classes/java/nio/channels/SelectionKey.java
index 6af664fa96b..8983093ade2 100644
--- a/src/java.base/share/classes/java/nio/channels/SelectionKey.java
+++ b/src/java.base/share/classes/java/nio/channels/SelectionKey.java
@@ -196,6 +196,82 @@ public abstract class SelectionKey {
*/
public abstract SelectionKey interestOps(int ops);
+ /**
+ * Atomically sets this key's interest set to bitwise union ("or") of the existing
+ * interest set and the given value. This method is guaranteed to be
+ * atomic with respect to other concurrent calls to this method or to
+ * {@link #interestOpsAnd(int)}.
+ *
+ * <p> This method may be invoked at any time. Whether or not it blocks,
+ * and for how long, is implementation-dependent.
+ *
+ * @param ops The interest set to apply
+ *
+ * @return The previous interest set
+ *
+ * @throws IllegalArgumentException
+ * If a bit in the resultant set does not correspond to an operation that
+ * is supported by this key's channel, that is, if
+ * {@code ((interestOps() | ops) & ~channel().validOps()) != 0}
+ *
+ * @throws CancelledKeyException
+ * If this key has been cancelled
+ *
+ * @implSpec The default implementation synchronizes on this {@code SelectionKey}
+ * instance, calling {@link #interestOps()} and {@link #interestOps(int)}
+ * in turn; subclasses should provide a better implementation if
+ * possible (for example, using a
+ * {@link java.lang.invoke.VarHandle VarHandle} may be appropriate).
+ */
+ public int interestOpsOr(int ops) {
+ synchronized (this) {
+ int oldVal = interestOps();
+ interestOps(oldVal | ops);
+ return oldVal;
+ }
+ }
+
+ /**
+ * Atomically sets this key's interest set to bitwise intersection ("and") of the
+ * existing interest set and the given value. This method is guaranteed to be
+ * atomic with respect to other concurrent calls to this method or to
+ * {@link #interestOpsOr(int)}.
+ *
+ * <p> This method may be invoked at any time. Whether or not it blocks,
+ * and for how long, is implementation-dependent.
+ *
+ * @param ops The interest set to apply
+ *
+ * @return The previous interest set
+ *
+ * @throws IllegalArgumentException
+ * If a bit in the resultant set does not correspond to an operation that
+ * is supported by this key's channel, that is, if
+ * {@code (interestOps() & ops & ~channel().validOps()) != 0}
+ *
+ * @throws CancelledKeyException
+ * If this key has been cancelled
+ *
+ * @apiNote The {@code ops} argument may contain bits which are not normally
+ * allowed by this key's channel, allowing bits to be cleared using
+ * bitwise complement values. For example,
+ * {@code interestOpsAnd(~SelectionKey.OP_READ)} will remove the
+ * {@code OP_READ} bit from the set without affecting other bits.
+ *
+ * @implSpec The default implementation synchronizes on this {@code SelectionKey}
+ * instance, calling {@link #interestOps()} and {@link #interestOps(int)}
+ * in turn; subclasses should provide a better implementation if
+ * possible (for example, using a
+ * {@link java.lang.invoke.VarHandle VarHandle} may be appropriate).
+ */
+ public int interestOpsAnd(int ops) {
+ synchronized (this) {
+ int oldVal = interestOps();
+ interestOps(oldVal & ops);
+ return oldVal;
+ }
+ }
+
/**
* Retrieves this key's ready-operation set.
*
diff --git a/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java b/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java
index 2f917c8d2e3..26b2afe2f08 100644
--- a/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/SelectionKeyImpl.java
@@ -25,6 +25,9 @@
package sun.nio.ch;
+import java.lang.invoke.ConstantBootstraps;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
@@ -42,6 +45,10 @@ public final class SelectionKeyImpl
private final SelChImpl channel;
private final SelectorImpl selector;
+ private static final VarHandle interestOpsHandle = ConstantBootstraps.fieldVarHandle(
+ MethodHandles.lookup(), "interestOps", VarHandle.class, SelectionKeyImpl.class, int.class
+ );
+
private volatile int interestOps;
private volatile int readyOps;
@@ -84,7 +91,35 @@ public final class SelectionKeyImpl
@Override
public SelectionKey interestOps(int ops) {
ensureValid();
- return nioInterestOps(ops);
+ if ((ops & ~channel().validOps()) != 0)
+ throw new IllegalArgumentException();
+ int oldOps = (int) interestOpsHandle.getAndSet(this, ops);
+ if (ops != oldOps) {
+ selector.setEventOps(this);
+ }
+ return this;
+ }
+
+ @Override
+ public int interestOpsOr(final int ops) {
+ ensureValid();
+ if ((ops & ~channel().validOps()) != 0)
+ throw new IllegalArgumentException();
+ int oldVal = (int) interestOpsHandle.getAndBitwiseOr(this, ops);
+ if (oldVal != (oldVal | ops)) {
+ selector.setEventOps(this);
+ }
+ return oldVal;
+ }
+
+ @Override
+ public int interestOpsAnd(final int ops) {
+ ensureValid();
+ int oldVal = (int) interestOpsHandle.getAndBitwiseAnd(this, ops);
+ if (oldVal != (oldVal & ops)) {
+ selector.setEventOps(this);
+ }
+ return oldVal;
}
@Override
More information about the nio-dev
mailing list