xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/qlock.c (revision 40ef9009116dd37656783aaadc8782c1d8bfb056)
1 #define _LOCK_EXTENSION
2 #define _QLOCK_EXTENSION
3 #define _RESEARCH_SOURCE
4 #include <u.h>
5 #include <lock.h>
6 #include <qlock.h>
7 #include <stdlib.h>
8 #include "sys9.h"
9 
10 #define rendezvous _RENDEZVOUS
11 #define _rendezvousp rendezvous
12 #define _tas tas
13 #define nelem(x) (sizeof(x)/sizeof((x)[0]))
14 
15 static struct {
16 	QLp	*p;
17 	QLp	x[1024];
18 } ql = {
19 	ql.x
20 };
21 
22 enum
23 {
24 	Queuing,
25 	QueuingR,
26 	QueuingW,
27 	Sleeping,
28 };
29 
30 /* find a free shared memory location to queue ourselves in */
31 static QLp*
getqlp(void)32 getqlp(void)
33 {
34 	QLp *p, *op;
35 
36 	op = ql.p;
37 	for(p = op+1; ; p++){
38 		if(p == &ql.x[nelem(ql.x)])
39 			p = ql.x;
40 		if(p == op)
41 			abort();
42 		if(_tas(&(p->inuse)) == 0){
43 			ql.p = p;
44 			p->next = nil;
45 			break;
46 		}
47 	}
48 	return p;
49 }
50 
51 void
qlock(QLock * q)52 qlock(QLock *q)
53 {
54 	QLp *p, *mp;
55 
56 	lock(&q->lock);
57 	if(!q->locked){
58 		q->locked = 1;
59 		unlock(&q->lock);
60 		return;
61 	}
62 
63 
64 	/* chain into waiting list */
65 	mp = getqlp();
66 	p = q->tail;
67 	if(p == nil)
68 		q->head = mp;
69 	else
70 		p->next = mp;
71 	q->tail = mp;
72 	mp->state = Queuing;
73 	unlock(&q->lock);
74 
75 	/* wait */
76 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
77 		;
78 	mp->inuse = 0;
79 }
80 
81 void
qunlock(QLock * q)82 qunlock(QLock *q)
83 {
84 	QLp *p;
85 
86 	lock(&q->lock);
87 	p = q->head;
88 	if(p != nil){
89 		/* wakeup head waiting process */
90 		q->head = p->next;
91 		if(q->head == nil)
92 			q->tail = nil;
93 		unlock(&q->lock);
94 		while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
95 			;
96 		return;
97 	}
98 	q->locked = 0;
99 	unlock(&q->lock);
100 }
101 
102 int
canqlock(QLock * q)103 canqlock(QLock *q)
104 {
105 	if(!canlock(&q->lock))
106 		return 0;
107 	if(!q->locked){
108 		q->locked = 1;
109 		unlock(&q->lock);
110 		return 1;
111 	}
112 	unlock(&q->lock);
113 	return 0;
114 }
115 
116 #if 0
117 
118 void
119 rlock(RWLock *q)
120 {
121 	QLp *p, *mp;
122 
123 	lock(&q->lock);
124 	if(q->writer == 0 && q->head == nil){
125 		/* no writer, go for it */
126 		q->readers++;
127 		unlock(&q->lock);
128 		return;
129 	}
130 
131 	mp = getqlp();
132 	p = q->tail;
133 	if(p == 0)
134 		q->head = mp;
135 	else
136 		p->next = mp;
137 	q->tail = mp;
138 	mp->next = nil;
139 	mp->state = QueuingR;
140 	unlock(&q->lock);
141 
142 	/* wait in kernel */
143 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
144 		;
145 	mp->inuse = 0;
146 }
147 
148 int
149 canrlock(RWLock *q)
150 {
151 	lock(&q->lock);
152 	if (q->writer == 0 && q->head == nil) {
153 		/* no writer; go for it */
154 		q->readers++;
155 		unlock(&q->lock);
156 		return 1;
157 	}
158 	unlock(&q->lock);
159 	return 0;
160 }
161 
162 void
163 runlock(RWLock *q)
164 {
165 	QLp *p;
166 
167 	lock(&q->lock);
168 	if(q->readers <= 0)
169 		abort();
170 	p = q->head;
171 	if(--(q->readers) > 0 || p == nil){
172 		unlock(&q->lock);
173 		return;
174 	}
175 
176 	/* start waiting writer */
177 	if(p->state != QueuingW)
178 		abort();
179 	q->head = p->next;
180 	if(q->head == 0)
181 		q->tail = 0;
182 	q->writer = 1;
183 	unlock(&q->lock);
184 
185 	/* wakeup waiter */
186 	while((*_rendezvousp)((ulong)p, 0) == ~0)
187 		;
188 }
189 
190 void
191 wlock(RWLock *q)
192 {
193 	QLp *p, *mp;
194 
195 	lock(&q->lock);
196 	if(q->readers == 0 && q->writer == 0){
197 		/* noone waiting, go for it */
198 		q->writer = 1;
199 		unlock(&q->lock);
200 		return;
201 	}
202 
203 	/* wait */
204 	p = q->tail;
205 	mp = getqlp();
206 	if(p == nil)
207 		q->head = mp;
208 	else
209 		p->next = mp;
210 	q->tail = mp;
211 	mp->next = nil;
212 	mp->state = QueuingW;
213 	unlock(&q->lock);
214 
215 	/* wait in kernel */
216 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
217 		;
218 	mp->inuse = 0;
219 }
220 
221 int
222 canwlock(RWLock *q)
223 {
224 	lock(&q->lock);
225 	if (q->readers == 0 && q->writer == 0) {
226 		/* no one waiting; go for it */
227 		q->writer = 1;
228 		unlock(&q->lock);
229 		return 1;
230 	}
231 	unlock(&q->lock);
232 	return 0;
233 }
234 
235 void
236 wunlock(RWLock *q)
237 {
238 	QLp *p;
239 
240 	lock(&q->lock);
241 	if(q->writer == 0)
242 		abort();
243 	p = q->head;
244 	if(p == nil){
245 		q->writer = 0;
246 		unlock(&q->lock);
247 		return;
248 	}
249 	if(p->state == QueuingW){
250 		/* start waiting writer */
251 		q->head = p->next;
252 		if(q->head == nil)
253 			q->tail = nil;
254 		unlock(&q->lock);
255 		while((*_rendezvousp)((ulong)p, 0) == ~0)
256 			;
257 		return;
258 	}
259 
260 	if(p->state != QueuingR)
261 		abort();
262 
263 	/* wake waiting readers */
264 	while(q->head != nil && q->head->state == QueuingR){
265 		p = q->head;
266 		q->head = p->next;
267 		q->readers++;
268 		while((*_rendezvousp)((ulong)p, 0) == ~0)
269 			;
270 	}
271 	if(q->head == nil)
272 		q->tail = nil;
273 	q->writer = 0;
274 	unlock(&q->lock);
275 }
276 
277 void
278 rsleep(Rendez *r)
279 {
280 	QLp *t, *me;
281 
282 	if(!r->l)
283 		abort();
284 	lock(&r->l->lock);
285 	/* we should hold the qlock */
286 	if(!r->l->locked)
287 		abort();
288 
289 	/* add ourselves to the wait list */
290 	me = getqlp();
291 	me->state = Sleeping;
292 	if(r->head == nil)
293 		r->head = me;
294 	else
295 		r->tail->next = me;
296 	me->next = nil;
297 	r->tail = me;
298 
299 	/* pass the qlock to the next guy */
300 	t = r->l->head;
301 	if(t){
302 		r->l->head = t->next;
303 		if(r->l->head == nil)
304 			r->l->tail = nil;
305 		unlock(&r->l->lock);
306 		while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
307 			;
308 	}else{
309 		r->l->locked = 0;
310 		unlock(&r->l->lock);
311 	}
312 
313 	/* wait for a wakeup */
314 	while((*_rendezvousp)((ulong)me, 1) == ~0)
315 		;
316 	me->inuse = 0;
317 }
318 
319 int
320 rwakeup(Rendez *r)
321 {
322 	QLp *t;
323 
324 	/*
325 	 * take off wait and put on front of queue
326 	 * put on front so guys that have been waiting will not get starved
327 	 */
328 
329 	if(!r->l)
330 		abort();
331 	lock(&r->l->lock);
332 	if(!r->l->locked)
333 		abort();
334 
335 	t = r->head;
336 	if(t == nil){
337 		unlock(&r->l->lock);
338 		return 0;
339 	}
340 
341 	r->head = t->next;
342 	if(r->head == nil)
343 		r->tail = nil;
344 
345 	t->next = r->l->head;
346 	r->l->head = t;
347 	if(r->l->tail == nil)
348 		r->l->tail = t;
349 
350 	t->state = Queuing;
351 	unlock(&r->l->lock);
352 	return 1;
353 }
354 
355 int
356 rwakeupall(Rendez *r)
357 {
358 	int i;
359 
360 	for(i=0; rwakeup(r); i++)
361 		;
362 	return i;
363 }
364 
365 #endif
366