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 void 26 seqcount_init(seqcount_t *s) 27 { 28 __seqcount_init(s, NULL, NULL); 29 } 30 31 static inline unsigned int 32 __read_seqcount_begin(const seqcount_t *s) 33 { 34 unsigned int r; 35 for (;;) { 36 r = s->sequence; 37 if ((r & 1) == 0) 38 break; 39 cpu_relax(); 40 } 41 return r; 42 } 43 44 static inline unsigned int 45 read_seqcount_begin(const seqcount_t *s) 46 { 47 unsigned int r = __read_seqcount_begin(s); 48 membar_consumer(); 49 return r; 50 } 51 52 static inline int 53 __read_seqcount_retry(const seqcount_t *s, unsigned start) 54 { 55 return (s->sequence != start); 56 } 57 58 static inline int 59 read_seqcount_retry(const seqcount_t *s, unsigned start) 60 { 61 membar_consumer(); 62 return __read_seqcount_retry(s, start); 63 } 64 65 static inline void 66 write_seqcount_begin(seqcount_t *s) 67 { 68 s->sequence++; 69 membar_producer(); 70 } 71 72 static inline void 73 write_seqcount_end(seqcount_t *s) 74 { 75 membar_producer(); 76 s->sequence++; 77 } 78 79 static inline unsigned int 80 raw_read_seqcount(const seqcount_t *s) 81 { 82 unsigned int r = s->sequence; 83 membar_consumer(); 84 return r; 85 } 86 87 typedef struct { 88 unsigned int seq; 89 struct mutex lock; 90 } seqlock_t; 91 92 static inline void 93 seqlock_init(seqlock_t *sl, int wantipl) 94 { 95 sl->seq = 0; 96 mtx_init(&sl->lock, wantipl); 97 } 98 99 static inline void 100 write_seqlock(seqlock_t *sl) 101 { 102 mtx_enter(&sl->lock); 103 sl->seq++; 104 membar_producer(); 105 } 106 107 static inline void 108 __write_seqlock_irqsave(seqlock_t *sl) 109 { 110 mtx_enter(&sl->lock); 111 sl->seq++; 112 membar_producer(); 113 } 114 #define write_seqlock_irqsave(_sl, _flags) do { \ 115 _flags = 0; \ 116 __write_seqlock_irqsave(_sl); \ 117 } while (0) 118 119 static inline void 120 write_sequnlock(seqlock_t *sl) 121 { 122 membar_producer(); 123 sl->seq++; 124 mtx_leave(&sl->lock); 125 } 126 127 static inline void 128 __write_sequnlock_irqrestore(seqlock_t *sl) 129 { 130 membar_producer(); 131 sl->seq++; 132 mtx_leave(&sl->lock); 133 } 134 #define write_sequnlock_irqrestore(_sl, _flags) do { \ 135 (void)(_flags); \ 136 __write_sequnlock_irqrestore(_sl); \ 137 } while (0) 138 139 static inline unsigned int 140 read_seqbegin(seqlock_t *sl) 141 { 142 return READ_ONCE(sl->seq); 143 } 144 145 static inline unsigned int 146 read_seqretry(seqlock_t *sl, unsigned int pos) 147 { 148 return sl->seq != pos; 149 } 150 151 typedef struct { 152 seqcount_t seq; 153 struct rwlock lock; 154 } seqcount_mutex_t; 155 156 #define seqcount_mutex_init(s, l) seqcount_init(&(s)->seq) 157 158 static inline unsigned int 159 seqprop_sequence(const seqcount_mutex_t *sm) 160 { 161 return READ_ONCE(sm->seq.sequence); 162 } 163 164 #endif 165