D2 weak references

Jason House jason.james.house at gmail.com
Sat Apr 25 11:19:27 PDT 2009


Leandro Lucarella Wrote:

> Jason House, el 23 de abril a las 16:48 me escribiste:
> > > What I'm not sure is if it's really necessary to do that step. What can go
> > > wrong with this simple approach?
> > > 
> > >      T opCall() {
> > >          if (!pool.mark.test(index))
> > >              t = null;
> > >          return t;
> > >      }
> > 
> > What happens when a collection runs after test returns? You need to copy
> > t onto the stack in order to be safe.
> 
> You're right, I definitely underestimated the problem. Now I see that this
> sequence breaks that implementation:
> 
> 1) WeakRef.opCall() is called (whick stores a reference to R)
> 2) The mark bit for R is tested and returns true
> 3) CPU time is given to other threads with reference to R, which are
>    removed
> 4) Other thread triggers a collection and the world is stopped
> 5) R gets unmarked because there are no other references to it
> 6) The world is started
> 7) WeakRef.opCall() returns R when it should returned null
> 
> The problem I see with your original proposal:
> 
>     T opCall(){
>         T tmp = t; // force future conservative GC scan to find the pointer
>         if ( (tmp is null) || (pool.mark[index] == false) ){
>             t = null;
>             return null;
>         }
>         tmp = t; // avoid race where t was replaced with new data
>         return tmp;
>     }
> 
> Is that I guess is very likely that 'tmp' get optimized out. Would
> declaring it as volatile help? If not, I guess the only way to avoid that
> race is add a root manually to the GC (or mark the weakref again as no
> NO_SCAN). But both requires synchronization. =(

I would use tango.core.atomic that I took from the Tango D2 branch. Another option is inline asm, but I'd have to research how to do that.

 
> > > Weakref only reads the reference *if* the mark bit is set, in which case
> > > is safe to assume that the object is live.
> > 
> > How do you check the mark bit? In the sample code, it used the
> > reference... Admittedly, one could store the right info to avoid that,
> > but it hardly matters.
> 
> Right.
> 
> > > If the object is garbage, the mark bit is unset and in that case the
> > > reference is only *written* (the only race it could happen is the sweep()
> > > can be called but in that case the reference is written to null too, so
> > > there should be no problem with that, I guess...
> > > 
> > > As long as the test are successful (t is not overwritten to null), the GC
> > > should be able to find the reference in the stack when the function
> > > returns.
> > > 
> > > I'm probably missing something else...
> > 
> > You're not considering what can happen if the weak ref dereferencing
> > thread stops and the rest of the world wreaks havoc on the state of the
> > world. A collection could run after checking the mark. If one is careful
> > with that, and a copy of t is kept on the stack, will the optimizer
> > reuse it? Or will it reread the value? That matters if the finalizer
> > runs. The mark bit check can fail from reallocation after deletion.
> > 
> > I hope that helps...
> 
> Yes, thank you.

It's amazingly difficult to get right for something so "simple"
 
> -- 
> Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
> ----------------------------------------------------------------------------
> GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
> ----------------------------------------------------------------------------
> - Que hacés, ratita?
> - Espero un ratito...




More information about the Digitalmars-d mailing list