Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Aug 2010 10:02:34 -0400
From:      Stephan Uphoff <ups@freebsd.org>
To:        Max Laier <max@laiers.net>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: rmlock(9) two additions
Message-ID:  <4C73D0FA.5030102@freebsd.org>
In-Reply-To: <201008240045.15998.max@laiers.net>
References:  <201008160515.21412.max@love2party.net> <4C7042BA.8000402@freebsd.org> <201008222105.47276.max@love2party.net> <201008240045.15998.max@laiers.net>

index | next in thread | previous in thread | raw e-mail

Max Laier wrote:
> On Sunday 22 August 2010 21:05:47 Max Laier wrote:
>   
>> On Saturday 21 August 2010 23:18:50 Stephan Uphoff wrote:
>>     
>>> Max Laier wrote:
>>> ...
>>> The rm_try_rlock() will never succeed when the lock was last locked as
>>> writer.
>>> Maybe add:
>>>
>>> void
>>> _rm_wunlock(struct rmlock *rm)
>>> {
>>> +   rm->rm_noreadtoken = 0;
>>>
>>>     mtx_unlock(&rm->rm_lock);
>>>
>>> }
>>>
>>> But then
>>>
>>> _rm_wlock(struct rmlock *rm)
>>>
>>> always needs to use IPIs - even when the lock was used last as a write
>>> lock.
>>>       
>> I don't think this is a big problem - I can't see many use cases for
>> rmlocks where you'd routinely see repeated wlocks without rlocks between
>> them. However, I think there should be a release memory barrier
>> before/while clearing rm_noreadtoken, otherwise readers may not see the
>> data writes that are supposed to be protected by the lock?!?
>>     
>>> ...
>>>       
>> I believe either solution will work.  #1 is a bit more in the spirit of the
>> rmlock - i.e. make the read case cheap and the write case expensive.  I'm
>> just not sure about the lock semantics.
>>
>> I guess a
>>
>>   atomic_store_rel_int(&rm->rm_noreadtoken, 0);
>>
>> should work.
>>     
>
> thinking about this for a while makes me wonder: Are readers really guaranteed 
> to see all the updates of a writer - even in the current version?
>
> Example:
>
>   writer thread:
>   rm_wlock();		// lock mtx, IPI, wait for reader drain
>   modify_data();
>   rm_wunlock();	// unlock mtx (this does a atomic_*_rel)
>
>   reader thread #1:
>   // failed to get the lock, spinning/waiting on mtx
>   mtx_lock();		// this does a atomic_*_acq -> this CPU sees the new data
>   rm->rm_noreadtoken = 0;	// now new readers can enter quickly
>   ...
>
>   reader thread 2# (on a different CPU than reader #1):
>   // enters rm_rlock() "after" rm_noreadtoken was reset -> no memory barrier
>   // does this thread see the modifications?
>
> I realize this is a somewhat pathological case, but would it be possible in 
> theory?  Or is the compiler_memory_barrier() actually enough?
>
> Otherwise, I think we need an IPI on rm_wunlock() that does a atomic_*_acq on 
> every CPU.
>
> Thoughts?
>   Max
>
>   
Yes - this is a problem that needs to be addressed.
Fortunately most platforms won't need to be as strict and I suggest per 
platform parameters.
An alternative that was in my original design was to use a bitmap for 
the rm_noreadtoken.
Each CPU would then have an associated bit that will only be cleared by 
that cpu.
This would also allow targeted IPIs to only the token holders.

Stephan





home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4C73D0FA.5030102>