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