typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef signed long long s64; typedef _Bool bool; # define CC_SET(c) "\n\t/* output condition code " #c "*/\n" # define CC_OUT(c) "=@cc" #c #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) extern void __cmpxchg_wrong_size(void); #define __raw_cmpxchg(ptr, old, new, size, lock) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (old); \ __typeof__(*(ptr)) __new = (new); \ switch (size) { \ case 1: \ { \ volatile u8 *__ptr = (volatile u8 *)(ptr); \ asm volatile(lock "cmpxchgb %2,%1" \ : "=a" (__ret), "+m" (*__ptr) \ : "q" (__new), "0" (__old) \ : "memory"); \ break; \ } \ case 2: \ { \ volatile u16 *__ptr = (volatile u16 *)(ptr); \ asm volatile(lock "cmpxchgw %2,%1" \ : "=a" (__ret), "+m" (*__ptr) \ : "r" (__new), "0" (__old) \ : "memory"); \ break; \ } \ case 4: \ { \ volatile u32 *__ptr = (volatile u32 *)(ptr); \ asm volatile(lock "cmpxchgl %2,%1" \ : "=a" (__ret), "+m" (*__ptr) \ : "r" (__new), "0" (__old) \ : "memory"); \ break; \ } \ case 8: \ { \ volatile u64 *__ptr = (volatile u64 *)(ptr); \ asm volatile(lock "cmpxchgq %2,%1" \ : "=a" (__ret), "+m" (*__ptr) \ : "r" (__new), "0" (__old) \ : "memory"); \ break; \ } \ default: \ __cmpxchg_wrong_size(); \ } \ __ret; \ }) #define __cmpxchg(ptr, old, new, size) \ __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) #define cmpxchg(ptr, old, new) \ __cmpxchg(ptr, old, new, sizeof(*(ptr))) #define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock) \ ({ \ bool success; \ __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __new = (_new); \ switch (size) { \ case 1: \ { \ volatile u8 *__ptr = (volatile u8 *)(_ptr); \ asm volatile(lock "cmpxchgb %[new], %[ptr]" \ CC_SET(z) \ : CC_OUT(z) (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "q" (__new) \ : "memory"); \ break; \ } \ case 2: \ { \ volatile u16 *__ptr = (volatile u16 *)(_ptr); \ asm volatile(lock "cmpxchgw %[new], %[ptr]" \ CC_SET(z) \ : CC_OUT(z) (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ : "memory"); \ break; \ } \ case 4: \ { \ volatile u32 *__ptr = (volatile u32 *)(_ptr); \ asm volatile(lock "cmpxchgl %[new], %[ptr]" \ CC_SET(z) \ : CC_OUT(z) (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ : "memory"); \ break; \ } \ case 8: \ { \ volatile u64 *__ptr = (volatile u64 *)(_ptr); \ asm volatile(lock "cmpxchgq %[new], %[ptr]" \ CC_SET(z) \ : CC_OUT(z) (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ : "memory"); \ break; \ } \ default: \ __cmpxchg_wrong_size(); \ } \ if (unlikely(!success)) \ *_old = __old; \ likely(success); \ }) #define LOCK_PREFIX "lock; " #define __try_cmpxchg(ptr, pold, new, size) \ __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) #define try_cmpxchg(ptr, pold, new) \ __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr))) #define READ_ONCE(x) (*(volatile typeof(x) *)(&x)) int __down_read_trylock1(unsigned long *l) { long tmp; while ((tmp = READ_ONCE(*l)) >= 0) { if (tmp == cmpxchg(l, tmp, tmp + 1)) return 1; } return 0; } int __down_read_trylock2(unsigned long *l) { long tmp = READ_ONCE(*l); while (tmp >= 0) { if (try_cmpxchg(l, &tmp, tmp + 1)) return 1; } return 0; } int __down_read_trylock3(unsigned long *l) { long new, old = READ_ONCE(*l); for (;;) { new = old + 1; if (new <= 0) return 0; if (try_cmpxchg(l, &old, new)) return 1; } }