home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6 / include / asm-generic / bitops / atomic.h < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-11  |  5.6 KB  |  192 lines

  1. #ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_
  2. #define _ASM_GENERIC_BITOPS_ATOMIC_H_
  3.  
  4. #include <asm/types.h>
  5.  
  6. #define BITOP_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
  7. #define BITOP_WORD(nr)        ((nr) / BITS_PER_LONG)
  8.  
  9. #ifdef CONFIG_SMP
  10. #include <asm/spinlock.h>
  11. #include <asm/cache.h>        /* we use L1_CACHE_BYTES */
  12.  
  13. /* Use an array of spinlocks for our atomic_ts.
  14.  * Hash function to index into a different SPINLOCK.
  15.  * Since "a" is usually an address, use one spinlock per cacheline.
  16.  */
  17. #  define ATOMIC_HASH_SIZE 4
  18. #  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
  19.  
  20. extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
  21.  
  22. /* Can't use raw_spin_lock_irq because of #include problems, so
  23.  * this is the substitute */
  24. #define _atomic_spin_lock_irqsave(l,f) do {    \
  25.     raw_spinlock_t *s = ATOMIC_HASH(l);    \
  26.     local_irq_save(f);            \
  27.     __raw_spin_lock(s);            \
  28. } while(0)
  29.  
  30. #define _atomic_spin_unlock_irqrestore(l,f) do {    \
  31.     raw_spinlock_t *s = ATOMIC_HASH(l);        \
  32.     __raw_spin_unlock(s);                \
  33.     local_irq_restore(f);                \
  34. } while(0)
  35.  
  36.  
  37. #else
  38. #  define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0)
  39. #  define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
  40. #endif
  41.  
  42. /*
  43.  * NMI events can occur at any time, including when interrupts have been
  44.  * disabled by *_irqsave().  So you can get NMI events occurring while a
  45.  * *_bit function is holding a spin lock.  If the NMI handler also wants
  46.  * to do bit manipulation (and they do) then you can get a deadlock
  47.  * between the original caller of *_bit() and the NMI handler.
  48.  *
  49.  * by Keith Owens
  50.  */
  51.  
  52. /**
  53.  * set_bit - Atomically set a bit in memory
  54.  * @nr: the bit to set
  55.  * @addr: the address to start counting from
  56.  *
  57.  * This function is atomic and may not be reordered.  See __set_bit()
  58.  * if you do not require the atomic guarantees.
  59.  *
  60.  * Note: there are no guarantees that this function will not be reordered
  61.  * on non x86 architectures, so if you are writting portable code,
  62.  * make sure not to rely on its reordering guarantees.
  63.  *
  64.  * Note that @nr may be almost arbitrarily large; this function is not
  65.  * restricted to acting on a single-word quantity.
  66.  */
  67. static inline void set_bit(int nr, volatile unsigned long *addr)
  68. {
  69.     unsigned long mask = BITOP_MASK(nr);
  70.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  71.     unsigned long flags;
  72.  
  73.     _atomic_spin_lock_irqsave(p, flags);
  74.     *p  |= mask;
  75.     _atomic_spin_unlock_irqrestore(p, flags);
  76. }
  77.  
  78. /**
  79.  * clear_bit - Clears a bit in memory
  80.  * @nr: Bit to clear
  81.  * @addr: Address to start counting from
  82.  *
  83.  * clear_bit() is atomic and may not be reordered.  However, it does
  84.  * not contain a memory barrier, so if it is used for locking purposes,
  85.  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  86.  * in order to ensure changes are visible on other processors.
  87.  */
  88. static inline void clear_bit(int nr, volatile unsigned long *addr)
  89. {
  90.     unsigned long mask = BITOP_MASK(nr);
  91.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  92.     unsigned long flags;
  93.  
  94.     _atomic_spin_lock_irqsave(p, flags);
  95.     *p &= ~mask;
  96.     _atomic_spin_unlock_irqrestore(p, flags);
  97. }
  98.  
  99. /**
  100.  * change_bit - Toggle a bit in memory
  101.  * @nr: Bit to change
  102.  * @addr: Address to start counting from
  103.  *
  104.  * change_bit() is atomic and may not be reordered. It may be
  105.  * reordered on other architectures than x86.
  106.  * Note that @nr may be almost arbitrarily large; this function is not
  107.  * restricted to acting on a single-word quantity.
  108.  */
  109. static inline void change_bit(int nr, volatile unsigned long *addr)
  110. {
  111.     unsigned long mask = BITOP_MASK(nr);
  112.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  113.     unsigned long flags;
  114.  
  115.     _atomic_spin_lock_irqsave(p, flags);
  116.     *p ^= mask;
  117.     _atomic_spin_unlock_irqrestore(p, flags);
  118. }
  119.  
  120. /**
  121.  * test_and_set_bit - Set a bit and return its old value
  122.  * @nr: Bit to set
  123.  * @addr: Address to count from
  124.  *
  125.  * This operation is atomic and cannot be reordered.
  126.  * It may be reordered on other architectures than x86.
  127.  * It also implies a memory barrier.
  128.  */
  129. static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
  130. {
  131.     unsigned long mask = BITOP_MASK(nr);
  132.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  133.     unsigned long old;
  134.     unsigned long flags;
  135.  
  136.     _atomic_spin_lock_irqsave(p, flags);
  137.     old = *p;
  138.     *p = old | mask;
  139.     _atomic_spin_unlock_irqrestore(p, flags);
  140.  
  141.     return (old & mask) != 0;
  142. }
  143.  
  144. /**
  145.  * test_and_clear_bit - Clear a bit and return its old value
  146.  * @nr: Bit to clear
  147.  * @addr: Address to count from
  148.  *
  149.  * This operation is atomic and cannot be reordered.
  150.  * It can be reorderdered on other architectures other than x86.
  151.  * It also implies a memory barrier.
  152.  */
  153. static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
  154. {
  155.     unsigned long mask = BITOP_MASK(nr);
  156.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  157.     unsigned long old;
  158.     unsigned long flags;
  159.  
  160.     _atomic_spin_lock_irqsave(p, flags);
  161.     old = *p;
  162.     *p = old & ~mask;
  163.     _atomic_spin_unlock_irqrestore(p, flags);
  164.  
  165.     return (old & mask) != 0;
  166. }
  167.  
  168. /**
  169.  * test_and_change_bit - Change a bit and return its old value
  170.  * @nr: Bit to change
  171.  * @addr: Address to count from
  172.  *
  173.  * This operation is atomic and cannot be reordered.
  174.  * It also implies a memory barrier.
  175.  */
  176. static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
  177. {
  178.     unsigned long mask = BITOP_MASK(nr);
  179.     unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
  180.     unsigned long old;
  181.     unsigned long flags;
  182.  
  183.     _atomic_spin_lock_irqsave(p, flags);
  184.     old = *p;
  185.     *p = old ^ mask;
  186.     _atomic_spin_unlock_irqrestore(p, flags);
  187.  
  188.     return (old & mask) != 0;
  189. }
  190.  
  191. #endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */
  192.