On Sat, May 4, 2013 at 8:50 AM, Edward Z. Yang <ezyang@cs.stanford.edu> wrote:
Akio, your derefWeak WHITEHOLE fix looks really weird. I don't
know what the right pattern is, but it seems like asking for trouble
when there are multiple concurrent derefs:

    if (info == stg_WHITEHOLE_info) {
      ("ptr" info) = ccall lockClosure(w "ptr");
       unlockClosure(w, info);
    }


I don't see what the problem is, could you elaborate?

The purpose of the fix was to prevent a sequence like this:

- w is a dead weak pointer.
- Thread A: finalizeWeak# w.
- Thread A: finalizeWeak#  calls lockClosure(w), overwriting w->info with stg_WHITEHOLE_info.
- Thread B: deRefWeak# w
- Thread B: deRefWeak# sees stg_WHITEHOLE_info, and since it's not the same as stg_DEAD_WEAK_info, it thinks w is alive.

The problem was that if deRefWeak# saw stg_WHITEHOLE_info, it was not clear whether the weak pointer was alive or not. So my fix adds a call to lockClosure, which never returns stg_WHITEHOLE_info.
 
> addForeignPtrFinalizer retries in this case.

This can't be right; a dead weak pointer always stays dead, so won't
this infinite loop?

No. When addForeignPtrFinalizer retries, it will use a new Weak# object, because foreignPtrFinalizer must have been replaced the content of the IORef.
 

> I haven't got around to looking at this, but I see Edward is on the case
> with some code review.  Do you think I should look at it before it goes in?

Now you're asking for it :)  I would always be interested in seeing if I
missed anything.

Cheers,
Edward