#include <linux/kernel.h>
#include <linux/preempt.h>
-#include <linux/atomic.h>
-#include <linux/bug.h>
+#include <linux/futex.h>
-static inline void bit_spin_lock(int bitnum, unsigned long *addr)
+static inline void bit_spin_lock(int nr, unsigned long *_addr)
{
- while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
- do {
- cpu_relax();
- } while (test_bit(bitnum, addr));
- }
-}
+ u32 mask, *addr = ((u32 *) _addr) + (nr / 32), v;
-static inline int bit_spin_trylock(int bitnum, unsigned long *addr)
-{
- return !test_and_set_bit_lock(bitnum, addr);
-}
+ nr &= 31;
+ mask = 1U << nr;
-static inline void bit_spin_unlock(int bitnum, unsigned long *addr)
-{
- BUG_ON(!test_bit(bitnum, addr));
+ while (1) {
+ v = __atomic_fetch_or(addr, mask, __ATOMIC_ACQUIRE);
+ if (!(v & mask))
+ break;
- clear_bit_unlock(bitnum, addr);
+ futex(addr, FUTEX_WAIT|FUTEX_PRIVATE_FLAG, v, NULL, NULL, 0);
+ }
}
-static inline void __bit_spin_unlock(int bitnum, unsigned long *addr)
+static inline void bit_spin_wake(int nr, unsigned long *_addr)
{
- bit_spin_unlock(bitnum, addr);
+ u32 *addr = ((u32 *) _addr) + (nr / 32);
+
+ futex(addr, FUTEX_WAKE|FUTEX_PRIVATE_FLAG, INT_MAX, NULL, NULL, 0);
}
-static inline int bit_spin_is_locked(int bitnum, unsigned long *addr)
+static inline void bit_spin_unlock(int nr, unsigned long *_addr)
{
- return test_bit(bitnum, addr);
+ u32 mask, *addr = ((u32 *) _addr) + (nr / 32);
+
+ nr &= 31;
+ mask = 1U << nr;
+
+ __atomic_and_fetch(addr, ~mask, __ATOMIC_RELEASE);
+ futex(addr, FUTEX_WAKE|FUTEX_PRIVATE_FLAG, INT_MAX, NULL, NULL, 0);
}
#endif /* __LINUX_BIT_SPINLOCK_H */