jdk9 VarHandle and Fence methods

classic Classic list List threaded Threaded
73 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

jdk9 VarHandle and Fence methods

Doug Lea

For those of you who haven't been following this on the jmm-dev list:

We are NOT planning a full JMM memory model update for jdk9 -- there
are still unresolved issues in revising the formal core model.
However, jdk9 will include APIs for VarHandles (a scaled-down version of
the "enhanced volatiles" JEP), that together with some other
support replaces the need to use of Unsafe to obtain these
effects and does so compatibly with C/C++11 atomics. To do this, we
must, until the next full JMM update, provide specs that are
clear to readers (at least those familiar with the underlying
concepts) but not formally tied to a base model, (Which limits
how much we can say in them.)

The tentative methods are pasted below and also at
   http://gee.cs.oswego.edu/dl/wwwtmp/Fodder.java
The javadocs currently do not include any examples helping to
explain why you would ever want to use any of these methods.

The actual VarHandle class will look a bit different because
it will rely on specializations of polymorphic signatures.
(Current versions can be found in the openjdk mercurial
"jdk9/sandbox" repo.) And the "Fences" method may end up
in a different java.lang.* utility class. We'd also retrofit
j.u.c.atomic.Atomic* classes to use compatible methods/names.

Comments welcome.

...

/**
  * Stand-in for spec purposes of jdk9 java.lang.invoke.VarHandle
  */
abstract class NotReallyVarHandle<T> {
     // Load

     /**
      * Returns the value, with memory semantics of reading a
      * non-volatile variable.
      *
      * @return the value
      */
     T getRelaxed(Object owner);

     /**
      * Returns the value, with memory semantics of reading a volatile
      * variable.
      *
      * @return the value
      */
     T getVolatile(Object owner);

     /**
      * Returns the value, and ensures that subsequent loads and stores
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

     /**
      * Returns the value, accessed in program order, but with no
      * assurance of memory ordering effects with respect to other
      * threads.
      *
      * @return the value
      */
     T getOpaque(Object owner);

     // Store

     /**
      * Sets the value, with memory semantics of setting a non-volatile
      * variable.
      *
      * @param val the new value
      */
     void setRelaxed(Object owner, T val);

     /**
      * Sets the value, with memory semantics of setting a volatile
      * variable.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_seq_cst.
      *
      * @param val the new value
      */
     void setVolatile(Object owner, T val);

     /**
      * Sets the value, and ensures that prior loads and stores are not
      * reordered after this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_release ordering.
      *
      * @param val the new value
      */
     void setRelease(Object owner, T val);

     /**
      * Sets the value, in program order, but with no assurance of
      * memory ordering effects with respect to other threads.
      *
      * @param val the new value
      */
     void setOpaque(Object owner, T val);

     // CAS

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setVolatile if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getVolatile.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
     boolean compareAndSet(Object owner, T expected, T val);

     // Value-returning compare and exchange

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setVolatile if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getVolatile.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeVolatile(Object owner, T expected, T val);

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setRelaxed if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getAcquire.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeAcquire(Object owner, T expected, T val);

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setRelease if the current value {@code ==}
      * the expected value, as accessed with the memory samantics of
      * getRelease.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeRelease(Object owner, T expected, T val);

     // Weak (spurious failures allowed)

     /**
      * Possibly atomically sets the value to the given updated value
      * with the semantics of setRelaxed if the current value {@code
      * ==} the expected value, as as accessed with the memory
      * semantics of getRelaxed.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetRelaxed(Object owner, T expected, T val);

     /**
      * Possibly atomically sets the value to the given updated value
      * with the memory semantics of setRelaxed if the current value
      * {@code ==} the expected value, as as accessed with the memory
      * semantics of getAcquire.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetAcquire(Object owner, T expected, T val);

     /**
      * Possibly atomically sets the value to the given updated value
      * with the memory semantics of setRelease if the current value
      * {@code ==} the expected value, as as accessed with the memory
      * semantics of getRelaxed.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetRelease(Object owner, T expected, T val);

     // special RMW

     /**
      * Atomically sets to the given value with the memory semantics of
      * setVolatile and returns the old value.
      *
      * @param newValue the new value
      * @return the previous value
      */
     T getAndSet(Object owner, T val);

     /**
      * Atomically adds the given value to the current value with the
      * memory semantics of setVolatile.
      *
      * @param delta the value to add
      * @return the previous value
      */
     T getAndAdd(Object owner, T delta);

     /**
      * Atomically adds the given value to the current value with the
      * memory semantics of setVolatile.
      *
      * @param delta the value to add
      * @return the current value
      */
     T addAndGet(Object owner, T delta);
}

/**
  * A set of methods providing fine-grained control of memory ordering.
  *
  * <p>The Java Language Specification permits operations to be
  * executed in orders different than are apparent in program source
  * code, subject to constraints mainly arising from the use of locks
  * and volatile fields. The methods of this class can also be used to
  * impose constraints. Their specifications are phrased in terms of
  * the lack of "reorderings" -- observable ordering effects that might
  * otherwise occur if the fence were not present.
  *
  * @apiNote More precise phrasing of these specifications may
  * accompany future updates of the Java Language Specification.
  */
public class Fences {

     /**
      * Ensures that loads and stores before the fence will not be
      * reordered with loads and stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_seq_cst)
      */
     public static void fullFence() {}

     /**
      * Ensures that loads before the fence will not be reordered with
      * loads and stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_acquire)
      */
     public static void acquireFence() {}

     /**
      * Ensures that loads and stores before the fence will not be
      * reordered with stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_release)
      */
     public static void releaseFence() {}

     /**
      * Ensures that loads before the fence will not be reordered with
      * loads after the fence.
      */
     public static void loadLoadFence() {}

     /**
      * Ensures that stores before the fence will not be reordered with
      * stores after the fence.
      */
     public static void storeStoreFence() {}

}

class java.lang.ref.Reference {
     // add:

     /**
      * Ensures that the object referenced by the given reference
      * remains <em>strongly reachable</em> (as defined in the {@link
      * java.lang.ref} package documentation), regardless of any prior
      * actions of the program that might otherwise cause the object to
      * become unreachable; thus, the referenced object is not
      * reclaimable by garbage collection at least until after the
      * invocation of this method. Invocation of this method does not
      * itself initiate garbage collection or finalization.
      *
      * @param ref the reference. If null, this method has no effect.
      */
     public static void reachabilityFence(Object ref) {}

}
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Nathan Reynolds-2
What is the difference between getRelaxed() and getOpaque()?  I realize that specifies the semantics of reading a non-volatile variable and the other has no guarantees what so ever.   What's up with reading a non-volatile variable?

getOpaque() versus setVolatile() - Which one wins?  getOpaque() kind of says it can be re-ordered but setVolatile() forces an ordering.  Does getOpaque() get to be re-ordered with respect to a setVolatile()?  How about the Fence APIs?

For compareAndSet____() methods, should the variable names be (Object owner, T expect, T update) to match that of Atomic___ classes?

Are you going to supply a web page similar to JSR 133 Cookbook?  http://g.oswego.edu/dl/jmm/cookbook.html  I find this page extremely helpful.

I missed the conversation on reachabilityFence().  How do I use this?
-Nathan
On 8/21/2015 6:44 AM, Doug Lea wrote:

For those of you who haven't been following this on the jmm-dev list:

We are NOT planning a full JMM memory model update for jdk9 -- there
are still unresolved issues in revising the formal core model.
However, jdk9 will include APIs for VarHandles (a scaled-down version of
the "enhanced volatiles" JEP), that together with some other
support replaces the need to use of Unsafe to obtain these
effects and does so compatibly with C/C++11 atomics. To do this, we
must, until the next full JMM update, provide specs that are
clear to readers (at least those familiar with the underlying
concepts) but not formally tied to a base model, (Which limits
how much we can say in them.)

The tentative methods are pasted below and also at
  http://gee.cs.oswego.edu/dl/wwwtmp/Fodder.java
The javadocs currently do not include any examples helping to
explain why you would ever want to use any of these methods.

The actual VarHandle class will look a bit different because
it will rely on specializations of polymorphic signatures.
(Current versions can be found in the openjdk mercurial
"jdk9/sandbox" repo.) And the "Fences" method may end up
in a different java.lang.* utility class. We'd also retrofit
j.u.c.atomic.Atomic* classes to use compatible methods/names.

Comments welcome.

...

/**
 * Stand-in for spec purposes of jdk9 java.lang.invoke.VarHandle
 */
abstract class NotReallyVarHandle<T> {
    // Load

    /**
     * Returns the value, with memory semantics of reading a
     * non-volatile variable.
     *
     * @return the value
     */
    T getRelaxed(Object owner);

    /**
     * Returns the value, with memory semantics of reading a volatile
     * variable.
     *
     * @return the value
     */
    T getVolatile(Object owner);

    /**
     * Returns the value, and ensures that subsequent loads and stores
     * are not reordered before this access.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * memory_order_acquire ordering.
     *
     * @return the value
     */
    T getAcquire(Object owner);

    /**
     * Returns the value, accessed in program order, but with no
     * assurance of memory ordering effects with respect to other
     * threads.
     *
     * @return the value
     */
    T getOpaque(Object owner);

    // Store

    /**
     * Sets the value, with memory semantics of setting a non-volatile
     * variable.
     *
     * @param val the new value
     */
    void setRelaxed(Object owner, T val);

    /**
     * Sets the value, with memory semantics of setting a volatile
     * variable.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * memory_order_seq_cst.
     *
     * @param val the new value
     */
    void setVolatile(Object owner, T val);

    /**
     * Sets the value, and ensures that prior loads and stores are not
     * reordered after this access.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * memory_order_release ordering.
     *
     * @param val the new value
     */
    void setRelease(Object owner, T val);

    /**
     * Sets the value, in program order, but with no assurance of
     * memory ordering effects with respect to other threads.
     *
     * @param val the new value
     */
    void setOpaque(Object owner, T val);

    // CAS

    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setVolatile if the current value {@code ==}
     * the expected value, as accessed with the memory semantics of
     * getVolatile.
     *
     * @param expected the expected value
     * @param val the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    boolean compareAndSet(Object owner, T expected, T val);

    // Value-returning compare and exchange

    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setVolatile if the current value {@code ==}
     * the expected value, as accessed with the memory semantics of
     * getVolatile.
     *
     * @param expected the expected value
     * @param val the new value
     * @return the current value, which will be the same as {@code val} if
     * successful.
     */
    T compareAndExchangeVolatile(Object owner, T expected, T val);

    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setRelaxed if the current value {@code ==}
     * the expected value, as accessed with the memory semantics of
     * getAcquire.
     *
     * @param expected the expected value
     * @param val the new value
     * @return the current value, which will be the same as {@code val} if
     * successful.
     */
    T compareAndExchangeAcquire(Object owner, T expected, T val);

    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setRelease if the current value {@code ==}
     * the expected value, as accessed with the memory samantics of
     * getRelease.
     *
     * @param expected the expected value
     * @param val the new value
     * @return the current value, which will be the same as {@code val} if
     * successful.
     */
    T compareAndExchangeRelease(Object owner, T expected, T val);

    // Weak (spurious failures allowed)

    /**
     * Possibly atomically sets the value to the given updated value
     * with the semantics of setRelaxed if the current value {@code
     * ==} the expected value, as as accessed with the memory
     * semantics of getRelaxed.  This operation may fail spuriously
     * (typically, due to memory contention) even if the current value
     * does match the expected value.
     *
     * @param expected the expected value
     * @param val the new value
     * @return {@code true} if successful
     */
    boolean weakCompareAndSetRelaxed(Object owner, T expected, T val);

    /**
     * Possibly atomically sets the value to the given updated value
     * with the memory semantics of setRelaxed if the current value
     * {@code ==} the expected value, as as accessed with the memory
     * semantics of getAcquire.  This operation may fail spuriously
     * (typically, due to memory contention) even if the current value
     * does match the expected value.
     *
     * @param expected the expected value
     * @param val the new value
     * @return {@code true} if successful
     */
    boolean weakCompareAndSetAcquire(Object owner, T expected, T val);

    /**
     * Possibly atomically sets the value to the given updated value
     * with the memory semantics of setRelease if the current value
     * {@code ==} the expected value, as as accessed with the memory
     * semantics of getRelaxed.  This operation may fail spuriously
     * (typically, due to memory contention) even if the current value
     * does match the expected value.
     *
     * @param expected the expected value
     * @param val the new value
     * @return {@code true} if successful
     */
    boolean weakCompareAndSetRelease(Object owner, T expected, T val);

    // special RMW

    /**
     * Atomically sets to the given value with the memory semantics of
     * setVolatile and returns the old value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    T getAndSet(Object owner, T val);

    /**
     * Atomically adds the given value to the current value with the
     * memory semantics of setVolatile.
     *
     * @param delta the value to add
     * @return the previous value
     */
    T getAndAdd(Object owner, T delta);

    /**
     * Atomically adds the given value to the current value with the
     * memory semantics of setVolatile.
     *
     * @param delta the value to add
     * @return the current value
     */
    T addAndGet(Object owner, T delta);
}

/**
 * A set of methods providing fine-grained control of memory ordering.
 *
 * <p>The Java Language Specification permits operations to be
 * executed in orders different than are apparent in program source
 * code, subject to constraints mainly arising from the use of locks
 * and volatile fields. The methods of this class can also be used to
 * impose constraints. Their specifications are phrased in terms of
 * the lack of "reorderings" -- observable ordering effects that might
 * otherwise occur if the fence were not present.
 *
 * @apiNote More precise phrasing of these specifications may
 * accompany future updates of the Java Language Specification.
 */
public class Fences {

    /**
     * Ensures that loads and stores before the fence will not be
     * reordered with loads and stores after the fence.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * atomic_thread_fence(memory_order_seq_cst)
     */
    public static void fullFence() {}

    /**
     * Ensures that loads before the fence will not be reordered with
     * loads and stores after the fence.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * atomic_thread_fence(memory_order_acquire)
     */
    public static void acquireFence() {}

    /**
     * Ensures that loads and stores before the fence will not be
     * reordered with stores after the fence.
     *
     * @apiNote Ignoring the many semantic differences from C and
     * C++, this method has memory ordering effects compatible with
     * atomic_thread_fence(memory_order_release)
     */
    public static void releaseFence() {}

    /**
     * Ensures that loads before the fence will not be reordered with
     * loads after the fence.
     */
    public static void loadLoadFence() {}

    /**
     * Ensures that stores before the fence will not be reordered with
     * stores after the fence.
     */
    public static void storeStoreFence() {}

}

class java.lang.ref.Reference {
    // add:

    /**
     * Ensures that the object referenced by the given reference
     * remains <em>strongly reachable</em> (as defined in the {@link
     * java.lang.ref} package documentation), regardless of any prior
     * actions of the program that might otherwise cause the object to
     * become unreachable; thus, the referenced object is not
     * reclaimable by garbage collection at least until after the
     * invocation of this method. Invocation of this method does not
     * itself initiate garbage collection or finalization.
     *
     * @param ref the reference. If null, this method has no effect.
     */
    public static void reachabilityFence(Object ref) {}

}
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
For some similar questions and answers, see today's archives of
   jmm-dev:   http://mail.openjdk.java.net/mailman/listinfo/jmm-dev
   valhalla-dev: http://mail.openjdk.java.net/mailman/listinfo/valhalla-dev

On 08/21/2015 12:39 PM, Nathan Reynolds wrote:
> What is the difference between getRelaxed() and getOpaque()?  I realize that
> specifies the semantics of reading a non-volatile variable and the other has no
> guarantees what so ever.   What's up with reading a non-volatile variable?

getRelaxed is a plain ordinary read with rules specified by the JMM.
These APIs don't say what those rules are, allowing them to be revised.
But many reorderings and  transformations are allowed.

getOpaque is the same, but with the further constraint that the read
must actually occur even if other JMM rules would allow it to be
optimized away (for example due to common subexpression evaluation).
Usage is rare. Think IO.

>
> getOpaque() versus setVolatile() - Which one wins?

In the case I think you have in mind:  getX (X=relaxed, acquire, ...)
is a load. A preceding setVolatile entails what amount to a trailing
storeLoad fence, so cannot be reordered downward.

>
> For compareAndSet____() methods, should the variable names be (Object owner, T
> expect, T update) to match that of Atomic___ classes?

Probably so; thanks!

>
> Are you going to supply a web page similar to JSR 133 Cookbook?

Yes, that's the plan.

>
> I missed the conversation on reachabilityFence().  How do I use this?
>

You might glance through August 2014 jmm-dev mail with
"finalization" in subject.
   http://mail.openjdk.java.net/pipermail/jmm-dev/2014-August/thread.html

Also, here's a paste of draft javadocs from the last time we
considered this (5+ years ago):

Avoiding premature finalization. Finalization may occur whenever a Java Virtual
Machine detects that no reference to an object will ever be stored in the heap:
A garbage collector may reclaim an object even if the fields of that object are
still in use, so long as the object has otherwise become unreachable. This may
have surprising and undesirable effects in cases such as the following example
in which the bookkeeping associated with a class is managed through array
indices. Here, method action uses a reachabilityFence to ensure that the
Resource object is not reclaimed before bookkeeping on an associated
ExternalResource has been performed; in particular here, to ensure that the
array slot holding the ExternalResource is not nulled out in method
Object.finalize(), which may otherwise run concurrently.


  class Resource {
    private static ExternalResource[] externalResourceArray = ...

    int myIndex;
    Resource(...) {
      myIndex = ...
      externalResourceArray[myIndex] = ...;
      ...
    }
    protected void finalize() {
      externalResourceArray[myIndex] = null;
      ...
    }
    public void action() {
      try {
        // ...
        int i = myIndex;
        Resource.update(externalResourceArray[i]);
      } finally {
        Fences.reachabilityFence(this);
      }
    }
    private static void update(ExternalResource ext) {
      ext.status = ...;
    }
  }

Here, the call to reachabilityFence is nonintuitively placed after the call to
update, to ensure that the array slot is not nulled out by Object.finalize()
before the update, even if the call to action was the last use of this object.
This might be the case if for example a usage in a user program had the form new
Resource().action(); which retains no other reference to this Resource. While
probably overkill here, reachabilityFence is placed in a finally block to ensure
that it is invoked across all paths in the method. In a method with more complex
control paths, you might need further precautions to ensure that
reachabilityFence is encountered along all of them.

It is sometimes possible to better encapsulate use of reachabilityFence.
Continuing the above example, if it were OK for the call to method update to
proceed even if the finalizer had already executed (nulling out slot), then you
could localize use of reachabilityFence:


  public void action2() {
    // ...
    Resource.update(getExternalResource());
  }
  private ExternalResource getExternalResource() {
    ExternalResource ext = externalResourceArray[myIndex];
    Fences.reachabilityFence(this);
    return ext;
  }

Method reachabilityFence is not required in constructions that themselves ensure
reachability. For example, because objects that are locked cannot in general be
reclaimed, it would suffice if all accesses of the object, in all methods of
class Resource (including finalize) were enclosed in synchronized (this) blocks.
(Further, such blocks must not include infinite loops, or themselves be
unreachable, which fall into the corner case exceptions to the "in general"
disclaimer.) However, method reachabilityFence remains a better option in cases
where this approach is not as efficient, desirable, or possible; for example
because it would encounter deadlock.


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
In reply to this post by Doug Lea
I'm especially glad to see the T compareAndExchangeXXX(Object owner, T expected, T val) versions (assuming they're implemented via intrinsics of course).
Is the lack of code examples deliberate (can of worms), or are you soliciting some?
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Peter Levart
In reply to this post by Doug Lea
Hi Doug,

On 08/21/2015 03:44 PM, Doug Lea wrote:
    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setRelease if the current value {@code ==}
     * the expected value, as accessed with the memory samantics of
     * getRelease.
            ^^^^
Should that be getRelaxed or more probably getAcquire ?

     *
     * @param expected the expected value
     * @param val the new value
     * @return the current value, which will be the same as {@code val} if
     * successful.
     */
    T compareAndExchangeRelease(Object owner, T expected, T val);

Suppose the value is currently 1 and two threads do the following concurrently:

Thread1:

v1 = compareAndExchangeRelease(owner, 1, 2);

Thread2:

v2 = compareAndExchangeRelease(owner, 1, 3);



Can the outcome be: v1 == 2, v2 == 3 ?

If it is getAcquire then probably not, but if it is getRelaxed then It might be or not?


Regards, Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Vitaly Davidovich

That wouldn't be a CAS if that outcome were possible.  My understanding is the ordering in those CAS variants dictates ordering of memory accesses before and after the CAS with respect to the CAS itself.

sent from my phone

On Aug 21, 2015 5:09 PM, "Peter Levart" <[hidden email]> wrote:
Hi Doug,

On 08/21/2015 03:44 PM, Doug Lea wrote:
    /**
     * Atomically sets the value to the given updated value with the
     * memory semantics of setRelease if the current value {@code ==}
     * the expected value, as accessed with the memory samantics of
     * getRelease.
            ^^^^
Should that be getRelaxed or more probably getAcquire ?

     *
     * @param expected the expected value
     * @param val the new value
     * @return the current value, which will be the same as {@code val} if
     * successful.
     */
    T compareAndExchangeRelease(Object owner, T expected, T val);

Suppose the value is currently 1 and two threads do the following concurrently:

Thread1:

v1 = compareAndExchangeRelease(owner, 1, 2);

Thread2:

v2 = compareAndExchangeRelease(owner, 1, 3);



Can the outcome be: v1 == 2, v2 == 3 ?

If it is getAcquire then probably not, but if it is getRelaxed then It might be or not?


Regards, Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
In reply to this post by Peter Levart
On 08/21/2015 04:47 PM, Peter Levart wrote:

> Hi Doug,
>
> On 08/21/2015 03:44 PM, Doug Lea wrote:
>> /**
>>      * Atomically sets the value to the given updated value with the
>>      * memory semantics of setRelease if the current value {@code ==}
>>      * the expected value, as accessed with the memory samantics of
>>      * getRelease.
>              ^^^^
> Should that be getRelaxed or more probably getAcquire ?

Thanks; fixed. It should say getRelaxed.

>
>> *
>>      * @param expected the expected value
>>      * @param val the new value
>>      * @return the current value, which will be the same as {@code val} if
>>      * successful.
>>      */
>>     T compareAndExchangeRelease(Object owner, T expected, T val);
>
> Suppose the value is currently 1 and two threads do the following concurrently:
>
> Thread1:
>
> v1 = compareAndExchangeRelease(owner, 1, 2);
>
> Thread2:
>
> v2 = compareAndExchangeRelease(owner, 1, 3);
>
>
>
> Can the outcome be: v1 == 2, v2 == 3 ?
>
> If it is getAcquire then probably not, but if it is getRelaxed then It might be
> or not?

No; the CAS "confirms" the value. As Vitaly noted, the modes are
there for finer-grained control of what happens before/after the CAS.
(Note: on X86 and Sparc, all flavors of CAS map to the same instruction,
but they may all differ on ARM and POWER.)

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
In reply to this post by thurstonn
On 08/21/2015 04:01 PM, thurstonn wrote:

> Is the lack of code examples deliberate (can of worms), or are you
> soliciting some?
>

Candidate javadoc examples would be welcome. Although
I imagine that external articles, blogs, etc will do a better
job at conveying when these methods are applicable than we can do
in javadocs.

-Doug




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
In reply to this post by Doug Lea
So the current Java 8 JavaDoc has the following in the atomic package:

"compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables."

So it's been decided to essentially replace that with the  following?:

 /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setVolatile if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getVolatile.  


I find that confusing/awkward (maybe it's just me), but I realize it's tricky, and so if others don't then fine

Also,
"(Note: on X86 and Sparc, all flavors of CAS map to the same instruction,
but they may all differ on ARM and POWER.) "

Just to be clear, that instruction is (LOCK) CMPXCHG and requires no before or after fences, right?
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
In reply to this post by Doug Lea
I have a couple of questions, but first I wanted to make sure that I'm not missing something basic.

This sentence:
"We are NOT planning a full JMM memory model update for jdk9"

should not be taken to mean that (for jdk9),
<code>
T getVolatile(Object owner) and
T getAcquire(Object owner)
</code>
have the exact same "memory order effects", right?

i.e. they are not just placeholders "until a full JMM is agreed upon"?
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
On 08/22/2015 09:06 AM, thurstonn wrote:

> I have a couple of questions, but first I wanted to make sure that I'm not
> missing something basic.
>
> This sentence:
> "We are NOT planning a full JMM memory model update for jdk9"
>
> should *not *be taken to mean that (for jdk9),
> <code>
> T getVolatile(Object owner) and
> T getAcquire(Object owner)
> </code>
> have the exact same "memory order effects", right?

Yes and no. They currently have the same implementation, and
any future changes will be compatible with this, but future
specs need not be identical. Although probably they will differ
at most in uninteresting ways, for example any wording needed to
continue to allow volatile fields that never escape threads to
be treated (essentially) as if non-volatile.

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
In reply to this post by thurstonn
On 08/21/2015 07:39 PM, thurstonn wrote:
> So the current Java 8 JavaDoc has the following in the atomic package:
>
> "compareAndSet and all other read-and-update operations such as
> getAndIncrement have the memory effects of both reading and writing volatile
> variables."

Thanks for the reminder that j.u.c.atomic package docs will need
some touch-up when we adapt methods/names for the Atomic* classes.

> Also,
> "(Note: on X86 and Sparc, all flavors of CAS map to the same *instruction*,
> but they may all differ on ARM and POWER.) "
>
> Just to be clear, that instruction is (LOCK) CMPXCHG and requires no before
> or after fences, right?

Yes. (Actually more than one instruction because of different widths for
int vs long etc.)

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
In reply to this post by Doug Lea
Thanks for the prompt reply.  I guess I'll operate then from the yes perspective.

What are the plans with respect to the "higher-order methods" on e.g. AtomicReference, i.e.

T getAndAccumulate(T, BinaryOperator<T>)
T updateAndGet(UnaryOperator<T>)
. . .
etc.


Are you going to have:
T getAndAccumulateVolatilely(T, BinaryOperator<T>)
T getAndAccumulateAcquiredly(T, BinaryOperator<T>)
etc versions?


That seems like a pollution of the API, IMO (and just awful names).  And I'm not really sure where it ends.

And then a small javadoc modification suggestion:
/**
      * Returns the value, and ensures that subsequent loads and stores
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

I find
/**
      * Returns the value, and ensures that subsequent loads and stores (in the program order)
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

to be a little clearer as subsequent is an overloaded term when it comes to JMM matters.

And one final question that I've always been confused about;  are there different "memory ordering effects" between a successful CAS and an unsuccessful one (presumably in the latter because no write actually occurs)?
IIRC, when looking at the java 8 JVM code, I believe a fence was inserted in the successful case, at least on x86/64.  If so, I can take a shot at producing some javadoc language to reflect that, if it would be helpful.
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Vitaly Davidovich

I would hope there's no ordering difference between successful and unsuccessful CAS.  On x86/64 the instruction itself provides full fence irrespective of outcome; compiler doesn't know a priori whether it will succeed or not.  Are there platforms where the lowering of the CAS has different cpu ordering based on outcome? LL/SC can fail if cacheline is modified in between (even if value is still the expected one) but I'm not aware of that changing ordering semantics.  However, if there are cases where this would matter, I hope the JVM ensures the requested ordering irrespective of outcome.

Along this line, the more "interesting" and related question is what the ordering guarantees are for failed tryLock methods.

sent from my phone

On Aug 22, 2015 1:41 PM, "thurstonn" <[hidden email]> wrote:
Thanks for the prompt reply.  I guess I'll operate then from the yes
perspective.

What are the plans with respect to the "higher-order methods" on e.g.
AtomicReference, i.e.

T getAndAccumulate(T, BinaryOperator<T>)
T updateAndGet(UnaryOperator<T>)
. . .
etc.


Are you going to have:
T getAndAccumulateVolatilely(T, BinaryOperator<T>)
T getAndAccumulateAcquiredly(T, BinaryOperator<T>)
etc versions?


That seems like a pollution of the API, IMO (and just awful names).  And I'm
not really sure where it ends.

And then a small javadoc modification suggestion:
/**
      * Returns the value, and ensures that subsequent loads and stores
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

I find
/**
      * Returns the value, and ensures that subsequent loads and stores (*in
the program order*)
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

to be a little clearer as *subsequent* is an overloaded term when it comes
to JMM matters.

And one final question that I've always been confused about;  are there
different "memory ordering effects" between a successful CAS and an
unsuccessful one (presumably in the latter because no write actually
occurs)?
IIRC, when looking at the java 8 JVM code, I believe a fence was inserted in
the successful case, at least on x86/64.  If so, I can take a shot at
producing some javadoc language to reflect that, if it would be helpful.



--
View this message in context: http://jsr166-concurrency.10961.n7.nabble.com/jdk9-VarHandle-and-Fence-methods-tp12666p12680.html
Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Vitaly Davidovich
In reply to this post by thurstonn

As for higher order variants, I'd vote to keep them out unless they can be done more cheaply by virtue of being backed by some intrinsics.  Otherwise, anyone can build them on top of the lower level functionality.

sent from my phone

On Aug 22, 2015 1:41 PM, "thurstonn" <[hidden email]> wrote:
Thanks for the prompt reply.  I guess I'll operate then from the yes
perspective.

What are the plans with respect to the "higher-order methods" on e.g.
AtomicReference, i.e.

T getAndAccumulate(T, BinaryOperator<T>)
T updateAndGet(UnaryOperator<T>)
. . .
etc.


Are you going to have:
T getAndAccumulateVolatilely(T, BinaryOperator<T>)
T getAndAccumulateAcquiredly(T, BinaryOperator<T>)
etc versions?


That seems like a pollution of the API, IMO (and just awful names).  And I'm
not really sure where it ends.

And then a small javadoc modification suggestion:
/**
      * Returns the value, and ensures that subsequent loads and stores
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

I find
/**
      * Returns the value, and ensures that subsequent loads and stores (*in
the program order*)
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

to be a little clearer as *subsequent* is an overloaded term when it comes
to JMM matters.

And one final question that I've always been confused about;  are there
different "memory ordering effects" between a successful CAS and an
unsuccessful one (presumably in the latter because no write actually
occurs)?
IIRC, when looking at the java 8 JVM code, I believe a fence was inserted in
the successful case, at least on x86/64.  If so, I can take a shot at
producing some javadoc language to reflect that, if it would be helpful.



--
View this message in context: http://jsr166-concurrency.10961.n7.nabble.com/jdk9-VarHandle-and-Fence-methods-tp12666p12680.html
Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Doug Lea
In reply to this post by thurstonn
On 08/22/2015 12:47 PM, thurstonn wrote:

> What are the plans with respect to the "higher-order methods" on e.g.
> AtomicReference, i.e.
>
> T getAndAccumulate(T, BinaryOperator<T>)
> T updateAndGet(UnaryOperator<T>)

No plans; basically for the reasons you noted: There are too many
possibilities to support, all of them can be done on top of what
we do provide, and they don't fit well with the polymorphic
signature mechanics.

> And one final question that I've always been confused about;  are there
> different "memory ordering effects" between a successful CAS and an
> unsuccessful one (presumably in the latter because no write actually
> occurs)?

The memory ordering effects are the same regardless of outcome.
Ensuring this sometimes takes some thought on ARM -- see some
exchanges on this list last fall(?).

> IIRC, when looking at the java 8 JVM code, I believe a fence was inserted in
> the successful case, at least on x86/64.  If so, I can take a shot at
> producing some javadoc language to reflect that, if it would be helpful.

There is no extra fence on x86. (Hotspot sometimes prevents
internal IR reorderings using the (misnamed) MemBarCPUOrder
just for internal reasons. This might be what you were seeing.)

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
from unsafe.cpp:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))

  UnsafeWrapper("Unsafe_CompareAndSwapObject");

  oop x = JNIHandles::resolve(x_h);

  oop e = JNIHandles::resolve(e_h);

  oop p = JNIHandles::resolve(obj);

  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);

  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);

  jboolean success  = (res == e);

  if (success)

    update_barrier_set((void*)addr, x);


  return success;

UNSAFE_END

That's what I was referring to; I  presumed update_barrier_set resulted in some sort of store fence
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Vitaly Davidovich

That's likely a store/write barrier for GC (i.e. card mark).

sent from my phone

On Aug 23, 2015 1:17 PM, "thurstonn" <[hidden email]> wrote:
from unsafe.cpp:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject
unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))

  UnsafeWrapper("Unsafe_CompareAndSwapObject");

  oop x = JNIHandles::resolve(x_h);

  oop e = JNIHandles::resolve(e_h);

  oop p = JNIHandles::resolve(obj);

  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);

  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);

  jboolean success  = (res == e);

 * if (success)

    update_barrier_set((void*)addr, x);*

  return success;

UNSAFE_END

That's what I was referring to; I  presumed update_barrier_set resulted in
some sort of store fence



--
View this message in context: http://jsr166-concurrency.10961.n7.nabble.com/jdk9-VarHandle-and-Fence-methods-tp12666p12688.html
Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

thurstonn
In reply to this post by Doug Lea
As far as a code sample for the compareAndExchangeXXX variants:


//An improved updateAndGet
Object owner = . . .
VarHandle<T> referent = . . .
UnaryOperator<T> identity = it -> it;

T expected = referent.getXXX();
T updated = identity.apply(expected);


for (; (expected = referent.compareAndExchangeXXX(owner, expected, updated)) != updated; updated = identity.apply(expected)) {}

return updated; //updated == expected


Not exactly sure whether AtomicReference will use VarHandles or not, but all of the "higher order methods" should be rewritten similarly
Reply | Threaded
Open this post in threaded view
|

Re: jdk9 VarHandle and Fence methods

Aleksey Shipilev-2
In reply to this post by Vitaly Davidovich
That *is* a GC write barrier. While it may have an internal memory
semantics that affects the actual semantics of reference CAS, its
effects are not advertised.

-Aleksey

P.S. Somewhat amusingly, C2 intrinsic for reference CAS implemented a
success-only GC write barrier only recently:
  https://bugs.openjdk.java.net/browse/JDK-8019968


On 08/23/2015 08:30 PM, Vitaly Davidovich wrote:

> That's likely a store/write barrier for GC (i.e. card mark).
>
> sent from my phone
>
> On Aug 23, 2015 1:17 PM, "thurstonn" <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     from unsafe.cpp:
>
>     UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject
>     unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
>
>       UnsafeWrapper("Unsafe_CompareAndSwapObject");
>
>       oop x = JNIHandles::resolve(x_h);
>
>       oop e = JNIHandles::resolve(e_h);
>
>       oop p = JNIHandles::resolve(obj);
>
>       HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p,
>     offset);
>
>       oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);
>
>       jboolean success  = (res == e);
>
>      * if (success)
>
>         update_barrier_set((void*)addr, x);*
>
>       return success;
>
>     UNSAFE_END
>
>     That's what I was referring to; I  presumed update_barrier_set
>     resulted in
>     some sort of store fence
>
>
>
>     --
>     View this message in context:
>     http://jsr166-concurrency.10961.n7.nabble.com/jdk9-VarHandle-and-Fence-methods-tp12666p12688.html
>     Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
>     _______________________________________________
>     Concurrency-interest mailing list
>     [hidden email]
>     <mailto:[hidden email]>
>     http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
1234