1 /* Public domain. */ 2 3 #ifndef _LINUX_SEQLOCK_H 4 #define _LINUX_SEQLOCK_H 5 6 #include <sys/types.h> 7 #include <sys/mutex.h> 8 #include <sys/atomic.h> 9 #include <linux/lockdep.h> 10 #include <linux/processor.h> 11 #include <linux/preempt.h> 12 #include <linux/compiler.h> 13 14 typedef struct { 15 unsigned int sequence; 16 } seqcount_t; 17 18 static inline void 19 __seqcount_init(seqcount_t *s, const char *name, 20 struct lock_class_key *key) 21 { 22 s->sequence = 0; 23 } 24 25 static inline unsigned int 26 __read_seqcount_begin(const seqcount_t *s) 27 { 28 unsigned int r; 29 for (;;) { 30 r = s->sequence; 31 if ((r & 1) == 0) 32 break; 33 cpu_relax(); 34 } 35 return r; 36 } 37 38 static inline unsigned int 39 read_seqcount_begin(const seqcount_t *s) 40 { 41 unsigned int r = __read_seqcount_begin(s); 42 membar_consumer(); 43 return r; 44 } 45 46 static inline int 47 __read_seqcount_retry(const seqcount_t *s, unsigned start) 48 { 49 return (s->sequence != start); 50 } 51 52 static inline int 53 read_seqcount_retry(const seqcount_t *s, unsigned start) 54 { 55 membar_consumer(); 56 return __read_seqcount_retry(s, start); 57 } 58 59 static inline void 60 write_seqcount_begin(seqcount_t *s) 61 { 62 s->sequence++; 63 membar_producer(); 64 } 65 66 static inline void 67 write_seqcount_end(seqcount_t *s) 68 { 69 membar_producer(); 70 s->sequence++; 71 } 72 73 static inline unsigned int 74 raw_read_seqcount(const seqcount_t *s) 75 { 76 unsigned int r = s->sequence; 77 membar_consumer(); 78 return r; 79 } 80 81 typedef struct { 82 unsigned int seq; 83 struct mutex lock; 84 } seqlock_t; 85 86 static inline void 87 seqlock_init(seqlock_t *sl, int wantipl) 88 { 89 sl->seq = 0; 90 mtx_init(&sl->lock, wantipl); 91 } 92 93 static inline void 94 write_seqlock(seqlock_t *sl) 95 { 96 mtx_enter(&sl->lock); 97 sl->seq++; 98 membar_producer(); 99 } 100 101 static inline void 102 write_seqlock_irqsave(seqlock_t *sl, __unused long flags) 103 { 104 mtx_enter(&sl->lock); 105 sl->seq++; 106 membar_producer(); 107 } 108 109 static inline void 110 write_sequnlock(seqlock_t *sl) 111 { 112 membar_producer(); 113 sl->seq++; 114 mtx_leave(&sl->lock); 115 } 116 117 static inline void 118 write_sequnlock_irqrestore(seqlock_t *sl, __unused long flags) 119 { 120 membar_producer(); 121 sl->seq++; 122 mtx_leave(&sl->lock); 123 } 124 125 static inline unsigned int 126 read_seqbegin(seqlock_t *sl) 127 { 128 return READ_ONCE(sl->seq); 129 } 130 131 static inline unsigned int 132 read_seqretry(seqlock_t *sl, unsigned int pos) 133 { 134 return sl->seq != pos; 135 } 136 137 #endif 138