xref: /plan9-contrib/sys/src/9k/port/qlock.c (revision d46407a37b53d968b453d19c0e464c526df5e227)
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