Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking changes from Ingo Molnar: "The main changes in this cycle were: - More gradual enhancements to atomic ops: new atomic*_read_ctrl() ops, synchronize atomic_{read,set}() ordering requirements between architectures, add atomic_long_t bitops. (Peter Zijlstra) - Add _{relaxed|acquire|release}() variants for inc/dec atomics and use them in various locking primitives: mutex, rtmutex, mcs, rwsem. This enables weakly ordered architectures (such as arm64) to make use of more locking related optimizations. (Davidlohr Bueso) - Implement atomic[64]_{inc,dec}_relaxed() on ARM. (Will Deacon) - Futex kernel data cache footprint micro-optimization. (Rasmus Villemoes) - pvqspinlock runtime overhead micro-optimization. (Waiman Long) - misc smaller fixlets" * 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: ARM, locking/atomics: Implement _relaxed variants of atomic[64]_{inc,dec} locking/rwsem: Use acquire/release semantics locking/mcs: Use acquire/release semantics locking/rtmutex: Use acquire/release semantics locking/mutex: Use acquire/release semantics locking/asm-generic: Add _{relaxed|acquire|release}() variants for inc/dec atomics atomic: Implement atomic_read_ctrl() atomic, arch: Audit atomic_{read,set}() atomic: Add atomic_long_t bitops futex: Force hot variables into a single cache line locking/pvqspinlock: Kick the PV CPU unconditionally when _Q_SLOW_VAL locking/osq: Relax atomic semantics locking/qrwlock: Rename ->lock to ->wait_lock locking/Documentation/lockstat: Fix typo - lokcing -> locking locking/atomics, cmpxchg: Privatize the inclusion of asm/cmpxchg.h
This commit is contained in:
@@ -35,7 +35,7 @@ typedef atomic_t atomic_long_t;
|
||||
#endif
|
||||
|
||||
#define ATOMIC_LONG_READ_OP(mo) \
|
||||
static inline long atomic_long_read##mo(atomic_long_t *l) \
|
||||
static inline long atomic_long_read##mo(const atomic_long_t *l) \
|
||||
{ \
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \
|
||||
\
|
||||
@@ -43,6 +43,7 @@ static inline long atomic_long_read##mo(atomic_long_t *l) \
|
||||
}
|
||||
ATOMIC_LONG_READ_OP()
|
||||
ATOMIC_LONG_READ_OP(_acquire)
|
||||
ATOMIC_LONG_READ_OP(_ctrl)
|
||||
|
||||
#undef ATOMIC_LONG_READ_OP
|
||||
|
||||
@@ -112,19 +113,23 @@ static inline void atomic_long_dec(atomic_long_t *l)
|
||||
ATOMIC_LONG_PFX(_dec)(v);
|
||||
}
|
||||
|
||||
static inline void atomic_long_add(long i, atomic_long_t *l)
|
||||
{
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l;
|
||||
|
||||
ATOMIC_LONG_PFX(_add)(i, v);
|
||||
#define ATOMIC_LONG_OP(op) \
|
||||
static inline void \
|
||||
atomic_long_##op(long i, atomic_long_t *l) \
|
||||
{ \
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \
|
||||
\
|
||||
ATOMIC_LONG_PFX(_##op)(i, v); \
|
||||
}
|
||||
|
||||
static inline void atomic_long_sub(long i, atomic_long_t *l)
|
||||
{
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l;
|
||||
ATOMIC_LONG_OP(add)
|
||||
ATOMIC_LONG_OP(sub)
|
||||
ATOMIC_LONG_OP(and)
|
||||
ATOMIC_LONG_OP(or)
|
||||
ATOMIC_LONG_OP(xor)
|
||||
ATOMIC_LONG_OP(andnot)
|
||||
|
||||
ATOMIC_LONG_PFX(_sub)(i, v);
|
||||
}
|
||||
#undef ATOMIC_LONG_OP
|
||||
|
||||
static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
|
||||
{
|
||||
@@ -154,19 +159,24 @@ static inline int atomic_long_add_negative(long i, atomic_long_t *l)
|
||||
return ATOMIC_LONG_PFX(_add_negative)(i, v);
|
||||
}
|
||||
|
||||
static inline long atomic_long_inc_return(atomic_long_t *l)
|
||||
{
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l;
|
||||
|
||||
return (long)ATOMIC_LONG_PFX(_inc_return)(v);
|
||||
#define ATOMIC_LONG_INC_DEC_OP(op, mo) \
|
||||
static inline long \
|
||||
atomic_long_##op##_return##mo(atomic_long_t *l) \
|
||||
{ \
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \
|
||||
\
|
||||
return (long)ATOMIC_LONG_PFX(_##op##_return##mo)(v); \
|
||||
}
|
||||
ATOMIC_LONG_INC_DEC_OP(inc,)
|
||||
ATOMIC_LONG_INC_DEC_OP(inc, _relaxed)
|
||||
ATOMIC_LONG_INC_DEC_OP(inc, _acquire)
|
||||
ATOMIC_LONG_INC_DEC_OP(inc, _release)
|
||||
ATOMIC_LONG_INC_DEC_OP(dec,)
|
||||
ATOMIC_LONG_INC_DEC_OP(dec, _relaxed)
|
||||
ATOMIC_LONG_INC_DEC_OP(dec, _acquire)
|
||||
ATOMIC_LONG_INC_DEC_OP(dec, _release)
|
||||
|
||||
static inline long atomic_long_dec_return(atomic_long_t *l)
|
||||
{
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l;
|
||||
|
||||
return (long)ATOMIC_LONG_PFX(_dec_return)(v);
|
||||
}
|
||||
#undef ATOMIC_LONG_INC_DEC_OP
|
||||
|
||||
static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
|
||||
{
|
||||
|
@@ -127,7 +127,7 @@ ATOMIC_OP(xor, ^)
|
||||
* Atomically reads the value of @v.
|
||||
*/
|
||||
#ifndef atomic_read
|
||||
#define atomic_read(v) ACCESS_ONCE((v)->counter)
|
||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -137,7 +137,7 @@ ATOMIC_OP(xor, ^)
|
||||
*
|
||||
* Atomically sets the value of @v to @i.
|
||||
*/
|
||||
#define atomic_set(v, i) (((v)->counter) = (i))
|
||||
#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
|
||||
|
||||
#include <linux/irqflags.h>
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
static inline void
|
||||
__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
{
|
||||
if (unlikely(atomic_dec_return(count) < 0))
|
||||
if (unlikely(atomic_dec_return_acquire(count) < 0))
|
||||
fail_fn(count);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
static inline int
|
||||
__mutex_fastpath_lock_retval(atomic_t *count)
|
||||
{
|
||||
if (unlikely(atomic_dec_return(count) < 0))
|
||||
if (unlikely(atomic_dec_return_acquire(count) < 0))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ __mutex_fastpath_lock_retval(atomic_t *count)
|
||||
static inline void
|
||||
__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
{
|
||||
if (unlikely(atomic_inc_return(count) <= 0))
|
||||
if (unlikely(atomic_inc_return_release(count) <= 0))
|
||||
fail_fn(count);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
static inline int
|
||||
__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
{
|
||||
if (likely(atomic_cmpxchg(count, 1, 0) == 1))
|
||||
if (likely(atomic_cmpxchg_acquire(count, 1, 0) == 1))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
* to ensure that any waiting tasks are woken up by the
|
||||
* unlock slow path.
|
||||
*/
|
||||
if (likely(atomic_xchg(count, -1) != 1))
|
||||
if (likely(atomic_xchg_acquire(count, -1) != 1))
|
||||
fail_fn(count);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
static inline int
|
||||
__mutex_fastpath_lock_retval(atomic_t *count)
|
||||
{
|
||||
if (unlikely(atomic_xchg(count, 0) != 1))
|
||||
if (unlikely(atomic_xchg_acquire(count, 0) != 1))
|
||||
if (likely(atomic_xchg(count, -1) != 1))
|
||||
return -1;
|
||||
return 0;
|
||||
@@ -67,7 +67,7 @@ __mutex_fastpath_lock_retval(atomic_t *count)
|
||||
static inline void
|
||||
__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
{
|
||||
if (unlikely(atomic_xchg(count, 1) != 0))
|
||||
if (unlikely(atomic_xchg_release(count, 1) != 0))
|
||||
fail_fn(count);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
static inline int
|
||||
__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
{
|
||||
int prev = atomic_xchg(count, 0);
|
||||
int prev = atomic_xchg_acquire(count, 0);
|
||||
|
||||
if (unlikely(prev < 0)) {
|
||||
/*
|
||||
@@ -105,7 +105,7 @@ __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
* owner's unlock path needlessly, but that's not a problem
|
||||
* in practice. ]
|
||||
*/
|
||||
prev = atomic_xchg(count, prev);
|
||||
prev = atomic_xchg_acquire(count, prev);
|
||||
if (prev < 0)
|
||||
prev = 0;
|
||||
}
|
||||
|
@@ -10,12 +10,12 @@
|
||||
|
||||
typedef struct qrwlock {
|
||||
atomic_t cnts;
|
||||
arch_spinlock_t lock;
|
||||
arch_spinlock_t wait_lock;
|
||||
} arch_rwlock_t;
|
||||
|
||||
#define __ARCH_RW_LOCK_UNLOCKED { \
|
||||
.cnts = ATOMIC_INIT(0), \
|
||||
.lock = __ARCH_SPIN_LOCK_UNLOCKED, \
|
||||
.wait_lock = __ARCH_SPIN_LOCK_UNLOCKED, \
|
||||
}
|
||||
|
||||
#endif /* __ASM_GENERIC_QRWLOCK_TYPES_H */
|
||||
|
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
static inline void __down_read(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
|
||||
if (unlikely(atomic_long_inc_return_acquire((atomic_long_t *)&sem->count) <= 0))
|
||||
rwsem_down_read_failed(sem);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
|
||||
long tmp;
|
||||
|
||||
while ((tmp = sem->count) >= 0) {
|
||||
if (tmp == cmpxchg(&sem->count, tmp,
|
||||
if (tmp == cmpxchg_acquire(&sem->count, tmp,
|
||||
tmp + RWSEM_ACTIVE_READ_BIAS)) {
|
||||
return 1;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
tmp = atomic_long_add_return_acquire(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
(atomic_long_t *)&sem->count);
|
||||
if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
|
||||
rwsem_down_write_failed(sem);
|
||||
@@ -72,7 +72,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
tmp = cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
RWSEM_ACTIVE_WRITE_BIAS);
|
||||
return tmp == RWSEM_UNLOCKED_VALUE;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ static inline void __up_read(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
|
||||
tmp = atomic_long_dec_return_release((atomic_long_t *)&sem->count);
|
||||
if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
|
||||
rwsem_wake(sem);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ static inline void __up_read(struct rw_semaphore *sem)
|
||||
*/
|
||||
static inline void __up_write(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
if (unlikely(atomic_long_sub_return_release(RWSEM_ACTIVE_WRITE_BIAS,
|
||||
(atomic_long_t *)&sem->count) < 0))
|
||||
rwsem_wake(sem);
|
||||
}
|
||||
@@ -114,7 +114,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
|
||||
/*
|
||||
* When downgrading from exclusive to shared ownership,
|
||||
* anything inside the write-locked region cannot leak
|
||||
* into the read side. In contrast, anything in the
|
||||
* read-locked region is ok to be re-ordered into the
|
||||
* write side. As such, rely on RELEASE semantics.
|
||||
*/
|
||||
tmp = atomic_long_add_return_release(-RWSEM_WAITING_BIAS,
|
||||
(atomic_long_t *)&sem->count);
|
||||
if (tmp < 0)
|
||||
rwsem_downgrade_wake(sem);
|
||||
|
Reference in New Issue
Block a user