#ifndef __LINUX_SEQLOCK_H #define __LINUX_SEQLOCK_H #include #include #include typedef struct { unsigned sequence; spinlock_t lock; } seqlock_t; #define __SEQLOCK_UNLOCKED(lockname) \ { 0, __SPIN_LOCK_UNLOCKED(lockname) } #define seqlock_init(x) \ do { \ (x)->sequence = 0; \ spin_lock_init(&(x)->lock); \ } while (0) #define DEFINE_SEQLOCK(x) \ seqlock_t x = __SEQLOCK_UNLOCKED(x) static inline void write_seqlock(seqlock_t *sl) { spin_lock(&sl->lock); ++sl->sequence; smp_wmb(); } static inline void write_sequnlock(seqlock_t *sl) { smp_wmb(); sl->sequence++; spin_unlock(&sl->lock); } static inline int write_tryseqlock(seqlock_t *sl) { int ret = spin_trylock(&sl->lock); if (ret) { ++sl->sequence; smp_wmb(); } return ret; } static __always_inline unsigned read_seqbegin(const seqlock_t *sl) { unsigned ret; repeat: ret = ACCESS_ONCE(sl->sequence); if (unlikely(ret & 1)) { cpu_relax(); goto repeat; } smp_rmb(); return ret; } static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start) { smp_rmb(); return unlikely(sl->sequence != start); } typedef struct seqcount { unsigned sequence; } seqcount_t; #define SEQCNT_ZERO { 0 } #define seqcount_init(x) do { *(x) = (seqcount_t) SEQCNT_ZERO; } while (0) static inline unsigned __read_seqcount_begin(const seqcount_t *s) { unsigned ret; repeat: ret = ACCESS_ONCE(s->sequence); if (unlikely(ret & 1)) { cpu_relax(); goto repeat; } return ret; } static inline unsigned read_seqcount_begin(const seqcount_t *s) { unsigned ret = __read_seqcount_begin(s); smp_rmb(); return ret; } static inline unsigned raw_seqcount_begin(const seqcount_t *s) { unsigned ret = ACCESS_ONCE(s->sequence); smp_rmb(); return ret & ~1; } static inline int __read_seqcount_retry(const seqcount_t *s, unsigned start) { return unlikely(s->sequence != start); } static inline int read_seqcount_retry(const seqcount_t *s, unsigned start) { smp_rmb(); return __read_seqcount_retry(s, start); } static inline void write_seqcount_begin(seqcount_t *s) { s->sequence++; smp_wmb(); } static inline void write_seqcount_end(seqcount_t *s) { smp_wmb(); s->sequence++; } static inline void write_seqcount_barrier(seqcount_t *s) { smp_wmb(); s->sequence+=2; } #define write_seqlock_irqsave(lock, flags) \ do { local_irq_save(flags); write_seqlock(lock); } while (0) #define write_seqlock_irq(lock) \ do { local_irq_disable(); write_seqlock(lock); } while (0) #define write_seqlock_bh(lock) \ do { local_bh_disable(); write_seqlock(lock); } while (0) #define write_sequnlock_irqrestore(lock, flags) \ do { write_sequnlock(lock); local_irq_restore(flags); } while(0) #define write_sequnlock_irq(lock) \ do { write_sequnlock(lock); local_irq_enable(); } while(0) #define write_sequnlock_bh(lock) \ do { write_sequnlock(lock); local_bh_enable(); } while(0) #define read_seqbegin_irqsave(lock, flags) \ ({ local_irq_save(flags); read_seqbegin(lock); }) #define read_seqretry_irqrestore(lock, iv, flags) \ ({ \ int ret = read_seqretry(lock, iv); \ local_irq_restore(flags); \ ret; \ }) #endif