atomic.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. #ifndef _ASM_PARISC_ATOMIC_H_
  2. #define _ASM_PARISC_ATOMIC_H_
  3. #include <linux/config.h>
  4. #include <asm/system.h>
  5. /* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>.  */
  6. /*
  7.  * Atomic operations that C can't guarantee us.  Useful for
  8.  * resource counting etc..
  9.  *
  10.  * And probably incredibly slow on parisc.  OTOH, we don't
  11.  * have to write any serious assembly.   prumpf
  12.  */
  13. #ifdef CONFIG_SMP
  14. /* Use an array of spinlocks for our atomic_ts.
  15. ** Hash function to index into a different SPINLOCK.
  16. ** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes.
  17. */
  18. #  define ATOMIC_HASH_SIZE 4
  19. #  define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)])
  20. extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
  21. /* copied from <asm/spinlock.h> and modified */
  22. #  define SPIN_LOCK(x) 
  23. do { while(__ldcw(&(x)->lock) == 0); } while(0)
  24. #  define SPIN_UNLOCK(x) 
  25. do { (x)->lock = 1; } while(0)
  26. #else
  27. #  define ATOMIC_HASH_SIZE 1
  28. #  define ATOMIC_HASH(a) (0)
  29. /* copied from <linux/spinlock.h> and modified */
  30. #  define SPIN_LOCK(x) (void)(x)
  31. #  define SPIN_UNLOCK(x) do { } while(0)
  32. #endif
  33. /* copied from <linux/spinlock.h> and modified */
  34. #define SPIN_LOCK_IRQSAVE(lock, flags) do { local_irq_save(flags);       SPIN_LOCK(lock); } while (0)
  35. #define SPIN_UNLOCK_IRQRESTORE(lock, flags) do { SPIN_UNLOCK(lock);  local_irq_restore(flags); } while (0)
  36. /* Note that we need not lock read accesses - aligned word writes/reads
  37.  * are atomic, so a reader never sees unconsistent values.
  38.  *
  39.  * Cache-line alignment would conflict with, for example, linux/module.h
  40.  */
  41. typedef struct {
  42. volatile int counter;
  43. } atomic_t;
  44. /*
  45. ** xchg/cmpxchg moved from asm/system.h - ggg
  46. */
  47. #if 1
  48. /* This should get optimized out since it's never called.
  49. ** Or get a link error if xchg is used "wrong".
  50. */
  51. extern void __xchg_called_with_bad_pointer(void);
  52. #else
  53. static inline void __xchg_called_with_bad_pointer(void)
  54. {
  55. extern void panic(const char * fmt, ...);
  56. panic("xchg called with bad pointer");
  57. }
  58. #endif
  59. /* __xchg32/64 defined in arch/parisc/lib/bitops.c */
  60. extern unsigned long __xchg8(char, char *);
  61. extern unsigned long __xchg32(int, int *);
  62. #ifdef __LP64__
  63. extern unsigned long __xchg64(unsigned long, unsigned long *);
  64. #endif
  65. /* optimizer better get rid of switch since size is a constant */
  66. static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
  67.                                        int size)
  68. {
  69. switch(size) {
  70. #ifdef __LP64__
  71. case 8: return __xchg64(x,(unsigned long *) ptr);
  72. #endif
  73. case 4: return __xchg32((int) x, (int *) ptr);
  74. case 1: return __xchg8((char) x, (char *) ptr);
  75. }
  76. __xchg_called_with_bad_pointer();
  77. return x;
  78. }
  79. /*
  80. ** REVISIT - Abandoned use of LDCW in xchg() for now:
  81. ** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
  82. ** o and while we are at it, could __LP64__ code use LDCD too?
  83. **
  84. ** if (__builtin_constant_p(x) && (x == NULL))
  85. ** if (((unsigned long)p & 0xf) == 0)
  86. ** return __ldcw(p);
  87. */
  88. #define xchg(ptr,x) 
  89. ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
  90. #define __HAVE_ARCH_CMPXCHG 1
  91. /* bug catcher for when unsupported size is used - won't link */
  92. extern void __cmpxchg_called_with_bad_pointer(void);
  93. /* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */
  94. extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old, unsigned int new_);
  95. extern unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new_);
  96. /* don't worry...optimizer will get rid of most of this */
  97. static __inline__ unsigned long
  98. __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
  99. {
  100. switch(size) {
  101. #ifdef __LP64__
  102. case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
  103. #endif
  104. case 4: return __cmpxchg_u32((unsigned int *)ptr, (unsigned int) old, (unsigned int) new_);
  105. }
  106. __cmpxchg_called_with_bad_pointer();
  107. return old;
  108. }
  109. #define cmpxchg(ptr,o,n)  
  110.   ({  
  111.      __typeof__(*(ptr)) _o_ = (o);  
  112.      __typeof__(*(ptr)) _n_ = (n);  
  113.      (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,  
  114.     (unsigned long)_n_, sizeof(*(ptr))); 
  115.   })
  116. /* It's possible to reduce all atomic operations to either
  117.  * __atomic_add_return, __atomic_set and __atomic_ret (the latter
  118.  * is there only for consistency). */
  119. static __inline__ int __atomic_add_return(int i, atomic_t *v)
  120. {
  121. int ret;
  122. unsigned long flags;
  123. SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
  124. ret = (v->counter += i);
  125. SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
  126. return ret;
  127. }
  128. static __inline__ void __atomic_set(atomic_t *v, int i) 
  129. {
  130. unsigned long flags;
  131. SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
  132. v->counter = i;
  133. SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
  134. }
  135. static __inline__ int __atomic_read(atomic_t *v)
  136. {
  137. return v->counter;
  138. }
  139. /* exported interface */
  140. #define atomic_add(i,v) ((void)(__atomic_add_return( (i),(v))))
  141. #define atomic_sub(i,v) ((void)(__atomic_add_return(-(i),(v))))
  142. #define atomic_inc(v) ((void)(__atomic_add_return(   1,(v))))
  143. #define atomic_dec(v) ((void)(__atomic_add_return(  -1,(v))))
  144. #define atomic_add_return(i,v) (__atomic_add_return( (i),(v)))
  145. #define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v)))
  146. #define atomic_inc_return(v) (__atomic_add_return(   1,(v)))
  147. #define atomic_dec_return(v) (__atomic_add_return(  -1,(v)))
  148. #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
  149. #define atomic_set(v,i) (__atomic_set((v),i))
  150. #define atomic_read(v) (__atomic_read(v))
  151. #define ATOMIC_INIT(i) { (i) }
  152. #define smp_mb__before_atomic_dec() smp_mb()
  153. #define smp_mb__after_atomic_dec() smp_mb()
  154. #define smp_mb__before_atomic_inc() smp_mb()
  155. #define smp_mb__after_atomic_inc() smp_mb()
  156. #endif