[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCHv3 3/4] xen: use ticket locks for spin locks



At 15:24 +0100 on 23 Apr (1429802696), Tim Deegan wrote:
> At 14:43 +0100 on 23 Apr (1429800229), David Vrabel wrote:
> > On 23/04/15 13:03, Tim Deegan wrote:
> > > Hi,
> > > 
> > > At 11:11 +0100 on 21 Apr (1429614687), David Vrabel wrote:
> > >>  void _spin_lock(spinlock_t *lock)
> > >>  {
> > >> +    spinlock_tickets_t tickets = { .tail = 1, };
> > >>      LOCK_PROFILE_VAR;
> > >>  
> > >>      check_lock(&lock->debug);
> > >> -    while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
> > >> +    tickets.head_tail = xadd(&lock->tickets.head_tail, 
> > >> tickets.head_tail);
> > >> +    while ( tickets.tail != observe_head(&lock->tickets) )
> > >>      {
> > >>          LOCK_PROFILE_BLOCK;
> > >> -        while ( likely(_raw_spin_is_locked(&lock->raw)) )
> > >> -            cpu_relax();
> > >> +        cpu_relax();
> > >>      }
> > >>      LOCK_PROFILE_GOT;
> > >>      preempt_disable();
> > > 
> > > I think you need an smp_mb() here to make sure that locked accesses
> > > don't get hoisted past the wait-for-my-ticket loop by an out-of-order
> > > (ARM) cpu.
> > 
> > Ok, but smp_mb() turns into an mfence on x86.  Is this a
> > problem/sub-optimal?
> 
> So, having chased this around my head for a while, I think you're
> right.  Expanding this code a bit, I think the important ops are:
> 
> (in observe_head())
>     smp_rmb() (== barrier())
>     [ POINT A ]
>     read lock and see that we have acquired it
> (in preempt_disable())    
>     increment disable count (this is both a read and a write)
>     barrier();
>     [ POINT B ]
> 
> A read after point B can't see unlocked state because of the second
> compiler barrier and the fact that x86 won't reorder it past the read
> in observe_head().
> 
> A write after point B can't be observed before we have the lock
> because
> 1) the second barrier stops the compiler reorderign before the increment;
> 2) x86 won't make it visible before the write half of the increment;
> 3) the write half of the increment can't happen before the read half; and
> 4) the read half can't happen before the read in observe_head().
> 
> I'm not 100% sure about (3), as it happens; maybe either the compiler
> or the CPU might do something unexpected there?
> 
> So probably, on x86, we don't need the mfence.  A bit fragile,
> though, relying on the internals of preempt_disable().

Andrew pointed me at the SDM (vol 3, 8.2.2.) that says that writes
are not reordered with older reads.  So the write case is the same as
the read case: the read in observe_head() is the important one and all
we need here is a barrier().

I guess you could invent an arch_lock_acquire_barrier() or similar
to go here, that expands to barrier() on x86 and dmb() on ARM...

Tim.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.