Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 211 lines 6.0 kB view raw
1/* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for i486+ 2 * 3 * Written by David Howells (dhowells@redhat.com). 4 * 5 * Derived from asm-x86/semaphore.h 6 * 7 * 8 * The MSW of the count is the negated number of active writers and waiting 9 * lockers, and the LSW is the total number of active locks 10 * 11 * The lock count is initialized to 0 (no active and no waiting lockers). 12 * 13 * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an 14 * uncontended lock. This can be determined because XADD returns the old value. 15 * Readers increment by 1 and see a positive value when uncontended, negative 16 * if there are writers (and maybe) readers waiting (in which case it goes to 17 * sleep). 18 * 19 * The value of WAITING_BIAS supports up to 32766 waiting processes. This can 20 * be extended to 65534 by manually checking the whole MSW rather than relying 21 * on the S flag. 22 * 23 * The value of ACTIVE_BIAS supports up to 65535 active processes. 24 * 25 * This should be totally fair - if anything is waiting, a process that wants a 26 * lock will go to the back of the queue. When the currently active lock is 27 * released, if there's a writer at the front of the queue, then that and only 28 * that will be woken up; if there's a bunch of consequtive readers at the 29 * front, then they'll all be woken up, but no other readers will be. 30 */ 31 32#ifndef _ASM_X86_RWSEM_H 33#define _ASM_X86_RWSEM_H 34 35#ifndef _LINUX_RWSEM_H 36#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" 37#endif 38 39#ifdef __KERNEL__ 40#include <asm/asm.h> 41 42/* 43 * The bias values and the counter type limits the number of 44 * potential readers/writers to 32767 for 32 bits and 2147483647 45 * for 64 bits. 46 */ 47 48#ifdef CONFIG_X86_64 49# define RWSEM_ACTIVE_MASK 0xffffffffL 50#else 51# define RWSEM_ACTIVE_MASK 0x0000ffffL 52#endif 53 54#define RWSEM_UNLOCKED_VALUE 0x00000000L 55#define RWSEM_ACTIVE_BIAS 0x00000001L 56#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) 57#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS 58#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) 59 60/* 61 * lock for reading 62 */ 63static inline void __down_read(struct rw_semaphore *sem) 64{ 65 asm volatile("# beginning down_read\n\t" 66 LOCK_PREFIX _ASM_INC "(%1)\n\t" 67 /* adds 0x00000001 */ 68 " jns 1f\n" 69 " call call_rwsem_down_read_failed\n" 70 "1:\n\t" 71 "# ending down_read\n\t" 72 : "+m" (sem->count) 73 : "a" (sem) 74 : "memory", "cc"); 75} 76 77/* 78 * trylock for reading -- returns 1 if successful, 0 if contention 79 */ 80static inline int __down_read_trylock(struct rw_semaphore *sem) 81{ 82 long result, tmp; 83 asm volatile("# beginning __down_read_trylock\n\t" 84 " mov %0,%1\n\t" 85 "1:\n\t" 86 " mov %1,%2\n\t" 87 " add %3,%2\n\t" 88 " jle 2f\n\t" 89 LOCK_PREFIX " cmpxchg %2,%0\n\t" 90 " jnz 1b\n\t" 91 "2:\n\t" 92 "# ending __down_read_trylock\n\t" 93 : "+m" (sem->count), "=&a" (result), "=&r" (tmp) 94 : "i" (RWSEM_ACTIVE_READ_BIAS) 95 : "memory", "cc"); 96 return result >= 0 ? 1 : 0; 97} 98 99/* 100 * lock for writing 101 */ 102static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) 103{ 104 long tmp; 105 asm volatile("# beginning down_write\n\t" 106 LOCK_PREFIX " xadd %1,(%2)\n\t" 107 /* adds 0xffff0001, returns the old value */ 108 " test %1,%1\n\t" 109 /* was the count 0 before? */ 110 " jz 1f\n" 111 " call call_rwsem_down_write_failed\n" 112 "1:\n" 113 "# ending down_write" 114 : "+m" (sem->count), "=d" (tmp) 115 : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) 116 : "memory", "cc"); 117} 118 119static inline void __down_write(struct rw_semaphore *sem) 120{ 121 __down_write_nested(sem, 0); 122} 123 124/* 125 * trylock for writing -- returns 1 if successful, 0 if contention 126 */ 127static inline int __down_write_trylock(struct rw_semaphore *sem) 128{ 129 long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, 130 RWSEM_ACTIVE_WRITE_BIAS); 131 if (ret == RWSEM_UNLOCKED_VALUE) 132 return 1; 133 return 0; 134} 135 136/* 137 * unlock after reading 138 */ 139static inline void __up_read(struct rw_semaphore *sem) 140{ 141 long tmp; 142 asm volatile("# beginning __up_read\n\t" 143 LOCK_PREFIX " xadd %1,(%2)\n\t" 144 /* subtracts 1, returns the old value */ 145 " jns 1f\n\t" 146 " call call_rwsem_wake\n" /* expects old value in %edx */ 147 "1:\n" 148 "# ending __up_read\n" 149 : "+m" (sem->count), "=d" (tmp) 150 : "a" (sem), "1" (-RWSEM_ACTIVE_READ_BIAS) 151 : "memory", "cc"); 152} 153 154/* 155 * unlock after writing 156 */ 157static inline void __up_write(struct rw_semaphore *sem) 158{ 159 long tmp; 160 asm volatile("# beginning __up_write\n\t" 161 LOCK_PREFIX " xadd %1,(%2)\n\t" 162 /* subtracts 0xffff0001, returns the old value */ 163 " jns 1f\n\t" 164 " call call_rwsem_wake\n" /* expects old value in %edx */ 165 "1:\n\t" 166 "# ending __up_write\n" 167 : "+m" (sem->count), "=d" (tmp) 168 : "a" (sem), "1" (-RWSEM_ACTIVE_WRITE_BIAS) 169 : "memory", "cc"); 170} 171 172/* 173 * downgrade write lock to read lock 174 */ 175static inline void __downgrade_write(struct rw_semaphore *sem) 176{ 177 asm volatile("# beginning __downgrade_write\n\t" 178 LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t" 179 /* 180 * transitions 0xZZZZ0001 -> 0xYYYY0001 (i386) 181 * 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 (x86_64) 182 */ 183 " jns 1f\n\t" 184 " call call_rwsem_downgrade_wake\n" 185 "1:\n\t" 186 "# ending __downgrade_write\n" 187 : "+m" (sem->count) 188 : "a" (sem), "er" (-RWSEM_WAITING_BIAS) 189 : "memory", "cc"); 190} 191 192/* 193 * implement atomic add functionality 194 */ 195static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) 196{ 197 asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0" 198 : "+m" (sem->count) 199 : "er" (delta)); 200} 201 202/* 203 * implement exchange and add functionality 204 */ 205static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) 206{ 207 return delta + xadd(&sem->count, delta); 208} 209 210#endif /* __KERNEL__ */ 211#endif /* _ASM_X86_RWSEM_H */