mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 00:20:32 +00:00
locking/atomic, arch/alpha: Implement atomic{,64}_fetch_{add,sub,and,andnot,or,xor}()
Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Matt Turner <mattst88@gmail.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Richard Henderson <rth@twiddle.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-alpha@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
b316ff783d
commit
1f51dee7ca
1 changed files with 56 additions and 9 deletions
|
@ -65,6 +65,25 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
|
||||||
return result; \
|
return result; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ATOMIC_FETCH_OP(op, asm_op) \
|
||||||
|
static inline int atomic_fetch_##op(int i, atomic_t *v) \
|
||||||
|
{ \
|
||||||
|
long temp, result; \
|
||||||
|
smp_mb(); \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
"1: ldl_l %2,%1\n" \
|
||||||
|
" " #asm_op " %2,%3,%0\n" \
|
||||||
|
" stl_c %0,%1\n" \
|
||||||
|
" beq %0,2f\n" \
|
||||||
|
".subsection 2\n" \
|
||||||
|
"2: br 1b\n" \
|
||||||
|
".previous" \
|
||||||
|
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||||
|
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||||
|
smp_mb(); \
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
#define ATOMIC64_OP(op, asm_op) \
|
#define ATOMIC64_OP(op, asm_op) \
|
||||||
static __inline__ void atomic64_##op(long i, atomic64_t * v) \
|
static __inline__ void atomic64_##op(long i, atomic64_t * v) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -101,11 +120,32 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \
|
||||||
return result; \
|
return result; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ATOMIC64_FETCH_OP(op, asm_op) \
|
||||||
|
static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \
|
||||||
|
{ \
|
||||||
|
long temp, result; \
|
||||||
|
smp_mb(); \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
"1: ldq_l %2,%1\n" \
|
||||||
|
" " #asm_op " %2,%3,%0\n" \
|
||||||
|
" stq_c %0,%1\n" \
|
||||||
|
" beq %0,2f\n" \
|
||||||
|
".subsection 2\n" \
|
||||||
|
"2: br 1b\n" \
|
||||||
|
".previous" \
|
||||||
|
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||||
|
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||||
|
smp_mb(); \
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
#define ATOMIC_OPS(op) \
|
#define ATOMIC_OPS(op) \
|
||||||
ATOMIC_OP(op, op##l) \
|
ATOMIC_OP(op, op##l) \
|
||||||
ATOMIC_OP_RETURN(op, op##l) \
|
ATOMIC_OP_RETURN(op, op##l) \
|
||||||
|
ATOMIC_FETCH_OP(op, op##l) \
|
||||||
ATOMIC64_OP(op, op##q) \
|
ATOMIC64_OP(op, op##q) \
|
||||||
ATOMIC64_OP_RETURN(op, op##q)
|
ATOMIC64_OP_RETURN(op, op##q) \
|
||||||
|
ATOMIC64_FETCH_OP(op, op##q)
|
||||||
|
|
||||||
ATOMIC_OPS(add)
|
ATOMIC_OPS(add)
|
||||||
ATOMIC_OPS(sub)
|
ATOMIC_OPS(sub)
|
||||||
|
@ -113,18 +153,25 @@ ATOMIC_OPS(sub)
|
||||||
#define atomic_andnot atomic_andnot
|
#define atomic_andnot atomic_andnot
|
||||||
#define atomic64_andnot atomic64_andnot
|
#define atomic64_andnot atomic64_andnot
|
||||||
|
|
||||||
ATOMIC_OP(and, and)
|
#define atomic_fetch_or atomic_fetch_or
|
||||||
ATOMIC_OP(andnot, bic)
|
|
||||||
ATOMIC_OP(or, bis)
|
|
||||||
ATOMIC_OP(xor, xor)
|
|
||||||
ATOMIC64_OP(and, and)
|
|
||||||
ATOMIC64_OP(andnot, bic)
|
|
||||||
ATOMIC64_OP(or, bis)
|
|
||||||
ATOMIC64_OP(xor, xor)
|
|
||||||
|
|
||||||
#undef ATOMIC_OPS
|
#undef ATOMIC_OPS
|
||||||
|
#define ATOMIC_OPS(op, asm) \
|
||||||
|
ATOMIC_OP(op, asm) \
|
||||||
|
ATOMIC_FETCH_OP(op, asm) \
|
||||||
|
ATOMIC64_OP(op, asm) \
|
||||||
|
ATOMIC64_FETCH_OP(op, asm)
|
||||||
|
|
||||||
|
ATOMIC_OPS(and, and)
|
||||||
|
ATOMIC_OPS(andnot, bic)
|
||||||
|
ATOMIC_OPS(or, bis)
|
||||||
|
ATOMIC_OPS(xor, xor)
|
||||||
|
|
||||||
|
#undef ATOMIC_OPS
|
||||||
|
#undef ATOMIC64_FETCH_OP
|
||||||
#undef ATOMIC64_OP_RETURN
|
#undef ATOMIC64_OP_RETURN
|
||||||
#undef ATOMIC64_OP
|
#undef ATOMIC64_OP
|
||||||
|
#undef ATOMIC_FETCH_OP
|
||||||
#undef ATOMIC_OP_RETURN
|
#undef ATOMIC_OP_RETURN
|
||||||
#undef ATOMIC_OP
|
#undef ATOMIC_OP
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue