blob: 625c100f5568f2a845d19027c1594158840687db [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
rsc06bb4ed2004-09-17 00:38:29 +000019static void (*procsleep)(_Procrend*) = _procsleep;
20static void (*procwakeup)(_Procrend*) = _procwakeup;
rscb2cfc4e2003-09-30 17:47:41 +000021
22/* this gets called by the thread library ONLY to get us to use its rendezvous */
23void
rsc06bb4ed2004-09-17 00:38:29 +000024_qlockinit(void (*sleep)(_Procrend*), void (*wakeup)(_Procrend*))
rscb2cfc4e2003-09-30 17:47:41 +000025{
rsc06bb4ed2004-09-17 00:38:29 +000026 procsleep = sleep;
27 procwakeup = wakeup;
rscb2cfc4e2003-09-30 17:47:41 +000028}
29
30/* find a free shared memory location to queue ourselves in */
31static QLp*
32getqlp(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;
rscbe36ff62004-04-29 17:13:24 +000040 if(p == op){
41 fprint(2, "qlock: out of qlp\n");
rscb2cfc4e2003-09-30 17:47:41 +000042 abort();
rscbe36ff62004-04-29 17:13:24 +000043 }
rsc06bb4ed2004-09-17 00:38:29 +000044 if(canlock(&p->inuse)){
rscb2cfc4e2003-09-30 17:47:41 +000045 ql.p = p;
46 p->next = nil;
47 break;
48 }
49 }
50 return p;
51}
52
53void
54qlock(QLock *q)
55{
56 QLp *p, *mp;
57
58 lock(&q->lock);
59 if(!q->locked){
60 q->locked = 1;
61 unlock(&q->lock);
62 return;
63 }
64
65
66 /* chain into waiting list */
67 mp = getqlp();
68 p = q->tail;
69 if(p == nil)
70 q->head = mp;
71 else
72 p->next = mp;
73 q->tail = mp;
74 mp->state = Queuing;
rsc06bb4ed2004-09-17 00:38:29 +000075 mp->rend.l = &q->lock;
76 _procsleep(&mp->rend);
rscb2cfc4e2003-09-30 17:47:41 +000077 unlock(&q->lock);
rsc6c746072004-05-23 00:59:33 +000078 assert(mp->state == Waking);
rsc06bb4ed2004-09-17 00:38:29 +000079 unlock(&mp->inuse);
rscb2cfc4e2003-09-30 17:47:41 +000080}
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;
rsc6c746072004-05-23 00:59:33 +000094 p->state = Waking;
rsc06bb4ed2004-09-17 00:38:29 +000095 _procwakeup(&p->rend);
96 unlock(&q->lock);
rscb2cfc4e2003-09-30 17:47:41 +000097 return;
98 }
99 q->locked = 0;
100 unlock(&q->lock);
101}
102
103int
104canqlock(QLock *q)
105{
106 if(!canlock(&q->lock))
107 return 0;
108 if(!q->locked){
109 q->locked = 1;
110 unlock(&q->lock);
111 return 1;
112 }
113 unlock(&q->lock);
114 return 0;
115}
116
117void
118rlock(RWLock *q)
119{
120 QLp *p, *mp;
121
122 lock(&q->lock);
123 if(q->writer == 0 && q->head == nil){
124 /* no writer, go for it */
125 q->readers++;
126 unlock(&q->lock);
127 return;
128 }
129
130 mp = getqlp();
131 p = q->tail;
132 if(p == 0)
133 q->head = mp;
134 else
135 p->next = mp;
136 q->tail = mp;
137 mp->next = nil;
138 mp->state = QueuingR;
rsc06bb4ed2004-09-17 00:38:29 +0000139 mp->rend.l = &q->lock;
140 _procsleep(&mp->rend);
rscb2cfc4e2003-09-30 17:47:41 +0000141 unlock(&q->lock);
rsc6c746072004-05-23 00:59:33 +0000142 assert(mp->state == Waking);
rsc06bb4ed2004-09-17 00:38:29 +0000143 unlock(&mp->inuse);
rscb2cfc4e2003-09-30 17:47:41 +0000144}
145
146int
147canrlock(RWLock *q)
148{
149 lock(&q->lock);
150 if (q->writer == 0 && q->head == nil) {
151 /* no writer; go for it */
152 q->readers++;
153 unlock(&q->lock);
154 return 1;
155 }
156 unlock(&q->lock);
157 return 0;
158}
159
160void
161runlock(RWLock *q)
162{
163 QLp *p;
164
165 lock(&q->lock);
166 if(q->readers <= 0)
167 abort();
168 p = q->head;
169 if(--(q->readers) > 0 || p == nil){
170 unlock(&q->lock);
171 return;
172 }
173
174 /* start waiting writer */
175 if(p->state != QueuingW)
176 abort();
177 q->head = p->next;
178 if(q->head == 0)
179 q->tail = 0;
180 q->writer = 1;
rscb2cfc4e2003-09-30 17:47:41 +0000181
182 /* wakeup waiter */
rsc6c746072004-05-23 00:59:33 +0000183 p->state = Waking;
rsc06bb4ed2004-09-17 00:38:29 +0000184 _procwakeup(&p->rend);
185 unlock(&q->lock);
rscb2cfc4e2003-09-30 17:47:41 +0000186}
187
188void
189wlock(RWLock *q)
190{
191 QLp *p, *mp;
192
193 lock(&q->lock);
194 if(q->readers == 0 && q->writer == 0){
195 /* noone waiting, go for it */
196 q->writer = 1;
197 unlock(&q->lock);
198 return;
199 }
200
201 /* wait */
202 p = q->tail;
203 mp = getqlp();
204 if(p == nil)
205 q->head = mp;
206 else
207 p->next = mp;
208 q->tail = mp;
209 mp->next = nil;
210 mp->state = QueuingW;
rscb2cfc4e2003-09-30 17:47:41 +0000211
212 /* wait in kernel */
rsc06bb4ed2004-09-17 00:38:29 +0000213 mp->rend.l = &q->lock;
214 _procsleep(&mp->rend);
215 unlock(&q->lock);
rsc6c746072004-05-23 00:59:33 +0000216 assert(mp->state == Waking);
rsc06bb4ed2004-09-17 00:38:29 +0000217 unlock(&mp->inuse);
rscb2cfc4e2003-09-30 17:47:41 +0000218}
219
220int
221canwlock(RWLock *q)
222{
223 lock(&q->lock);
224 if (q->readers == 0 && q->writer == 0) {
225 /* no one waiting; go for it */
226 q->writer = 1;
227 unlock(&q->lock);
228 return 1;
229 }
230 unlock(&q->lock);
231 return 0;
232}
233
234void
235wunlock(RWLock *q)
236{
237 QLp *p;
238
239 lock(&q->lock);
rscbe36ff62004-04-29 17:13:24 +0000240 if(q->writer == 0){
241 fprint(2, "wunlock: not holding lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000242 abort();
rscbe36ff62004-04-29 17:13:24 +0000243 }
rscb2cfc4e2003-09-30 17:47:41 +0000244 p = q->head;
245 if(p == nil){
246 q->writer = 0;
247 unlock(&q->lock);
248 return;
249 }
250 if(p->state == QueuingW){
251 /* start waiting writer */
252 q->head = p->next;
253 if(q->head == nil)
254 q->tail = nil;
rsc6c746072004-05-23 00:59:33 +0000255 p->state = Waking;
rsc06bb4ed2004-09-17 00:38:29 +0000256 _procwakeup(&p->rend);
257 unlock(&q->lock);
rscb2cfc4e2003-09-30 17:47:41 +0000258 return;
259 }
260
rscbe36ff62004-04-29 17:13:24 +0000261 if(p->state != QueuingR){
262 fprint(2, "wunlock: bad state\n");
rscb2cfc4e2003-09-30 17:47:41 +0000263 abort();
rscbe36ff62004-04-29 17:13:24 +0000264 }
rscb2cfc4e2003-09-30 17:47:41 +0000265
266 /* wake waiting readers */
267 while(q->head != nil && q->head->state == QueuingR){
268 p = q->head;
269 q->head = p->next;
270 q->readers++;
rsc6c746072004-05-23 00:59:33 +0000271 p->state = Waking;
rsc06bb4ed2004-09-17 00:38:29 +0000272 _procwakeup(&p->rend);
rscb2cfc4e2003-09-30 17:47:41 +0000273 }
274 if(q->head == nil)
275 q->tail = nil;
276 q->writer = 0;
277 unlock(&q->lock);
278}
279
280void
281rsleep(Rendez *r)
282{
283 QLp *t, *me;
284
rscbe36ff62004-04-29 17:13:24 +0000285 if(!r->l){
286 fprint(2, "rsleep: no lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000287 abort();
rscbe36ff62004-04-29 17:13:24 +0000288 }
rscb2cfc4e2003-09-30 17:47:41 +0000289 lock(&r->l->lock);
290 /* we should hold the qlock */
rscbe36ff62004-04-29 17:13:24 +0000291 if(!r->l->locked){
292 fprint(2, "rsleep: not locked\n");
rscb2cfc4e2003-09-30 17:47:41 +0000293 abort();
rscbe36ff62004-04-29 17:13:24 +0000294 }
rscb2cfc4e2003-09-30 17:47:41 +0000295
296 /* add ourselves to the wait list */
297 me = getqlp();
298 me->state = Sleeping;
299 if(r->head == nil)
300 r->head = me;
301 else
302 r->tail->next = me;
303 me->next = nil;
304 r->tail = me;
305
306 /* pass the qlock to the next guy */
307 t = r->l->head;
308 if(t){
309 r->l->head = t->next;
310 if(r->l->head == nil)
311 r->l->tail = nil;
rsc6c746072004-05-23 00:59:33 +0000312 t->state = Waking;
rsc06bb4ed2004-09-17 00:38:29 +0000313 _procwakeup(&t->rend);
314 }else
rscb2cfc4e2003-09-30 17:47:41 +0000315 r->l->locked = 0;
rscb2cfc4e2003-09-30 17:47:41 +0000316
317 /* wait for a wakeup */
rsc06bb4ed2004-09-17 00:38:29 +0000318 me->rend.l = &r->l->lock;
319 _procsleep(&me->rend);
320
rsc6c746072004-05-23 00:59:33 +0000321 assert(me->state == Waking);
rsc06bb4ed2004-09-17 00:38:29 +0000322 unlock(&me->inuse);
rscbe36ff62004-04-29 17:13:24 +0000323 if(!r->l->locked){
324 fprint(2, "rsleep: not locked after wakeup\n");
rscb2cfc4e2003-09-30 17:47:41 +0000325 abort();
rscbe36ff62004-04-29 17:13:24 +0000326 }
rscb2cfc4e2003-09-30 17:47:41 +0000327}
328
329int
330rwakeup(Rendez *r)
331{
332 QLp *t;
333
334 /*
335 * take off wait and put on front of queue
336 * put on front so guys that have been waiting will not get starved
337 */
338
rscbe36ff62004-04-29 17:13:24 +0000339 if(!r->l){
340 fprint(2, "rwakeup: no lock\n");
rscb2cfc4e2003-09-30 17:47:41 +0000341 abort();
rscbe36ff62004-04-29 17:13:24 +0000342 }
rscb2cfc4e2003-09-30 17:47:41 +0000343 lock(&r->l->lock);
rscbe36ff62004-04-29 17:13:24 +0000344 if(!r->l->locked){
345 fprint(2, "rwakeup: not locked\n");
rscb2cfc4e2003-09-30 17:47:41 +0000346 abort();
rscbe36ff62004-04-29 17:13:24 +0000347 }
rscb2cfc4e2003-09-30 17:47:41 +0000348
349 t = r->head;
350 if(t == nil){
351 unlock(&r->l->lock);
352 return 0;
353 }
354
355 r->head = t->next;
356 if(r->head == nil)
357 r->tail = nil;
358
359 t->next = r->l->head;
360 r->l->head = t;
361 if(r->l->tail == nil)
362 r->l->tail = t;
363
364 t->state = Queuing;
365 unlock(&r->l->lock);
366 return 1;
367}
368
369int
370rwakeupall(Rendez *r)
371{
372 int i;
373
374 for(i=0; rwakeup(r); i++)
375 ;
376 return i;
377}