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