Blob
1 #include <lib9.h>3 static struct {4 QLp *p;5 QLp x[1024];6 } ql = {7 ql.x8 };10 enum11 {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 void23 _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 void52 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 else70 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 void83 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);102 }104 int105 canqlock(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 }118 void119 rlock(RWLock *q)120 {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;129 }131 mp = getqlp();132 p = q->tail;133 if(p == 0)134 q->head = mp;135 else136 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)144 ;145 assert(mp->state == Waking);146 mp->inuse = 0;147 }149 int150 canrlock(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 }163 void164 runlock(RWLock *q)165 {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;175 }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)189 ;190 }192 void193 wlock(RWLock *q)194 {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;203 }205 /* wait */206 p = q->tail;207 mp = getqlp();208 if(p == nil)209 q->head = mp;210 else211 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)219 ;220 assert(mp->state == Waking);221 mp->inuse = 0;222 }224 int225 canwlock(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 }238 void239 wunlock(RWLock *q)240 {241 QLp *p;243 lock(&q->lock);244 if(q->writer == 0){245 fprint(2, "wunlock: not holding lock\n");246 abort();247 }248 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);260 p->state = Waking;261 while((*_rendezvousp)((ulong)p, 0) == ~0)262 ;263 return;264 }266 if(p->state != QueuingR){267 fprint(2, "wunlock: bad state\n");268 abort();269 }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)278 ;279 }280 if(q->head == nil)281 q->tail = nil;282 q->writer = 0;283 unlock(&q->lock);284 }286 void287 rsleep(Rendez *r)288 {289 QLp *t, *me;291 if(!r->l){292 fprint(2, "rsleep: no lock\n");293 abort();294 }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();300 }302 /* add ourselves to the wait list */303 me = getqlp();304 me->state = Sleeping;305 if(r->head == nil)306 r->head = me;307 else308 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)321 ;322 }else{323 r->l->locked = 0;324 unlock(&r->l->lock);325 }327 /* wait for a wakeup */328 while((*_rendezvousp)((ulong)me, 0x23456) == ~0)329 ;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();335 }336 }338 int339 rwakeup(Rendez *r)340 {341 QLp *t;343 /*344 * take off wait and put on front of queue345 * put on front so guys that have been waiting will not get starved346 */348 if(!r->l){349 fprint(2, "rwakeup: no lock\n");350 abort();351 }352 lock(&r->l->lock);353 if(!r->l->locked){354 fprint(2, "rwakeup: not locked\n");355 abort();356 }358 t = r->head;359 if(t == nil){360 unlock(&r->l->lock);361 return 0;362 }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;376 }378 int379 rwakeupall(Rendez *r)380 {381 int i;383 for(i=0; rwakeup(r); i++)384 ;385 return i;386 }