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 32typedef 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 */ 60static inline void write_seqlock(seqlock_t *sl) 61{ 62 spin_lock(&sl->lock); 63 ++sl->sequence; 64 smp_wmb(); 65} 66 67static inline void write_sequnlock(seqlock_t *sl) 68{ 69 smp_wmb(); 70 sl->sequence++; 71 spin_unlock(&sl->lock); 72} 73 74static 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 */ 86static __always_inline unsigned read_seqbegin(const seqlock_t *sl) 87{ 88 unsigned ret; 89 90repeat: 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 */ 106static __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 121typedef 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. */ 129static inline unsigned read_seqcount_begin(const seqcount_t *s) 130{ 131 unsigned ret; 132 133repeat: 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 */ 146static 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 */ 158static inline void write_seqcount_begin(seqcount_t *s) 159{ 160 s->sequence++; 161 smp_wmb(); 162} 163 164static 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