blob: d83a4b7f7bb583c18ad6f307ffab48c7d7c4f76b [file] [log] [blame]
rscb2cfc4e2003-09-30 17:47:41 +00001#include <lib9.h>
2
3static struct {
4 QLp *p;
5 QLp x[1024];
6} ql = {
7 ql.x
8};
9
10enum
11{
12 Queuing,
13 QueuingR,
14 QueuingW,
15 Sleeping,
rsc6c746072004-05-23 00:59:33 +000016 Waking,
rscb2cfc4e2003-09-30 17:47:41 +000017};
18
19static ulong (*_rendezvousp)(ulong, ulong) = rendezvous;
20
21/* this gets called by the thread library ONLY to get us to use its rendezvous */
22void
23_qlockinit(ulong (*r)(ulong, ulong))
24{
25 _rendezvousp = r;
26}
27
28/* find a free shared memory location to queue ourselves in */
29static QLp*
30getqlp(void)
31{
32 QLp *p, *op;
33
34 op = ql.p;
35 for(p = op+1; ; p++){
36 if(p == &ql.x[nelem(ql.x)])
37 p = ql.x;
rscbe36ff62004-04-29 17:13:24 +000038 if(p == op){
39 fprint(2, "qlock: out of qlp\n");
rscb2cfc4e2003-09-30 17:47:41 +000040 abort();
rscbe36ff62004-04-29 17:13:24 +000041 }
rscb2cfc4e2003-09-30 17:47:41 +000042 if(_tas(&(p->inuse)) == 0){
43 ql.p = p;
44 p->next = nil;
45 break;
46 }
47 }
48 return p;
49}
50
51void
52qlock(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 ;
rsc6c746072004-05-23 00:59:33 +000078 assert(mp->state == Waking);
rscb2cfc4e2003-09-30 17:47:41 +000079 mp->inuse = 0;
80}
81
82void
83qunlock(QLock *q)
84{
85 QLp *p;
86
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);
rsc6c746072004-05-23 00:59:33 +000095 p->state = Waking;
rscb2cfc4e2003-09-30 17:47:41 +000096 while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
97 ;
98 return;
99 }
100 q->locked = 0;
101 unlock(&q->lock);
102}
103
104int
105canqlock(QLock *q)
106{
107 if(!canlock(&q->lock))
108 return 0;
109 if(!q->locked){
110 q->locked = 1;
111 unlock(&q->lock);
112 return 1;
113 }
114 unlock(&q->lock);
115 return 0;
116}
117
118void
119rlock(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 ;
rsc6c746072004-05-23 00:59:33 +0000145 assert(mp->state == Waking);
rscb2cfc4e2003-09-30 17:47:41 +0000146 mp->inuse = 0;
147}
148
149int
150canrlock(RWLock *q)
151{
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;
158 }
159 unlock(&q->lock);
160 return 0;
161}
162
163void
164runlock(RWLock *q)
165{
166 QLp *p;
167
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;
175 }
176
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);
185
186 /* wakeup waiter */
rsc6c746072004-05-23 00:59:33 +0000187 p->state = Waking;
rscb2cfc4e2003-09-30 17:47:41 +0000188 while((*_rendezvousp)((ulong)p, 0) == ~0)
189 ;
190}
191
192void
193wlock(RWLock *q)
194{
195 QLp *p, *mp;
196
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;
203 }
204
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);
216
217 /* wait in kernel */
218 while((*_rendezvousp)((ulong)mp, 1) == ~0)
219 ;
rsc6c746072004-05-23 00:59:33 +0000220 assert(mp->state == Waking);
rscb2cfc4e2003-09-30 17:47:41 +0000221 mp->inuse = 0;
222}
223
224int
225canwlock(RWLock *q)
226{
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;
233 }
234 unlock(&q->lock);
235 return 0;
236}
237
238void
239wunlock(RWLock *q)
240{
241 QLp *p;
242
243 lock(&q->lock);
rscbe36ff62004-04-29 17:13:24 +0000244 if(q->writer == 0){
245 fprint(2, "wunlock: not holding lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000246 abort();
rscbe36ff62004-04-29 17:13:24 +0000247 }
rscb2cfc4e2003-09-30 17:47:41 +0000248 p = q->head;
249 if(p == nil){
250 q->writer = 0;
251 unlock(&q->lock);
252 return;
253 }
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);
rsc6c746072004-05-23 00:59:33 +0000260 p->state = Waking;
rscb2cfc4e2003-09-30 17:47:41 +0000261 while((*_rendezvousp)((ulong)p, 0) == ~0)
262 ;
263 return;
264 }
265
rscbe36ff62004-04-29 17:13:24 +0000266 if(p->state != QueuingR){
267 fprint(2, "wunlock: bad state\n");
rscb2cfc4e2003-09-30 17:47:41 +0000268 abort();
rscbe36ff62004-04-29 17:13:24 +0000269 }
rscb2cfc4e2003-09-30 17:47:41 +0000270
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++;
rsc6c746072004-05-23 00:59:33 +0000276 p->state = Waking;
rscb2cfc4e2003-09-30 17:47:41 +0000277 while((*_rendezvousp)((ulong)p, 0) == ~0)
278 ;
279 }
280 if(q->head == nil)
281 q->tail = nil;
282 q->writer = 0;
283 unlock(&q->lock);
284}
285
286void
287rsleep(Rendez *r)
288{
289 QLp *t, *me;
290
rscbe36ff62004-04-29 17:13:24 +0000291 if(!r->l){
292 fprint(2, "rsleep: no lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000293 abort();
rscbe36ff62004-04-29 17:13:24 +0000294 }
rscb2cfc4e2003-09-30 17:47:41 +0000295 lock(&r->l->lock);
296 /* we should hold the qlock */
rscbe36ff62004-04-29 17:13:24 +0000297 if(!r->l->locked){
298 fprint(2, "rsleep: not locked\n");
rscb2cfc4e2003-09-30 17:47:41 +0000299 abort();
rscbe36ff62004-04-29 17:13:24 +0000300 }
rscb2cfc4e2003-09-30 17:47:41 +0000301
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;
311
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);
rsc6c746072004-05-23 00:59:33 +0000319 t->state = Waking;
rscb2cfc4e2003-09-30 17:47:41 +0000320 while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
321 ;
322 }else{
323 r->l->locked = 0;
324 unlock(&r->l->lock);
325 }
326
327 /* wait for a wakeup */
328 while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
329 ;
rsc6c746072004-05-23 00:59:33 +0000330 assert(me->state == Waking);
rscb2cfc4e2003-09-30 17:47:41 +0000331 me->inuse = 0;
rscbe36ff62004-04-29 17:13:24 +0000332 if(!r->l->locked){
333 fprint(2, "rsleep: not locked after wakeup\n");
rscb2cfc4e2003-09-30 17:47:41 +0000334 abort();
rscbe36ff62004-04-29 17:13:24 +0000335 }
rscb2cfc4e2003-09-30 17:47:41 +0000336}
337
338int
339rwakeup(Rendez *r)
340{
341 QLp *t;
342
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 */
347
rscbe36ff62004-04-29 17:13:24 +0000348 if(!r->l){
349 fprint(2, "rwakeup: no lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000350 abort();
rscbe36ff62004-04-29 17:13:24 +0000351 }
rscb2cfc4e2003-09-30 17:47:41 +0000352 lock(&r->l->lock);
rscbe36ff62004-04-29 17:13:24 +0000353 if(!r->l->locked){
354 fprint(2, "rwakeup: not locked\n");
rscb2cfc4e2003-09-30 17:47:41 +0000355 abort();
rscbe36ff62004-04-29 17:13:24 +0000356 }
rscb2cfc4e2003-09-30 17:47:41 +0000357
358 t = r->head;
359 if(t == nil){
360 unlock(&r->l->lock);
361 return 0;
362 }
363
364 r->head = t->next;
365 if(r->head == nil)
366 r->tail = nil;
367
368 t->next = r->l->head;
369 r->l->head = t;
370 if(r->l->tail == nil)
371 r->l->tail = t;
372
373 t->state = Queuing;
374 unlock(&r->l->lock);
375 return 1;
376}
377
378int
379rwakeupall(Rendez *r)
380{
381 int i;
382
383 for(i=0; rwakeup(r); i++)
384 ;
385 return i;
386}