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