Blob


1 #include <lib9.h>
3 static struct {
4 QLp *p;
5 QLp x[1024];
6 } ql = {
7 ql.x
8 };
10 enum
11 {
12 Queuing,
13 QueuingR,
14 QueuingW,
15 Sleeping,
16 Waking,
17 };
19 static ulong (*_rendezvousp)(ulong, ulong) = rendezvous;
21 /* this gets called by the thread library ONLY to get us to use its rendezvous */
22 void
23 _qlockinit(ulong (*r)(ulong, ulong))
24 {
25 _rendezvousp = r;
26 }
28 /* find a free shared memory location to queue ourselves in */
29 static QLp*
30 getqlp(void)
31 {
32 QLp *p, *op;
34 op = ql.p;
35 for(p = op+1; ; p++){
36 if(p == &ql.x[nelem(ql.x)])
37 p = ql.x;
38 if(p == op){
39 fprint(2, "qlock: out of qlp\n");
40 abort();
41 }
42 if(_tas(&(p->inuse)) == 0){
43 ql.p = p;
44 p->next = nil;
45 break;
46 }
47 }
48 return p;
49 }
51 void
52 qlock(QLock *q)
53 {
54 QLp *p, *mp;
56 lock(&q->lock);
57 if(!q->locked){
58 q->locked = 1;
59 unlock(&q->lock);
60 return;
61 }
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);
75 /* wait */
76 while((*_rendezvousp)((ulong)mp, 1) == ~0)
77 ;
78 assert(mp->state == Waking);
79 mp->inuse = 0;
80 }
82 void
83 qunlock(QLock *q)
84 {
85 QLp *p;
87 lock(&q->lock);
88 p = q->head;
89 if(p != nil){
90 /* wakeup head waiting process */
91 q->head = p->next;
92 if(q->head == nil)
93 q->tail = nil;
94 unlock(&q->lock);
95 p->state = Waking;
96 while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
97 ;
98 return;
99 }
100 q->locked = 0;
101 unlock(&q->lock);
104 int
105 canqlock(QLock *q)
107 if(!canlock(&q->lock))
108 return 0;
109 if(!q->locked){
110 q->locked = 1;
111 unlock(&q->lock);
112 return 1;
114 unlock(&q->lock);
115 return 0;
118 void
119 rlock(RWLock *q)
121 QLp *p, *mp;
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;
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);
142 /* wait in kernel */
143 while((*_rendezvousp)((ulong)mp, 1) == ~0)
145 assert(mp->state == Waking);
146 mp->inuse = 0;
149 int
150 canrlock(RWLock *q)
152 lock(&q->lock);
153 if (q->writer == 0 && q->head == nil) {
154 /* no writer; go for it */
155 q->readers++;
156 unlock(&q->lock);
157 return 1;
159 unlock(&q->lock);
160 return 0;
163 void
164 runlock(RWLock *q)
166 QLp *p;
168 lock(&q->lock);
169 if(q->readers <= 0)
170 abort();
171 p = q->head;
172 if(--(q->readers) > 0 || p == nil){
173 unlock(&q->lock);
174 return;
177 /* start waiting writer */
178 if(p->state != QueuingW)
179 abort();
180 q->head = p->next;
181 if(q->head == 0)
182 q->tail = 0;
183 q->writer = 1;
184 unlock(&q->lock);
186 /* wakeup waiter */
187 p->state = Waking;
188 while((*_rendezvousp)((ulong)p, 0) == ~0)
192 void
193 wlock(RWLock *q)
195 QLp *p, *mp;
197 lock(&q->lock);
198 if(q->readers == 0 && q->writer == 0){
199 /* noone waiting, go for it */
200 q->writer = 1;
201 unlock(&q->lock);
202 return;
205 /* wait */
206 p = q->tail;
207 mp = getqlp();
208 if(p == nil)
209 q->head = mp;
210 else
211 p->next = mp;
212 q->tail = mp;
213 mp->next = nil;
214 mp->state = QueuingW;
215 unlock(&q->lock);
217 /* wait in kernel */
218 while((*_rendezvousp)((ulong)mp, 1) == ~0)
220 assert(mp->state == Waking);
221 mp->inuse = 0;
224 int
225 canwlock(RWLock *q)
227 lock(&q->lock);
228 if (q->readers == 0 && q->writer == 0) {
229 /* no one waiting; go for it */
230 q->writer = 1;
231 unlock(&q->lock);
232 return 1;
234 unlock(&q->lock);
235 return 0;
238 void
239 wunlock(RWLock *q)
241 QLp *p;
243 lock(&q->lock);
244 if(q->writer == 0){
245 fprint(2, "wunlock: not holding lock\n");
246 abort();
248 p = q->head;
249 if(p == nil){
250 q->writer = 0;
251 unlock(&q->lock);
252 return;
254 if(p->state == QueuingW){
255 /* start waiting writer */
256 q->head = p->next;
257 if(q->head == nil)
258 q->tail = nil;
259 unlock(&q->lock);
260 p->state = Waking;
261 while((*_rendezvousp)((ulong)p, 0) == ~0)
263 return;
266 if(p->state != QueuingR){
267 fprint(2, "wunlock: bad state\n");
268 abort();
271 /* wake waiting readers */
272 while(q->head != nil && q->head->state == QueuingR){
273 p = q->head;
274 q->head = p->next;
275 q->readers++;
276 p->state = Waking;
277 while((*_rendezvousp)((ulong)p, 0) == ~0)
280 if(q->head == nil)
281 q->tail = nil;
282 q->writer = 0;
283 unlock(&q->lock);
286 void
287 rsleep(Rendez *r)
289 QLp *t, *me;
291 if(!r->l){
292 fprint(2, "rsleep: no lock\n");
293 abort();
295 lock(&r->l->lock);
296 /* we should hold the qlock */
297 if(!r->l->locked){
298 fprint(2, "rsleep: not locked\n");
299 abort();
302 /* add ourselves to the wait list */
303 me = getqlp();
304 me->state = Sleeping;
305 if(r->head == nil)
306 r->head = me;
307 else
308 r->tail->next = me;
309 me->next = nil;
310 r->tail = me;
312 /* pass the qlock to the next guy */
313 t = r->l->head;
314 if(t){
315 r->l->head = t->next;
316 if(r->l->head == nil)
317 r->l->tail = nil;
318 unlock(&r->l->lock);
319 t->state = Waking;
320 while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
322 }else{
323 r->l->locked = 0;
324 unlock(&r->l->lock);
327 /* wait for a wakeup */
328 while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
330 assert(me->state == Waking);
331 me->inuse = 0;
332 if(!r->l->locked){
333 fprint(2, "rsleep: not locked after wakeup\n");
334 abort();
338 int
339 rwakeup(Rendez *r)
341 QLp *t;
343 /*
344 * take off wait and put on front of queue
345 * put on front so guys that have been waiting will not get starved
346 */
348 if(!r->l){
349 fprint(2, "rwakeup: no lock\n");
350 abort();
352 lock(&r->l->lock);
353 if(!r->l->locked){
354 fprint(2, "rwakeup: not locked\n");
355 abort();
358 t = r->head;
359 if(t == nil){
360 unlock(&r->l->lock);
361 return 0;
364 r->head = t->next;
365 if(r->head == nil)
366 r->tail = nil;
368 t->next = r->l->head;
369 r->l->head = t;
370 if(r->l->tail == nil)
371 r->l->tail = t;
373 t->state = Queuing;
374 unlock(&r->l->lock);
375 return 1;
378 int
379 rwakeupall(Rendez *r)
381 int i;
383 for(i=0; rwakeup(r); i++)
385 return i;