Hello,

I must admit I'm still kind of lost here. The email from kettenis@
with comment from linux helped a bit, but still my understanding
is really blurry here. Let me share my view on the recent
example from visa@.


</snip>
> > 
> > Above, thread A would need a barrier before the release. Otherwise
> > the write might happen too late. This would be far from obvious if
> > the code was more complicated.
> 
> Below is another, less far-fetched, example that shows that the current
> state of affairs is not safe:
> 
>       mtx_enter(&w->w_mtx);
>       ...
>       mtx_leave(&w->w_mtx);
>       if (refcnt_rele(&w->w_refcnt))
>               free(w);
> 
> The mtx_leave() introduces a memory release barrier that forces all
> preceding memory accesses to complete before the decrement. However,
> there is no memory barrier after the write that releases the mutex.
> 
> SPL adjusting aside, mtx_leave() essentially does this:
> 
>       membar_exit();
>       mtx->mtx_owner = NULL;
> 

    after reading email from kettenis@ I can't see/understand a
    problem described in the example here.

    let's assume there are at least two threads:
        A - which has released w->w_mtx and is going to do recnt_rele()

        B - which is about to do mtx_enter(), in order to do mtx_enter(),
            the thread B must also posses a reference to w

    are those assumptions above right? If so, then the worst case which
    may happen is that thread B will spin in mtx_enter() for a while
    waiting for ->mtx_owner to become NULL. Does it sound right or
    I am completely lost?

    In my opinion the missing piece here is how both threads
    obtain a reference to `w`. I believe the typical way involves
    a look up operation under protection of some global lock:

        rw_enter_read(&w_rw);
        w = find_w();
        if (w != NULL)
                refcnt_take(&w->w_refcnt);
        rw_exit_read(&w_rw);

> Now, because of inadequate memory synchronization, the writing
> of mtx_owner can become visible to other CPUs after the decrement.
> 

    as I've said earlier. the worst thing which happens in my
    opinion is that the thread B can burn few cycles when spinning
    to wait ->mtx_owner becomes NULL.

> I think the sanest solution is to add the release and acquire barriers
> in refcnt_rele().
> 

    so are we discussing the cost of memory barrier vs. cost of
    cpu cycles burnt by thread B in mtx_enter() waiting for ->mtx_owner
    to become NULL. 

thanks for any hints on this

regards
sashan

Reply via email to