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