[PATCH] 6350055: Atomic SelectionKey operations

David Lloyd david.lloyd at redhat.com
Wed May 23 13:28:37 UTC 2018


The prophesied time has come.  Here's the updated version [1], also attached.

[1] https://github.com/dmlloyd/openjdk/tree/atomic-nio-ops-v7

On Tue, Apr 17, 2018 at 6:26 AM, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> On 16/04/2018 23:34, David Lloyd wrote:
>>
>> 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].
>
> The spec looks okay except that it will need to be adjusted once we get the
> changes for JDK-8201315 into jdk/jdk. If we get that in then the paragraph
> on when interestOpsXXX can be called will change to:
>
> "This method may be invoked at any time.  If this method is invoked while a
> selection operation is in progress then it has no effect upon that
> operation; the change to the key's interest set will be seen by the  next
> selection operation."
>
> -Alan



-- 
- DML
-------------- next part --------------
commit 39d09079a16a67a12d43cd8d09e6089d286b5b89
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 ad08fe43822..cfc4faeae8e 100644
--- a/src/java.base/share/classes/java/nio/channels/SelectionKey.java
+++ b/src/java.base/share/classes/java/nio/channels/SelectionKey.java
@@ -189,6 +189,86 @@ 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.  If this method is invoked
+     * while a selection operation is in progress then it has no effect upon
+     * that operation; the change to the key's interest set will be seen by the
+     * next selection operation.
+     *
+     * @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.  If this method is invoked
+     * while a selection operation is in progress then it has no effect upon
+     * that operation; the change to the key's interest set will be seen by the
+     * next selection operation.
+     *
+     * @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