From 26333576fd0d0b52f6e4025c5aded97e188bdd44 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Thu, 18 Oct 2007 03:06:39 -0700 Subject: [PATCH] bitops: introduce lock ops Introduce test_and_set_bit_lock / clear_bit_unlock bitops with lock semantics. Convert all architectures to use the generic implementation. Signed-off-by: Nick Piggin Acked-By: David Howells Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Haavard Skinnemoen Cc: Bryan Wu Cc: Mikael Starvik Cc: David Howells Cc: Yoshinori Sato Cc: "Luck, Tony" Cc: Hirokazu Takata Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: Greg Ungerer Cc: Ralf Baechle Cc: Kyle McMartin Cc: Matthew Wilcox Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: Paul Mundt Cc: Kazumoto Kojima Cc: Richard Curnow Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Miles Bader Cc: Andi Kleen Cc: Chris Zankel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/atomic_ops.txt | 14 ++++++++++ Documentation/memory-barriers.txt | 14 ++++++++-- include/asm-alpha/bitops.h | 1 + include/asm-arm/bitops.h | 1 + include/asm-avr32/bitops.h | 1 + include/asm-blackfin/bitops.h | 1 + include/asm-cris/bitops.h | 1 + include/asm-frv/bitops.h | 1 + include/asm-generic/bitops.h | 1 + include/asm-generic/bitops/lock.h | 45 +++++++++++++++++++++++++++++++ include/asm-h8300/bitops.h | 1 + include/asm-ia64/bitops.h | 2 ++ include/asm-m32r/bitops.h | 1 + include/asm-m68k/bitops.h | 1 + include/asm-m68knommu/bitops.h | 1 + include/asm-mips/bitops.h | 1 + include/asm-parisc/bitops.h | 1 + include/asm-powerpc/bitops.h | 1 + include/asm-s390/bitops.h | 1 + include/asm-sh/bitops.h | 1 + include/asm-sh64/bitops.h | 1 + include/asm-sparc/bitops.h | 1 + include/asm-sparc64/bitops.h | 1 + include/asm-v850/bitops.h | 1 + include/asm-x86/bitops_32.h | 1 + include/asm-x86/bitops_64.h | 1 + include/asm-xtensa/bitops.h | 1 + 27 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 include/asm-generic/bitops/lock.h diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index d46306fea23..f20c10c2858 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -418,6 +418,20 @@ brothers: */ smp_mb__after_clear_bit(); +There are two special bitops with lock barrier semantics (acquire/release, +same as spinlocks). These operate in the same way as their non-_lock/unlock +postfixed variants, except that they are to provide acquire/release semantics, +respectively. This means they can be used for bit_spin_trylock and +bit_spin_unlock type operations without specifying any more barriers. + + int test_and_set_bit_lock(unsigned long nr, unsigned long *addr); + void clear_bit_unlock(unsigned long nr, unsigned long *addr); + void __clear_bit_unlock(unsigned long nr, unsigned long *addr); + +The __clear_bit_unlock version is non-atomic, however it still implements +unlock barrier semantics. This can be useful if the lock itself is protecting +the other bits in the word. + Finally, there are non-atomic versions of the bitmask operations provided. They are used in contexts where some other higher-level SMP locking scheme is being used to protect the bitmask, and thus less diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 650657c5473..4e17beba237 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1479,7 +1479,8 @@ kernel. Any atomic operation that modifies some state in memory and returns information about the state (old or new) implies an SMP-conditional general memory barrier -(smp_mb()) on each side of the actual operation. These include: +(smp_mb()) on each side of the actual operation (with the exception of +explicit lock operations, described later). These include: xchg(); cmpxchg(); @@ -1536,10 +1537,19 @@ If they're used for constructing a lock of some description, then they probably do need memory barriers as a lock primitive generally has to do things in a specific order. - Basically, each usage case has to be carefully considered as to whether memory barriers are needed or not. +The following operations are special locking primitives: + + test_and_set_bit_lock(); + clear_bit_unlock(); + __clear_bit_unlock(); + +These implement LOCK-class and UNLOCK-class operations. These should be used in +preference to other operations when implementing locking primitives, because +their implementations can be optimised on many architectures. + [!] Note that special memory barrier primitives are available for these situations because on some CPUs the atomic instructions used imply full memory barriers, and so barrier instructions are superfluous in conjunction with them, diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h index 9e71201000d..ca667d12189 100644 --- a/include/asm-alpha/bitops.h +++ b/include/asm-alpha/bitops.h @@ -367,6 +367,7 @@ static inline unsigned int hweight8(unsigned int w) #else #include #endif +#include #endif /* __KERNEL__ */ diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h index b41831b6432..52fe05895de 100644 --- a/include/asm-arm/bitops.h +++ b/include/asm-arm/bitops.h @@ -286,6 +286,7 @@ static inline int constant_fls(int x) #include #include +#include /* * Ext2 is defined to use little-endian byte ordering. diff --git a/include/asm-avr32/bitops.h b/include/asm-avr32/bitops.h index 5299f8c8e11..f3faddfd46a 100644 --- a/include/asm-avr32/bitops.h +++ b/include/asm-avr32/bitops.h @@ -288,6 +288,7 @@ static inline int ffs(unsigned long word) #include #include #include +#include #include #include diff --git a/include/asm-blackfin/bitops.h b/include/asm-blackfin/bitops.h index 27c2d0e48e1..03ecedc1f2a 100644 --- a/include/asm-blackfin/bitops.h +++ b/include/asm-blackfin/bitops.h @@ -199,6 +199,7 @@ static __inline__ int __test_bit(int nr, const void *addr) #include #include +#include #include #include diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h index a569065113d..617151b9b72 100644 --- a/include/asm-cris/bitops.h +++ b/include/asm-cris/bitops.h @@ -154,6 +154,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) #include #include #include +#include #include diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h index f8560edf59f..8dba74b1a25 100644 --- a/include/asm-frv/bitops.h +++ b/include/asm-frv/bitops.h @@ -302,6 +302,7 @@ int __ilog2_u64(u64 n) #include #include +#include #include diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h index 1f9d99193df..e022a0f59e6 100644 --- a/include/asm-generic/bitops.h +++ b/include/asm-generic/bitops.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/include/asm-generic/bitops/lock.h b/include/asm-generic/bitops/lock.h new file mode 100644 index 00000000000..308a9e22c80 --- /dev/null +++ b/include/asm-generic/bitops/lock.h @@ -0,0 +1,45 @@ +#ifndef _ASM_GENERIC_BITOPS_LOCK_H_ +#define _ASM_GENERIC_BITOPS_LOCK_H_ + +/** + * test_and_set_bit_lock - Set a bit and return its old value, for lock + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and provides acquire barrier semantics. + * It can be used to implement bit locks. + */ +#define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr) + +/** + * clear_bit_unlock - Clear a bit in memory, for unlock + * @nr: the bit to set + * @addr: the address to start counting from + * + * This operation is atomic and provides release barrier semantics. + */ +#define clear_bit_unlock(nr, addr) \ +do { \ + smp_mb__before_clear_bit(); \ + clear_bit(nr, addr); \ +} while (0) + +/** + * __clear_bit_unlock - Clear a bit in memory, for unlock + * @nr: the bit to set + * @addr: the address to start counting from + * + * This operation is like clear_bit_unlock, however it is not atomic. + * It does provide release barrier semantics so it can be used to unlock + * a bit lock, however it would only be used if no other CPU can modify + * any bits in the memory until the lock is released (a good example is + * if the bit lock itself protects access to the other bits in the word). + */ +#define __clear_bit_unlock(nr, addr) \ +do { \ + smp_mb(); \ + __clear_bit(nr, addr); \ +} while (0) + +#endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */ + diff --git a/include/asm-h8300/bitops.h b/include/asm-h8300/bitops.h index d76299c98b8..e64ad315656 100644 --- a/include/asm-h8300/bitops.h +++ b/include/asm-h8300/bitops.h @@ -194,6 +194,7 @@ static __inline__ unsigned long __ffs(unsigned long word) #include #include #include +#include #include #include #include diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h index 6cc517e212a..569dd62fe19 100644 --- a/include/asm-ia64/bitops.h +++ b/include/asm-ia64/bitops.h @@ -371,6 +371,8 @@ hweight64 (unsigned long x) #define hweight16(x) (unsigned int) hweight64((x) & 0xfffful) #define hweight8(x) (unsigned int) hweight64((x) & 0xfful) +#include + #endif /* __KERNEL__ */ #include diff --git a/include/asm-m32r/bitops.h b/include/asm-m32r/bitops.h index 66ab672162c..313a02c4a88 100644 --- a/include/asm-m32r/bitops.h +++ b/include/asm-m32r/bitops.h @@ -255,6 +255,7 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr) #include #include #include +#include #endif /* __KERNEL__ */ diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h index 1a61fdb56aa..da151f70cdc 100644 --- a/include/asm-m68k/bitops.h +++ b/include/asm-m68k/bitops.h @@ -314,6 +314,7 @@ static inline int fls(int x) #include #include #include +#include /* Bitmap functions for the minix filesystem */ diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h index 7d6075d9b5c..b8b2770d687 100644 --- a/include/asm-m68knommu/bitops.h +++ b/include/asm-m68knommu/bitops.h @@ -160,6 +160,7 @@ static __inline__ int __test_bit(int nr, const volatile unsigned long * addr) #include #include +#include static __inline__ int ext2_set_bit(int nr, volatile void * addr) { diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 899357a72ac..0d3373f6492 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -556,6 +556,7 @@ static inline int ffs(int word) #include #include +#include #include #include #include diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h index 015cb0d379b..03ae287baf8 100644 --- a/include/asm-parisc/bitops.h +++ b/include/asm-parisc/bitops.h @@ -208,6 +208,7 @@ static __inline__ int fls(int x) #include #include +#include #include #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h index 8144a2788db..1d4c16613d2 100644 --- a/include/asm-powerpc/bitops.h +++ b/include/asm-powerpc/bitops.h @@ -266,6 +266,7 @@ static __inline__ int fls(unsigned int x) #include #include +#include #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) unsigned long find_next_zero_bit(const unsigned long *addr, diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index f79c9b792af..d756b34d25f 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -746,6 +746,7 @@ static inline int sched_find_first_bit(unsigned long *b) #include #include +#include /* * ATTENTION: intel byte ordering convention for ext2 and minix !! diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h index 1c16792cee1..9d7021723a2 100644 --- a/include/asm-sh/bitops.h +++ b/include/asm-sh/bitops.h @@ -137,6 +137,7 @@ static inline unsigned long __ffs(unsigned long word) #include #include #include +#include #include #include #include diff --git a/include/asm-sh64/bitops.h b/include/asm-sh64/bitops.h index f3bdcdb5d04..444d5ea92ce 100644 --- a/include/asm-sh64/bitops.h +++ b/include/asm-sh64/bitops.h @@ -136,6 +136,7 @@ static __inline__ unsigned long ffz(unsigned long word) #include #include #include +#include #include #include #include diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h index 329e696e775..00bd0a679d7 100644 --- a/include/asm-sparc/bitops.h +++ b/include/asm-sparc/bitops.h @@ -96,6 +96,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) #include #include #include +#include #include #include #include diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h index 3d5e1af8472..dd4bfe993b6 100644 --- a/include/asm-sparc64/bitops.h +++ b/include/asm-sparc64/bitops.h @@ -81,6 +81,7 @@ static inline unsigned int hweight8(unsigned int w) #include #endif +#include #endif /* __KERNEL__ */ #include diff --git a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h index 1fa99baf4e2..8eafdb1c08b 100644 --- a/include/asm-v850/bitops.h +++ b/include/asm-v850/bitops.h @@ -145,6 +145,7 @@ static inline int __test_bit (int nr, const void *addr) #include #include #include +#include #include #define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) diff --git a/include/asm-x86/bitops_32.h b/include/asm-x86/bitops_32.h index a20fe9822f6..c96641f7502 100644 --- a/include/asm-x86/bitops_32.h +++ b/include/asm-x86/bitops_32.h @@ -402,6 +402,7 @@ static inline int fls(int x) } #include +#include #endif /* __KERNEL__ */ diff --git a/include/asm-x86/bitops_64.h b/include/asm-x86/bitops_64.h index 1d7d9b4bcac..525edf2ce5c 100644 --- a/include/asm-x86/bitops_64.h +++ b/include/asm-x86/bitops_64.h @@ -408,6 +408,7 @@ static __inline__ int fls(int x) #define ARCH_HAS_FAST_MULTIPLIER 1 #include +#include #endif /* __KERNEL__ */ diff --git a/include/asm-xtensa/bitops.h b/include/asm-xtensa/bitops.h index 1c1e0d933ee..78db04cf6e4 100644 --- a/include/asm-xtensa/bitops.h +++ b/include/asm-xtensa/bitops.h @@ -108,6 +108,7 @@ static inline int fls (unsigned int x) #endif #include +#include #include #include -- 2.20.1