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
__seqcount_init(seqcount_t * s,const char * name,struct lock_class_key * key)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
seqcount_init(seqcount_t * s)26 seqcount_init(seqcount_t *s)
27 {
28 __seqcount_init(s, NULL, NULL);
29 }
30
31 static inline unsigned int
__read_seqcount_begin(const seqcount_t * s)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
read_seqcount_begin(const seqcount_t * s)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
__read_seqcount_retry(const seqcount_t * s,unsigned start)53 __read_seqcount_retry(const seqcount_t *s, unsigned start)
54 {
55 return (s->sequence != start);
56 }
57
58 static inline int
read_seqcount_retry(const seqcount_t * s,unsigned start)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
write_seqcount_begin(seqcount_t * s)66 write_seqcount_begin(seqcount_t *s)
67 {
68 s->sequence++;
69 membar_producer();
70 }
71
72 static inline void
write_seqcount_end(seqcount_t * s)73 write_seqcount_end(seqcount_t *s)
74 {
75 membar_producer();
76 s->sequence++;
77 }
78
79 static inline unsigned int
raw_read_seqcount(const seqcount_t * s)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
seqlock_init(seqlock_t * sl,int wantipl)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
write_seqlock(seqlock_t * sl)100 write_seqlock(seqlock_t *sl)
101 {
102 mtx_enter(&sl->lock);
103 sl->seq++;
104 membar_producer();
105 }
106
107 static inline void
__write_seqlock_irqsave(seqlock_t * sl)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
write_sequnlock(seqlock_t * sl)120 write_sequnlock(seqlock_t *sl)
121 {
122 membar_producer();
123 sl->seq++;
124 mtx_leave(&sl->lock);
125 }
126
127 static inline void
__write_sequnlock_irqrestore(seqlock_t * sl)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
read_seqbegin(seqlock_t * sl)140 read_seqbegin(seqlock_t *sl)
141 {
142 return READ_ONCE(sl->seq);
143 }
144
145 static inline unsigned int
read_seqretry(seqlock_t * sl,unsigned int pos)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
seqprop_sequence(const seqcount_mutex_t * sm)159 seqprop_sequence(const seqcount_mutex_t *sm)
160 {
161 return READ_ONCE(sm->seq.sequence);
162 }
163
164 #endif
165