linux/arch/alpha/include/asm/rwsem.h
<<
>>
Prefs
   1#ifndef _ALPHA_RWSEM_H
   2#define _ALPHA_RWSEM_H
   3
   4/*
   5 * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
   6 * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
   7 */
   8
   9#ifndef _LINUX_RWSEM_H
  10#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  11#endif
  12
  13#ifdef __KERNEL__
  14
  15#include <linux/compiler.h>
  16#include <linux/list.h>
  17#include <linux/spinlock.h>
  18
  19struct rwsem_waiter;
  20
  21extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
  22extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
  23extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
  24extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
  25
  26/*
  27 * the semaphore definition
  28 */
  29struct rw_semaphore {
  30        long                    count;
  31#define RWSEM_UNLOCKED_VALUE            0x0000000000000000L
  32#define RWSEM_ACTIVE_BIAS               0x0000000000000001L
  33#define RWSEM_ACTIVE_MASK               0x00000000ffffffffL
  34#define RWSEM_WAITING_BIAS              (-0x0000000100000000L)
  35#define RWSEM_ACTIVE_READ_BIAS          RWSEM_ACTIVE_BIAS
  36#define RWSEM_ACTIVE_WRITE_BIAS         (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  37        spinlock_t              wait_lock;
  38        struct list_head        wait_list;
  39};
  40
  41#define __RWSEM_INITIALIZER(name) \
  42        { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
  43        LIST_HEAD_INIT((name).wait_list) }
  44
  45#define DECLARE_RWSEM(name) \
  46        struct rw_semaphore name = __RWSEM_INITIALIZER(name)
  47
  48static inline void init_rwsem(struct rw_semaphore *sem)
  49{
  50        sem->count = RWSEM_UNLOCKED_VALUE;
  51        spin_lock_init(&sem->wait_lock);
  52        INIT_LIST_HEAD(&sem->wait_list);
  53}
  54
  55static inline void __down_read(struct rw_semaphore *sem)
  56{
  57        long oldcount;
  58#ifndef CONFIG_SMP
  59        oldcount = sem->count;
  60        sem->count += RWSEM_ACTIVE_READ_BIAS;
  61#else
  62        long temp;
  63        __asm__ __volatile__(
  64        "1:     ldq_l   %0,%1\n"
  65        "       addq    %0,%3,%2\n"
  66        "       stq_c   %2,%1\n"
  67        "       beq     %2,2f\n"
  68        "       mb\n"
  69        ".subsection 2\n"
  70        "2:     br      1b\n"
  71        ".previous"
  72        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  73        :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
  74#endif
  75        if (unlikely(oldcount < 0))
  76                rwsem_down_read_failed(sem);
  77}
  78
  79/*
  80 * trylock for reading -- returns 1 if successful, 0 if contention
  81 */
  82static inline int __down_read_trylock(struct rw_semaphore *sem)
  83{
  84        long old, new, res;
  85
  86        res = sem->count;
  87        do {
  88                new = res + RWSEM_ACTIVE_READ_BIAS;
  89                if (new <= 0)
  90                        break;
  91                old = res;
  92                res = cmpxchg(&sem->count, old, new);
  93        } while (res != old);
  94        return res >= 0 ? 1 : 0;
  95}
  96
  97static inline void __down_write(struct rw_semaphore *sem)
  98{
  99        long oldcount;
 100#ifndef CONFIG_SMP
 101        oldcount = sem->count;
 102        sem->count += RWSEM_ACTIVE_WRITE_BIAS;
 103#else
 104        long temp;
 105        __asm__ __volatile__(
 106        "1:     ldq_l   %0,%1\n"
 107        "       addq    %0,%3,%2\n"
 108        "       stq_c   %2,%1\n"
 109        "       beq     %2,2f\n"
 110        "       mb\n"
 111        ".subsection 2\n"
 112        "2:     br      1b\n"
 113        ".previous"
 114        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
 115        :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
 116#endif
 117        if (unlikely(oldcount))
 118                rwsem_down_write_failed(sem);
 119}
 120
 121/*
 122 * trylock for writing -- returns 1 if successful, 0 if contention
 123 */
 124static inline int __down_write_trylock(struct rw_semaphore *sem)
 125{
 126        long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
 127                           RWSEM_ACTIVE_WRITE_BIAS);
 128        if (ret == RWSEM_UNLOCKED_VALUE)
 129                return 1;
 130        return 0;
 131}
 132
 133static inline void __up_read(struct rw_semaphore *sem)
 134{
 135        long oldcount;
 136#ifndef CONFIG_SMP
 137        oldcount = sem->count;
 138        sem->count -= RWSEM_ACTIVE_READ_BIAS;
 139#else
 140        long temp;
 141        __asm__ __volatile__(
 142        "       mb\n"
 143        "1:     ldq_l   %0,%1\n"
 144        "       subq    %0,%3,%2\n"
 145        "       stq_c   %2,%1\n"
 146        "       beq     %2,2f\n"
 147        ".subsection 2\n"
 148        "2:     br      1b\n"
 149        ".previous"
 150        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
 151        :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
 152#endif
 153        if (unlikely(oldcount < 0))
 154                if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
 155                        rwsem_wake(sem);
 156}
 157
 158static inline void __up_write(struct rw_semaphore *sem)
 159{
 160        long count;
 161#ifndef CONFIG_SMP
 162        sem->count -= RWSEM_ACTIVE_WRITE_BIAS;
 163        count = sem->count;
 164#else
 165        long temp;
 166        __asm__ __volatile__(
 167        "       mb\n"
 168        "1:     ldq_l   %0,%1\n"
 169        "       subq    %0,%3,%2\n"
 170        "       stq_c   %2,%1\n"
 171        "       beq     %2,2f\n"
 172        "       subq    %0,%3,%0\n"
 173        ".subsection 2\n"
 174        "2:     br      1b\n"
 175        ".previous"
 176        :"=&r" (count), "=m" (sem->count), "=&r" (temp)
 177        :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
 178#endif
 179        if (unlikely(count))
 180                if ((int)count == 0)
 181                        rwsem_wake(sem);
 182}
 183
 184/*
 185 * downgrade write lock to read lock
 186 */
 187static inline void __downgrade_write(struct rw_semaphore *sem)
 188{
 189        long oldcount;
 190#ifndef CONFIG_SMP
 191        oldcount = sem->count;
 192        sem->count -= RWSEM_WAITING_BIAS;
 193#else
 194        long temp;
 195        __asm__ __volatile__(
 196        "1:     ldq_l   %0,%1\n"
 197        "       addq    %0,%3,%2\n"
 198        "       stq_c   %2,%1\n"
 199        "       beq     %2,2f\n"
 200        "       mb\n"
 201        ".subsection 2\n"
 202        "2:     br      1b\n"
 203        ".previous"
 204        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
 205        :"Ir" (-RWSEM_WAITING_BIAS), "m" (sem->count) : "memory");
 206#endif
 207        if (unlikely(oldcount < 0))
 208                rwsem_downgrade_wake(sem);
 209}
 210
 211static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem)
 212{
 213#ifndef CONFIG_SMP
 214        sem->count += val;
 215#else
 216        long temp;
 217        __asm__ __volatile__(
 218        "1:     ldq_l   %0,%1\n"
 219        "       addq    %0,%2,%0\n"
 220        "       stq_c   %0,%1\n"
 221        "       beq     %0,2f\n"
 222        ".subsection 2\n"
 223        "2:     br      1b\n"
 224        ".previous"
 225        :"=&r" (temp), "=m" (sem->count)
 226        :"Ir" (val), "m" (sem->count));
 227#endif
 228}
 229
 230static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem)
 231{
 232#ifndef CONFIG_SMP
 233        sem->count += val;
 234        return sem->count;
 235#else
 236        long ret, temp;
 237        __asm__ __volatile__(
 238        "1:     ldq_l   %0,%1\n"
 239        "       addq    %0,%3,%2\n"
 240        "       addq    %0,%3,%0\n"
 241        "       stq_c   %2,%1\n"
 242        "       beq     %2,2f\n"
 243        ".subsection 2\n"
 244        "2:     br      1b\n"
 245        ".previous"
 246        :"=&r" (ret), "=m" (sem->count), "=&r" (temp)
 247        :"Ir" (val), "m" (sem->count));
 248
 249        return ret;
 250#endif
 251}
 252
 253static inline int rwsem_is_locked(struct rw_semaphore *sem)
 254{
 255        return (sem->count != 0);
 256}
 257
 258#endif /* __KERNEL__ */
 259#endif /* _ALPHA_RWSEM_H */
 260