home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / include / linux / seqlock.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  4.6 KB  |  198 lines

  1. #ifndef __LINUX_SEQLOCK_H
  2. #define __LINUX_SEQLOCK_H
  3. /*
  4.  * Reader/writer consistent mechanism without starving writers. This type of
  5.  * lock for data where the reader wants a consistent set of information
  6.  * and is willing to retry if the information changes.  Readers never
  7.  * block but they may have to retry if a writer is in
  8.  * progress. Writers do not wait for readers. 
  9.  *
  10.  * This is not as cache friendly as brlock. Also, this will not work
  11.  * for data that contains pointers, because any writer could
  12.  * invalidate a pointer that a reader was following.
  13.  *
  14.  * Expected reader usage:
  15.  *     do {
  16.  *        seq = read_seqbegin(&foo);
  17.  *     ...
  18.  *      } while (read_seqretry(&foo, seq));
  19.  *
  20.  *
  21.  * On non-SMP the spin locks disappear but the writer still needs
  22.  * to increment the sequence variables because an interrupt routine could
  23.  * change the state of the data.
  24.  *
  25.  * Based on x86_64 vsyscall gettimeofday 
  26.  * by Keith Owens and Andrea Arcangeli
  27.  */
  28.  
  29. #include <linux/spinlock.h>
  30. #include <linux/preempt.h>
  31.  
  32. typedef struct {
  33.     unsigned sequence;
  34.     spinlock_t lock;
  35. } seqlock_t;
  36.  
  37. /*
  38.  * These macros triggered gcc-3.x compile-time problems.  We think these are
  39.  * OK now.  Be cautious.
  40.  */
  41. #define __SEQLOCK_UNLOCKED(lockname) \
  42.          { 0, __SPIN_LOCK_UNLOCKED(lockname) }
  43.  
  44. #define SEQLOCK_UNLOCKED \
  45.          __SEQLOCK_UNLOCKED(old_style_seqlock_init)
  46.  
  47. #define seqlock_init(x)                    \
  48.     do {                        \
  49.         (x)->sequence = 0;            \
  50.         spin_lock_init(&(x)->lock);        \
  51.     } while (0)
  52.  
  53. #define DEFINE_SEQLOCK(x) \
  54.         seqlock_t x = __SEQLOCK_UNLOCKED(x)
  55.  
  56. /* Lock out other writers and update the count.
  57.  * Acts like a normal spin_lock/unlock.
  58.  * Don't need preempt_disable() because that is in the spin_lock already.
  59.  */
  60. static inline void write_seqlock(seqlock_t *sl)
  61. {
  62.     spin_lock(&sl->lock);
  63.     ++sl->sequence;
  64.     smp_wmb();
  65. }
  66.  
  67. static inline void write_sequnlock(seqlock_t *sl)
  68. {
  69.     smp_wmb();
  70.     sl->sequence++;
  71.     spin_unlock(&sl->lock);
  72. }
  73.  
  74. static inline int write_tryseqlock(seqlock_t *sl)
  75. {
  76.     int ret = spin_trylock(&sl->lock);
  77.  
  78.     if (ret) {
  79.         ++sl->sequence;
  80.         smp_wmb();
  81.     }
  82.     return ret;
  83. }
  84.  
  85. /* Start of read calculation -- fetch last complete writer token */
  86. static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
  87. {
  88.     unsigned ret;
  89.  
  90. repeat:
  91.     ret = sl->sequence;
  92.     smp_rmb();
  93.     if (unlikely(ret & 1)) {
  94.         cpu_relax();
  95.         goto repeat;
  96.     }
  97.  
  98.     return ret;
  99. }
  100.  
  101. /*
  102.  * Test if reader processed invalid data.
  103.  *
  104.  * If sequence value changed then writer changed data while in section.
  105.  */
  106. static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)
  107. {
  108.     smp_rmb();
  109.  
  110.     return (sl->sequence != start);
  111. }
  112.  
  113.  
  114. /*
  115.  * Version using sequence counter only.
  116.  * This can be used when code has its own mutex protecting the
  117.  * updating starting before the write_seqcountbeqin() and ending
  118.  * after the write_seqcount_end().
  119.  */
  120.  
  121. typedef struct seqcount {
  122.     unsigned sequence;
  123. } seqcount_t;
  124.  
  125. #define SEQCNT_ZERO { 0 }
  126. #define seqcount_init(x)    do { *(x) = (seqcount_t) SEQCNT_ZERO; } while (0)
  127.  
  128. /* Start of read using pointer to a sequence counter only.  */
  129. static inline unsigned read_seqcount_begin(const seqcount_t *s)
  130. {
  131.     unsigned ret;
  132.  
  133. repeat:
  134.     ret = s->sequence;
  135.     smp_rmb();
  136.     if (unlikely(ret & 1)) {
  137.         cpu_relax();
  138.         goto repeat;
  139.     }
  140.     return ret;
  141. }
  142.  
  143. /*
  144.  * Test if reader processed invalid data because sequence number has changed.
  145.  */
  146. static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
  147. {
  148.     smp_rmb();
  149.  
  150.     return s->sequence != start;
  151. }
  152.  
  153.  
  154. /*
  155.  * Sequence counter only version assumes that callers are using their
  156.  * own mutexing.
  157.  */
  158. static inline void write_seqcount_begin(seqcount_t *s)
  159. {
  160.     s->sequence++;
  161.     smp_wmb();
  162. }
  163.  
  164. static inline void write_seqcount_end(seqcount_t *s)
  165. {
  166.     smp_wmb();
  167.     s->sequence++;
  168. }
  169.  
  170. /*
  171.  * Possible sw/hw IRQ protected versions of the interfaces.
  172.  */
  173. #define write_seqlock_irqsave(lock, flags)                \
  174.     do { local_irq_save(flags); write_seqlock(lock); } while (0)
  175. #define write_seqlock_irq(lock)                        \
  176.     do { local_irq_disable();   write_seqlock(lock); } while (0)
  177. #define write_seqlock_bh(lock)                        \
  178.         do { local_bh_disable();    write_seqlock(lock); } while (0)
  179.  
  180. #define write_sequnlock_irqrestore(lock, flags)                \
  181.     do { write_sequnlock(lock); local_irq_restore(flags); } while(0)
  182. #define write_sequnlock_irq(lock)                    \
  183.     do { write_sequnlock(lock); local_irq_enable(); } while(0)
  184. #define write_sequnlock_bh(lock)                    \
  185.     do { write_sequnlock(lock); local_bh_enable(); } while(0)
  186.  
  187. #define read_seqbegin_irqsave(lock, flags)                \
  188.     ({ local_irq_save(flags);   read_seqbegin(lock); })
  189.  
  190. #define read_seqretry_irqrestore(lock, iv, flags)            \
  191.     ({                                \
  192.         int ret = read_seqretry(lock, iv);            \
  193.         local_irq_restore(flags);                \
  194.         ret;                            \
  195.     })
  196.  
  197. #endif /* __LINUX_SEQLOCK_H */
  198.