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