This source file includes following definitions.
- rw_enter_read
- rw_enter_write
- rw_exit_read
- rw_exit_write
- rw_cas
- rw_enter_diag
- rw_init
- rw_enter
- rw_exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/proc.h>
31 #include <sys/rwlock.h>
32 #include <sys/limits.h>
33
34 #include <machine/lock.h>
35
36
37 #define RW_PROC(p) (((long)p) & ~RWLOCK_MASK)
38
39
40
41
42
43
44
45
46
47
48
49
50
51 static const struct rwlock_op {
52 unsigned long inc;
53 unsigned long check;
54 unsigned long wait_set;
55 long proc_mult;
56 int wait_prio;
57 } rw_ops[] = {
58 {
59 RWLOCK_WRLOCK,
60 ULONG_MAX,
61 RWLOCK_WAIT | RWLOCK_WRWANT,
62 1,
63 PLOCK - 4
64 },
65 {
66 RWLOCK_READ_INCR,
67 RWLOCK_WRLOCK,
68 RWLOCK_WAIT,
69 0,
70 PLOCK
71 },
72 {
73 RWLOCK_READ_INCR - RWLOCK_WRLOCK,
74 0,
75 0,
76 -1,
77 PLOCK
78 },
79 };
80
81 #ifndef __HAVE_MD_RWLOCK
82
83
84
85 void
86 rw_enter_read(struct rwlock *rwl)
87 {
88 unsigned long owner = rwl->rwl_owner;
89
90 if (__predict_false((owner & RWLOCK_WRLOCK) ||
91 rw_cas(&rwl->rwl_owner, owner, owner + RWLOCK_READ_INCR)))
92 rw_enter(rwl, RW_READ);
93 }
94
95 void
96 rw_enter_write(struct rwlock *rwl)
97 {
98 struct proc *p = curproc;
99
100 if (__predict_false(rw_cas(&rwl->rwl_owner, 0,
101 RW_PROC(p) | RWLOCK_WRLOCK)))
102 rw_enter(rwl, RW_WRITE);
103 }
104
105 void
106 rw_exit_read(struct rwlock *rwl)
107 {
108 unsigned long owner = rwl->rwl_owner;
109
110 if (__predict_false((owner & RWLOCK_WAIT) ||
111 rw_cas(&rwl->rwl_owner, owner, owner - RWLOCK_READ_INCR)))
112 rw_exit(rwl);
113 }
114
115 void
116 rw_exit_write(struct rwlock *rwl)
117 {
118 unsigned long owner = rwl->rwl_owner;
119
120 if (__predict_false((owner & RWLOCK_WAIT) ||
121 rw_cas(&rwl->rwl_owner, owner, 0)))
122 rw_exit(rwl);
123 }
124
125 #ifndef rw_cas
126 int
127 rw_cas(volatile unsigned long *p, unsigned long o, unsigned long n)
128 {
129 if (*p != o)
130 return (1);
131 *p = n;
132
133 return (0);
134 }
135 #endif
136
137 #endif
138
139 #ifdef DIAGNOSTIC
140
141
142
143
144 static void
145 rw_enter_diag(struct rwlock *rwl, int flags)
146 {
147 switch (flags & RW_OPMASK) {
148 case RW_WRITE:
149 case RW_READ:
150 if (RW_PROC(curproc) == RW_PROC(rwl->rwl_owner))
151 panic("rw_enter: %s locking against myself",
152 rwl->rwl_name);
153 break;
154 case RW_DOWNGRADE:
155
156
157
158 if ((rwl->rwl_owner & RWLOCK_WRLOCK) == 0)
159 panic("rw_enter: %s downgrade of non-write lock",
160 rwl->rwl_name);
161 if (RW_PROC(curproc) != RW_PROC(rwl->rwl_owner))
162 panic("rw_enter: %s downgrade, not holder",
163 rwl->rwl_name);
164 break;
165
166 default:
167 panic("rw_enter: unknown op 0x%x", flags);
168 }
169 }
170
171 #else
172 #define rw_enter_diag(r, f)
173 #endif
174
175 void
176 rw_init(struct rwlock *rwl, const char *name)
177 {
178 rwl->rwl_owner = 0;
179 rwl->rwl_name = name;
180 }
181
182 int
183 rw_enter(struct rwlock *rwl, int flags)
184 {
185 const struct rwlock_op *op;
186 struct sleep_state sls;
187 unsigned long inc, o;
188 int error;
189
190 op = &rw_ops[flags & RW_OPMASK];
191
192 inc = op->inc + RW_PROC(curproc) * op->proc_mult;
193 retry:
194 while (__predict_false(((o = rwl->rwl_owner) & op->check) != 0)) {
195 unsigned long set = o | op->wait_set;
196 int do_sleep;
197
198 rw_enter_diag(rwl, flags);
199
200 if (flags & RW_NOSLEEP)
201 return (EBUSY);
202
203 sleep_setup(&sls, rwl, op->wait_prio, rwl->rwl_name);
204 if (flags & RW_INTR)
205 sleep_setup_signal(&sls, op->wait_prio | PCATCH);
206
207 do_sleep = !rw_cas(&rwl->rwl_owner, o, set);
208
209 sleep_finish(&sls, do_sleep);
210 if ((flags & RW_INTR) &&
211 (error = sleep_finish_signal(&sls)) != 0)
212 return (error);
213 if (flags & RW_SLEEPFAIL)
214 return (EAGAIN);
215 }
216
217 if (__predict_false(rw_cas(&rwl->rwl_owner, o, o + inc)))
218 goto retry;
219
220
221
222
223
224
225 if (__predict_false((o & (RWLOCK_WRLOCK|RWLOCK_WAIT)) ==
226 (RWLOCK_WRLOCK|RWLOCK_WAIT)))
227 wakeup(rwl);
228
229 return (0);
230 }
231
232 void
233 rw_exit(struct rwlock *rwl)
234 {
235 unsigned long owner = rwl->rwl_owner;
236 int wrlock = owner & RWLOCK_WRLOCK;
237 unsigned long set;
238
239 do {
240 owner = rwl->rwl_owner;
241 if (wrlock)
242 set = 0;
243 else
244 set = (owner - RWLOCK_READ_INCR) &
245 ~(RWLOCK_WAIT|RWLOCK_WRWANT);
246 } while (rw_cas(&rwl->rwl_owner, owner, set));
247
248 if (owner & RWLOCK_WAIT)
249 wakeup(rwl);
250 }