#include #include static struct { QLp *p; QLp x[1024]; } ql = { ql.x }; enum { Queuing, QueuingR, QueuingW, }; static ulong (*_rendezvousp)(ulong, ulong) = rendezvous; /* this gets called by the thread library ONLY to get us to use its rendezvous */ void _qlockinit(ulong (*r)(ulong, ulong)) { _rendezvousp = r; } /* find a free shared memory location to queue ourselves in */ static QLp* getqlp(void) { QLp *p, *op; op = ql.p; for(p = op+1; ; p++){ if(p == &ql.x[nelem(ql.x)]) p = ql.x; if(p == op) abort(); if(_tas(&(p->inuse)) == 0){ ql.p = p; p->next = nil; break; } } return p; } void qlock(QLock *q) { QLp *p, *mp; lock(&q->lock); if(!q->locked){ q->locked = 1; unlock(&q->lock); return; } /* chain into waiting list */ mp = getqlp(); p = q->tail; if(p == nil) q->head = mp; else p->next = mp; q->tail = mp; mp->state = Queuing; unlock(&q->lock); /* wait */ (*_rendezvousp)((ulong)mp, 1); mp->inuse = 0; } void qunlock(QLock *q) { QLp *p; lock(&q->lock); p = q->head; if(p != nil){ /* wakeup head waiting process */ q->head = p->next; if(q->head == nil) q->tail = nil; unlock(&q->lock); (*_rendezvousp)((ulong)p, 0x12345); return; } q->locked = 0; unlock(&q->lock); } int canqlock(QLock *q) { lock(&q->lock); if(!q->locked){ q->locked = 1; unlock(&q->lock); return 1; } unlock(&q->lock); return 0; } void rlock(RWLock *q) { QLp *p, *mp; lock(&q->lock); if(q->writer == 0 && q->head == nil){ /* no writer, go for it */ q->readers++; unlock(&q->lock); return; } mp = getqlp(); p = q->tail; if(p == 0) q->head = mp; else p->next = mp; q->tail = mp; mp->next = nil; mp->state = QueuingR; unlock(&q->lock); /* wait in kernel */ (*_rendezvousp)((ulong)mp, 1); mp->inuse = 0; } void runlock(RWLock *q) { QLp *p; lock(&q->lock); p = q->head; if(--(q->readers) > 0 || p == nil){ unlock(&q->lock); return; } /* start waiting writer */ if(p->state != QueuingW) abort(); q->head = p->next; if(q->head == 0) q->tail = 0; q->writer = 1; unlock(&q->lock); /* wakeup waiter */ (*_rendezvousp)((ulong)p, 0); } void wlock(RWLock *q) { QLp *p, *mp; lock(&q->lock); if(q->readers == 0 && q->writer == 0){ /* noone waiting, go for it */ q->writer = 1; unlock(&q->lock); return; } /* wait */ p = q->tail; mp = getqlp(); if(p == nil) q->head = mp; else p->next = mp; q->tail = mp; mp->next = nil; mp->state = QueuingW; unlock(&q->lock); /* wait in kernel */ (*_rendezvousp)((ulong)mp, 1); mp->inuse = 0; } void wunlock(RWLock *q) { QLp *p; lock(&q->lock); p = q->head; if(p == nil){ q->writer = 0; unlock(&q->lock); return; } if(p->state == QueuingW){ /* start waiting writer */ q->head = p->next; if(q->head == nil) q->tail = nil; unlock(&q->lock); (*_rendezvousp)((ulong)p, 0); return; } if(p->state != QueuingR) abort(); /* waken waiting readers */ while(q->head != nil && q->head->state == QueuingR){ p = q->head; q->head = p->next; q->readers++; (*_rendezvousp)((ulong)p, 0); } if(q->head == nil) q->tail = nil; q->writer = 0; unlock(&q->lock); }