From: Nick Piggin Without branch hints, the very unlikely chance of the loop repeating due to cmpxchg failure is unrolled with gcc-4 that I have tested. Improve this for architectures with a native cas/cmpxchg. llsc archs should try to implement this natively. Signed-off-by: Nick Piggin Cc: Andi Kleen Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: "David S. Miller" Cc: Roman Zippel Signed-off-by: Andrew Morton --- include/asm-i386/atomic.h | 10 ++++++++-- include/asm-ia64/atomic.h | 10 ++++++++-- include/asm-m68k/atomic.h | 10 ++++++++-- include/asm-s390/atomic.h | 11 ++++++++--- include/asm-sparc64/atomic.h | 10 ++++++++-- include/asm-x86_64/atomic.h | 10 ++++++++-- 6 files changed, 48 insertions(+), 13 deletions(-) diff -puN include/asm-i386/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-i386/atomic.h --- devel/include/asm-i386/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-i386/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -225,9 +225,15 @@ static __inline__ int atomic_sub_return( ({ \ int c, old; \ c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + for (;;) { \ + if (unlikely(c == (u))) \ + break; \ + old = atomic_cmpxchg((v), c, c + (a)); \ + if (likely(old == c)) \ + break; \ c = old; \ - c != (u); \ + } \ + likely(c != (u)); \ }) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) diff -puN include/asm-ia64/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-ia64/atomic.h --- devel/include/asm-ia64/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-ia64/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -95,9 +95,15 @@ ia64_atomic64_sub (__s64 i, atomic64_t * ({ \ int c, old; \ c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + for (;;) { \ + if (unlikely(c == (u))) \ + break; \ + old = atomic_cmpxchg((v), c, c + (a)); \ + if (likely(old == c)) \ + break; \ c = old; \ - c != (u); \ + } \ + likely(c != (u)); \ }) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) diff -puN include/asm-m68k/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-m68k/atomic.h --- devel/include/asm-m68k/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-m68k/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -146,9 +146,15 @@ static inline void atomic_set_mask(unsig ({ \ int c, old; \ c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + for (;;) { \ + if (unlikely(c == (u))) \ + break; \ + old = atomic_cmpxchg((v), c, c + (a)); \ + if (likely(old == c)) \ + break; \ c = old; \ - c != (u); \ + } \ + likely(c != (u)); \ }) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) diff -puN include/asm-s390/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-s390/atomic.h --- devel/include/asm-s390/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-s390/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -89,11 +89,16 @@ static __inline__ int atomic_cmpxchg(ato static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) { int c, old; - c = atomic_read(v); - while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) + for (;;) { + if (unlikely(c == u)) + break; + old = atomic_cmpxchg(v, c, c + a); + if (likely(old == c)) + break; c = old; - return c != u; + } + return likely(c != u); } #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) diff -puN include/asm-sparc64/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-sparc64/atomic.h --- devel/include/asm-sparc64/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-sparc64/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -78,9 +78,15 @@ extern int atomic64_sub_ret(int, atomic6 ({ \ int c, old; \ c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + for (;;) { \ + if (unlikely(c == (u))) \ + break; \ + old = atomic_cmpxchg((v), c, c + (a)); \ + if (likely(old == c)) \ + break; \ c = old; \ - c != (u); \ + } \ + likely(c != (u)); \ }) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) diff -puN include/asm-x86_64/atomic.h~atomic-add_unless-cmpxchg-optimise include/asm-x86_64/atomic.h --- devel/include/asm-x86_64/atomic.h~atomic-add_unless-cmpxchg-optimise 2006-02-03 03:15:50.000000000 -0800 +++ devel-akpm/include/asm-x86_64/atomic.h 2006-02-03 03:15:50.000000000 -0800 @@ -405,9 +405,15 @@ static __inline__ long atomic64_sub_retu ({ \ int c, old; \ c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + for (;;) { \ + if (unlikely(c == (u))) \ + break; \ + old = atomic_cmpxchg((v), c, c + (a)); \ + if (likely(old == c)) \ + break; \ c = old; \ - c != (u); \ + } \ + likely(c != (u)); \ }) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) _