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

next in thread | previous in thread | raw e-mail | index | archive | help
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



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