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) 103 { 104 mtx_enter(&sl->lock); 105 sl->seq++; 106 membar_producer(); 107 } 108 #define write_seqlock_irqsave(_sl, _flags) do { \ 109 _flags = 0; \ 110 __write_seqlock_irqsave(_sl); \ 111 } while (0) 112 113 static inline void 114 write_sequnlock(seqlock_t *sl) 115 { 116 membar_producer(); 117 sl->seq++; 118 mtx_leave(&sl->lock); 119 } 120 121 static inline void 122 __write_sequnlock_irqrestore(seqlock_t *sl) 123 { 124 membar_producer(); 125 sl->seq++; 126 mtx_leave(&sl->lock); 127 } 128 #define write_sequnlock_irqrestore(_sl, _flags) do { \ 129 (void)(_flags); \ 130 __write_sequnlock_irqrestore(_sl); \ 131 } while (0) 132 133 static inline unsigned int 134 read_seqbegin(seqlock_t *sl) 135 { 136 return READ_ONCE(sl->seq); 137 } 138 139 static inline unsigned int 140 read_seqretry(seqlock_t *sl, unsigned int pos) 141 { 142 return sl->seq != pos; 143 } 144 145 #endif 146