[concurrency-interest] DirectByteBuffers and reachabilityFence

Timo Kinnunen timo.kinnunen at gmail.com
Fri Dec 11 15:56:19 EST 2015


I think I’ve figured out why the implementation of DirectByteBuffer.get(byte[], int, int) is safe. 

First, please convince yourself that reachabilityFence(this) is semantically equivalent or at least as-if compatible with a reachabilityPotentiallyEnds(this) call, with the method reachabilityPotentiallyEnds() being where all the finalization magic is implemented. (This is just for illustration and not the main point.)

Convinced already? Good �� 

First, consider a constructor. The execution of a constructor starts in a static context, where pretty much nothing except evaluating arguments and calling another constructor of the same class or some superclass constructor is allowed. After that call completes normally, the context becomes that of the newly constructed instance, all restrictions of the static context are lifted and the rest of the constructor proceeds to execute as usual. 

Now consider an instance method where the receiver is not used beyond a certain point, its bytecode with slot 0 not read after that point, and the native code version which therefore can overwrite and reuse the register housing the this-pointer as needed. Such a method could be refactored into methods A and B, where method A executes before B and where the receiver is used in A but not in B, so that method B can be static. For such a method an implicit reachabilityPotentiallyEnds(this) call could be considered to exist between the parts A and B. If the receiver does become unreachable in such a method then the result of such an execution would be a dual or the inverse to a constructor call. Let’s call such methods potentially asynchronous destructors:

A Potentially Asynchronous Destructor is an instance method where it’s possible to place a reachabilityFence(this) marker in such a way that the receiver is not referenced after execution reaches the marker and the rest of the execution happens in an effectively static context. 

Given this definition, any method where an explicit reachabilityFence(this) needs to be inserted so that the boundary between A and B moves to some later position to guarantee its safety is a potentially asynchronous destructor.

So why is the DBB.get() method safe and not a potentially asynchronous destructor? Simply because as the last thing it does is a “return this;” there is no place inside it where a reachabilityFence(this) could be placed such that the receiver would not be used afterwards! This doesn’t by itself mean that every call to it is done in a safe manner but it does mean that a reachability fence can’t fix the implementation of DBB.get() because DBB.get() isn’t broken. 

I think this is still safe, though, as everything until here has been limited to a single thread, therefore correctly synchronized, therefore data-race free and therefore sequentially consistent. If a single-threaded program could observe a crash here then it would mean the GC had observed the return of a method call before the method call returned, which would mean the thread’s execution wasn’t sequentially consistent, which is a contradiction. Therefore such a reordering is not a legal reordering.
So, what do you think? Sound reasoning or not?

Have a nice day, 

Sent from Mail for Windows 10

From: Gil Tene
Sent: Friday, December 11, 2015 06:01
To: Peter
Cc: Doug Lea;concurrency-interest at cs.oswego.edu
Subject: Re: [concurrency-interest] DirectByteBuffers and reachabilityFence

> On Dec 10, 2015, at 6:47 PM, Peter <jini at zeus.net.au> wrote:
> Would another workaround be to use a phantom reference  for the DBB?

That's exactly what sun.misc.Cleaner already does, and DBB already uses a cleaner. Cleaners and phantom references (or weak, or soft, or finalizers) do not get rid of the race. A DBB 'this' can become unreachable between computing an address and accessing it, GC picks up on that and enqueues the phantom reference (the Cleaner object), and the Cleaner object explicitly frees the buffer memory that was held by the DBB instance. Even though the DBB memory isn't reclaimed until the next GC, that doesn't matter, since the buffer has been freed [and potentially recycled elsewhere] before the unsafe call to perform the last read or write operation into it is made.

There is currently (prior to reachabilityFence) no way I know of in Java to close this race in DBB short of following each unsafe access (e.g. in each put or get) with some carefully crafted (and also expensive and/or optimization-hurting) volatile accesses. E.g. you can add an operation that stores 'this' to an extra volatile field initialized to point refer to 'this'. E.g. I think something like: ... unsafe(…); this.dummy.dummy = this; … might be sufficient to ensure that 'this' is reachable until after the unsafe call if dummy is volatile. But it will make buffer operations dead slow...

> The memory isn't reclaimed by gc until the phantom reference is cleared or becomes reachable.
> The phantom reference queue functionality could be implemented in static methods and fields.  Classes aren't gc'd until all classes in a ClassLoader and the ClassLoader itself becomes reachable.
> Just curious.
> Regards,
> Peter.
> Sent from my Samsung device.
> ---- Original message ----
> From: Doug Lea <dl at cs.oswego.edu>
> Sent: 11/12/2015 10:14:54 am
> To: concurrency-interest at cs.oswego.edu
> Subject: Re: [concurrency-interest] DirectByteBuffers and reachabilityFence
> On 12/10/2015 07:56 AM, Andrew Haley wrote:
> > On 12/10/2015 12:51 PM, Vitaly Davidovich wrote:
> >> I can see a few reasons against extending `this` lifetime at this stage of
> >> java's life, but what were the objections last time(s) this came up?
> >
> > Basically twofold.  Mostly efficiency, but also a reluctance to change
> > long-settled language semantics.  Making changes to something as
> > fundamental as this is always much tricker than people expect.  The
> > great advantage of reachabilityFence is that we can do it without a
> > lot of complex argument and politics.
> >
> Like Andrew and others who have seen periodic protracted
> discussions of this issue over the past decade or so, I'm not
> too optimistic.
> But this is also one reason for considering a @Finalized annotation
> for fields (not classes!), that would give essentially this
> guarantee only in those cases it was requested. Compilers would
> translate methods/blocks accessing @Finalized field r
> (as in .. use(r); ...)  to  the equivalent of:
>    try { ... use(r); ... } finally { reachabilityFence(); }
> In the mean time, users can at least arrange this manually though.
> There is no reason to believe that the performance impact would
> be any different in manual vs automated forms, as long as some of
> us are willing to help hotspot minimize it.
> -Doug
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20151211/cc93ecf1/attachment.html>

More information about the Concurrency-interest mailing list