[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCHv2 5/6] xen: use ticket locks for spin locks
On 10/04/15 15:19, David Vrabel wrote: > Replace the byte locks with ticket locks. Ticket locks are: a) fair; > and b) peform better when contented since they spin without an atomic > operation. > > The lock is split into two ticket values: head and tail. A locker > acquires a ticket by (atomically) increasing tail and using the > previous tail value. A CPU holds the lock if its ticket == head. The > lock is released by increasing head. > > Architectures need only provide an xadd() implementation. > > Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx> While I think this implementation is fine for x86, ARM almost certainly requires some smp barriers. ~Andrew > --- > xen/common/spinlock.c | 80 > +++++++++++++++++++++----------------------- > xen/include/xen/spinlock.h | 16 ++++++--- > 2 files changed, 50 insertions(+), 46 deletions(-) > > diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c > index 0c4289c..99163c5 100644 > --- a/xen/common/spinlock.c > +++ b/xen/common/spinlock.c > @@ -138,14 +138,17 @@ void spin_debug_disable(void) > > 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, tickets.head_tail); > + if ( tickets.tail != read_atomic(&lock->tickets.head) ) > { > LOCK_PROFILE_BLOCK; > - while ( likely(_raw_spin_is_locked(&lock->raw)) ) > + do { > cpu_relax(); > + } while ( tickets.tail != read_atomic(&lock->tickets.head) ); > } > LOCK_PROFILE_GOT; > preempt_disable(); > @@ -153,40 +156,17 @@ void _spin_lock(spinlock_t *lock) > > void _spin_lock_irq(spinlock_t *lock) > { > - LOCK_PROFILE_VAR; > - > ASSERT(local_irq_is_enabled()); > local_irq_disable(); > - check_lock(&lock->debug); > - while ( unlikely(!_raw_spin_trylock(&lock->raw)) ) > - { > - LOCK_PROFILE_BLOCK; > - local_irq_enable(); > - while ( likely(_raw_spin_is_locked(&lock->raw)) ) > - cpu_relax(); > - local_irq_disable(); > - } > - LOCK_PROFILE_GOT; > - preempt_disable(); > + _spin_lock(lock); > } > > unsigned long _spin_lock_irqsave(spinlock_t *lock) > { > unsigned long flags; > - LOCK_PROFILE_VAR; > > local_irq_save(flags); > - check_lock(&lock->debug); > - while ( unlikely(!_raw_spin_trylock(&lock->raw)) ) > - { > - LOCK_PROFILE_BLOCK; > - local_irq_restore(flags); > - while ( likely(_raw_spin_is_locked(&lock->raw)) ) > - cpu_relax(); > - local_irq_disable(); > - } > - LOCK_PROFILE_GOT; > - preempt_disable(); > + _spin_lock(lock); > return flags; > } > > @@ -194,35 +174,44 @@ void _spin_unlock(spinlock_t *lock) > { > preempt_enable(); > LOCK_PROFILE_REL; > - _raw_spin_unlock(&lock->raw); > + lock->tickets.head++; > } > > void _spin_unlock_irq(spinlock_t *lock) > { > - preempt_enable(); > - LOCK_PROFILE_REL; > - _raw_spin_unlock(&lock->raw); > + _spin_unlock(lock); > local_irq_enable(); > } > > void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) > { > - preempt_enable(); > - LOCK_PROFILE_REL; > - _raw_spin_unlock(&lock->raw); > + _spin_unlock(lock); > local_irq_restore(flags); > } > > +static int __spin_is_locked(spinlock_t *lock) > +{ > + return lock->tickets.head != lock->tickets.tail; > +} > + > int _spin_is_locked(spinlock_t *lock) > { > check_lock(&lock->debug); > - return _raw_spin_is_locked(&lock->raw); > + return __spin_is_locked(lock); > } > > int _spin_trylock(spinlock_t *lock) > { > + spinlock_tickets_t old, new; > + > check_lock(&lock->debug); > - if ( !_raw_spin_trylock(&lock->raw) ) > + old.head_tail = read_atomic(&lock->tickets.head_tail); > + if ( old.head != old.tail ) > + return 0; > + new = old; > + new.tail++; > + if ( cmpxchg(&lock->tickets.head_tail, old.head_tail, new.head_tail) > + != old.head_tail ) > return 0; > #ifdef LOCK_PROFILE > if (lock->profile) > @@ -239,7 +228,7 @@ void _spin_barrier(spinlock_t *lock) > u64 loop = 0; > > check_barrier(&lock->debug); > - do { smp_mb(); loop++;} while ( _raw_spin_is_locked(&lock->raw) ); > + do { smp_mb(); loop++;} while ( __spin_is_locked(lock) ); > if ((loop > 1) && lock->profile) > { > lock->profile->time_block += NOW() - block; > @@ -247,14 +236,14 @@ void _spin_barrier(spinlock_t *lock) > } > #else > check_barrier(&lock->debug); > - do { smp_mb(); } while ( _raw_spin_is_locked(&lock->raw) ); > + do { smp_mb(); } while ( __spin_is_locked(lock) ); > #endif > smp_mb(); > } > > int _spin_trylock_recursive(spinlock_t *lock) > { > - int cpu = smp_processor_id(); > + unsigned int cpu = smp_processor_id(); > > /* Don't allow overflow of recurse_cpu field. */ > BUILD_BUG_ON(NR_CPUS > 0xfffu); > @@ -277,8 +266,17 @@ int _spin_trylock_recursive(spinlock_t *lock) > > void _spin_lock_recursive(spinlock_t *lock) > { > - while ( !spin_trylock_recursive(lock) ) > - cpu_relax(); > + unsigned int cpu = smp_processor_id(); > + > + if ( likely(lock->recurse_cpu != cpu) ) > + { > + spin_lock(lock); > + lock->recurse_cpu = cpu; > + } > + > + /* We support only fairly shallow recursion, else the counter overflows. > */ > + ASSERT(lock->recurse_cnt < 0xfu); > + lock->recurse_cnt++; > } > > void _spin_unlock_recursive(spinlock_t *lock) > diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h > index eda9b2e..bafbc74 100644 > --- a/xen/include/xen/spinlock.h > +++ b/xen/include/xen/spinlock.h > @@ -80,8 +80,7 @@ struct lock_profile_qhead { > static struct lock_profile *__lock_profile_##name > \ > __used_section(".lockprofile.data") = > \ > &__lock_profile_data_##name > -#define _SPIN_LOCK_UNLOCKED(x) { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, > \ > - _LOCK_DEBUG, x } > +#define _SPIN_LOCK_UNLOCKED(x) { { 0 }, 0xfffu, 0, _LOCK_DEBUG, x } > #define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED(NULL) > #define DEFINE_SPINLOCK(l) > \ > spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL); > \ > @@ -117,8 +116,7 @@ extern void spinlock_profile_reset(unsigned char key); > > struct lock_profile_qhead { }; > > -#define SPIN_LOCK_UNLOCKED > \ > - { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG } > +#define SPIN_LOCK_UNLOCKED { { 0 }, 0xfffu, 0, _LOCK_DEBUG } > #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED > > #define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l)) > @@ -127,8 +125,16 @@ struct lock_profile_qhead { }; > > #endif > > +typedef union { > + u32 head_tail; > + struct { > + u16 head; > + u16 tail; > + }; > +} spinlock_tickets_t; > + > typedef struct spinlock { > - raw_spinlock_t raw; > + spinlock_tickets_t tickets; > u16 recurse_cpu:12; > u16 recurse_cnt:4; > struct lock_debug debug; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |