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