1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include <ptrace.h>
8
9 struct {
10 ulong rlock;
11 ulong rlockq;
12 ulong wlock;
13 ulong wlockq;
14 ulong qlock;
15 ulong qlockq;
16 } rwstats;
17
18 void
qlock(QLock * q)19 qlock(QLock *q)
20 {
21 Proc *p;
22 void (*pt)(Proc*, int, vlong, vlong);
23
24 if(m->ilockdepth != 0)
25 print("qlock: %#p: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
26 if(up != nil && up->nlocks)
27 print("qlock: %#p: nlocks %d\n", getcallerpc(&q), up->nlocks);
28
29 lock(&q->use);
30 rwstats.qlock++;
31 if(!q->locked) {
32 q->locked = 1;
33 q->qpc = getcallerpc(&q);
34 unlock(&q->use);
35 return;
36 }
37 if(up == nil)
38 panic("qlock");
39 rwstats.qlockq++;
40 p = q->tail;
41 if(p == 0)
42 q->head = up;
43 else
44 p->qnext = up;
45 q->tail = up;
46 up->qnext = 0;
47 up->state = Queueing;
48 up->qpc = getcallerpc(&q);
49 if(up->trace && (pt = proctrace) != nil)
50 pt(up, SSleep, 0, Queueing | (up->qpc<<8));
51 unlock(&q->use);
52 sched();
53 q->qpc = getcallerpc(&q);
54 }
55
56 int
canqlock(QLock * q)57 canqlock(QLock *q)
58 {
59 if(!canlock(&q->use))
60 return 0;
61 if(q->locked){
62 unlock(&q->use);
63 return 0;
64 }
65 q->locked = 1;
66 q->qpc = getcallerpc(&q);
67 unlock(&q->use);
68
69 return 1;
70 }
71
72 void
qunlock(QLock * q)73 qunlock(QLock *q)
74 {
75 Proc *p;
76
77 lock(&q->use);
78 if (q->locked == 0)
79 print("qunlock called with qlock not held, from %#p\n",
80 getcallerpc(&q));
81 p = q->head;
82 if(p){
83 q->head = p->qnext;
84 if(q->head == 0)
85 q->tail = 0;
86 unlock(&q->use);
87 ready(p);
88 return;
89 }
90 q->locked = 0;
91 q->qpc = 0;
92 unlock(&q->use);
93 }
94
95 void
rlock(RWlock * q)96 rlock(RWlock *q)
97 {
98 Proc *p;
99 void (*pt)(Proc*, int, vlong, vlong);
100 uintptr pc;
101
102 lock(&q->use);
103 rwstats.rlock++;
104 if(q->writer == 0 && q->head == nil){
105 /* no writer, go for it */
106 q->readers++;
107 unlock(&q->use);
108 return;
109 }
110
111 rwstats.rlockq++;
112 p = q->tail;
113 if(up == nil)
114 panic("rlock");
115 if(p == 0)
116 q->head = up;
117 else
118 p->qnext = up;
119 q->tail = up;
120 up->qnext = 0;
121 up->state = QueueingR;
122 if(up->trace && (pt = proctrace) != nil){
123 pc = getcallerpc(&q);
124 pt(up, SSleep, 0, QueueingR | (pc<<8));
125 }
126 unlock(&q->use);
127 sched();
128 }
129
130 void
runlock(RWlock * q)131 runlock(RWlock *q)
132 {
133 Proc *p;
134
135 lock(&q->use);
136 p = q->head;
137 if(--(q->readers) > 0 || p == nil){
138 unlock(&q->use);
139 return;
140 }
141
142 /* start waiting writer */
143 if(p->state != QueueingW)
144 panic("runlock");
145 q->head = p->qnext;
146 if(q->head == 0)
147 q->tail = 0;
148 q->writer = 1;
149 unlock(&q->use);
150 ready(p);
151 }
152
153 void
wlock(RWlock * q)154 wlock(RWlock *q)
155 {
156 Proc *p;
157 uintptr pc;
158 void (*pt)(Proc*, int, vlong, vlong);
159
160 lock(&q->use);
161 rwstats.wlock++;
162 if(q->readers == 0 && q->writer == 0){
163 /* noone waiting, go for it */
164 q->wpc = getcallerpc(&q);
165 q->wproc = up;
166 q->writer = 1;
167 unlock(&q->use);
168 return;
169 }
170
171 /* wait */
172 rwstats.wlockq++;
173 p = q->tail;
174 if(up == nil)
175 panic("wlock");
176 if(p == nil)
177 q->head = up;
178 else
179 p->qnext = up;
180 q->tail = up;
181 up->qnext = 0;
182 up->state = QueueingW;
183 if(up->trace && (pt = proctrace) != nil){
184 pc = getcallerpc(&q);
185 pt(up, SSleep, 0, QueueingW|(pc<<8));
186 }
187 unlock(&q->use);
188 sched();
189 }
190
191 void
wunlock(RWlock * q)192 wunlock(RWlock *q)
193 {
194 Proc *p;
195
196 lock(&q->use);
197 p = q->head;
198 if(p == nil){
199 q->writer = 0;
200 unlock(&q->use);
201 return;
202 }
203 if(p->state == QueueingW){
204 /* start waiting writer */
205 q->head = p->qnext;
206 if(q->head == nil)
207 q->tail = nil;
208 unlock(&q->use);
209 ready(p);
210 return;
211 }
212
213 if(p->state != QueueingR)
214 panic("wunlock");
215
216 /* waken waiting readers */
217 while(q->head != nil && q->head->state == QueueingR){
218 p = q->head;
219 q->head = p->qnext;
220 q->readers++;
221 ready(p);
222 }
223 if(q->head == nil)
224 q->tail = nil;
225 q->writer = 0;
226 unlock(&q->use);
227 }
228
229 /* same as rlock but punts if there are any writers waiting */
230 int
canrlock(RWlock * q)231 canrlock(RWlock *q)
232 {
233 lock(&q->use);
234 rwstats.rlock++;
235 if(q->writer == 0 && q->head == nil){
236 /* no writer, go for it */
237 q->readers++;
238 unlock(&q->use);
239 return 1;
240 }
241 unlock(&q->use);
242 return 0;
243 }
244