[jmm-dev] VarHandle.safepoint() methods

Sanjoy Das sanjoy at playingwithpointers.com
Wed Jan 4 20:11:20 UTC 2017


Hi Andrew,

On Wed, Jan 4, 2017 at 10:04 AM, Andrew Haley <aph at redhat.com> wrote:
> This is a proposal for a new VarHandle method, but it also is an
> extension to the Java Memory Model, so I'm starting the discussion
> here.
>
> My intention is to provide an efficient way to handle the case where a
> field has reads which outnumber writes by several orders of magnitude.
> Once a field has been successfully modified, no thread may observe a
> stale value.  Writes to a field are expected to be very rare, and can
> be expensive.
>
> It provides a secure and fast way to do something like a volatile
> access but without any memory fences (or even any restrictions on
> memory reordering) on the reader side.
>
> I propose two new VarHandle methods:
>
> Object getSafepoint()
>
>   Returns the value of a variable, with memory semantics of reading as
>   if the variable was declared non-volatile, except that this load
>   shall not be reordered with a preceding safepoint.

I presume you'll also want to prevent CSE across safepoints? That is:

  rA = t.getVolatile()
  JVM::SafepointPoll()
  rB = t.getVolatile()

=>

  rA = t.getVolatile()
  JVM::SafepointPoll()
  rB = rA

needs to be prohibited also?

[snip]

> Example: A closeable MappedByteBuffer.
>
> public class CloseableMappedByteBuffer {
>
>     // Actually unmaps a byte buffer.
>     private native void unmap(MappedByteBuffer b);
>
>     private volatile MappedByteBuffer _buf;
>     private VarHandle vh;
>
>     private MappedByteBuffer buf() {
>         return (MappedByteBuffer) v.getSafepoint();
>     }
>
>     public CloseableMappedByteBuffer wrap(MappedByteBuffer buf) {
>         return new CloseableMappedByteBuffer(buf);
>     }
>
>     public void unmap() {
>         MappedByteBuffer buf = buf();
>         vh.setOpaque(null);
>         VarHandle.safepoint();
>         // Now every thread sees the updated _buf, we can unmap it.
>         unmap(buf);
>     }
>
>     public byte get() {
>         return buf().get();
>     }

You'd need to make sure that get() does not have a safepoint between
buf() and get() right?

>
>     public byte get(int index) {
>         return buf().get(index);
>     }
>
>     ...etc, for all the ByteBuffer methods.
> }

Have you considered something like this:



     public void unmap() {
         MappedByteBuffer buf = buf();
         vh.setOpaque(null);
         while (true) {
           Traces = Thread.getAllStackTraces();
           // If no trace in Traces contains a get() method or something
           // equivalent then break; else loop.
          }
         unmap(buf);
     }

and nothing special about the get() methods.


I'm not sure how well Thread.getAllStackTraces() works in practice
though.


-- Sanjoy


More information about the jmm-dev mailing list