2003-09-30 17:47:41 +00:00
|
|
|
#include <lib9.h>
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
QLp *p;
|
|
|
|
QLp x[1024];
|
|
|
|
} ql = {
|
|
|
|
ql.x
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Queuing,
|
|
|
|
QueuingR,
|
|
|
|
QueuingW,
|
|
|
|
Sleeping,
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2004-04-29 17:13:24 +00:00
|
|
|
if(p == op){
|
|
|
|
fprint(2, "qlock: out of qlp\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
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 */
|
|
|
|
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
|
|
|
;
|
|
|
|
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);
|
|
|
|
while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
|
|
|
|
;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
q->locked = 0;
|
|
|
|
unlock(&q->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
canqlock(QLock *q)
|
|
|
|
{
|
|
|
|
if(!canlock(&q->lock))
|
|
|
|
return 0;
|
|
|
|
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 */
|
|
|
|
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
|
|
|
;
|
|
|
|
mp->inuse = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
canrlock(RWLock *q)
|
|
|
|
{
|
|
|
|
lock(&q->lock);
|
|
|
|
if (q->writer == 0 && q->head == nil) {
|
|
|
|
/* no writer; go for it */
|
|
|
|
q->readers++;
|
|
|
|
unlock(&q->lock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
unlock(&q->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runlock(RWLock *q)
|
|
|
|
{
|
|
|
|
QLp *p;
|
|
|
|
|
|
|
|
lock(&q->lock);
|
|
|
|
if(q->readers <= 0)
|
|
|
|
abort();
|
|
|
|
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 */
|
|
|
|
while((*_rendezvousp)((ulong)p, 0) == ~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 */
|
|
|
|
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
|
|
|
;
|
|
|
|
mp->inuse = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
canwlock(RWLock *q)
|
|
|
|
{
|
|
|
|
lock(&q->lock);
|
|
|
|
if (q->readers == 0 && q->writer == 0) {
|
|
|
|
/* no one waiting; go for it */
|
|
|
|
q->writer = 1;
|
|
|
|
unlock(&q->lock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
unlock(&q->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
wunlock(RWLock *q)
|
|
|
|
{
|
|
|
|
QLp *p;
|
|
|
|
|
|
|
|
lock(&q->lock);
|
2004-04-29 17:13:24 +00:00
|
|
|
if(q->writer == 0){
|
|
|
|
fprint(2, "wunlock: not holding lock\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
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);
|
|
|
|
while((*_rendezvousp)((ulong)p, 0) == ~0)
|
|
|
|
;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-04-29 17:13:24 +00:00
|
|
|
if(p->state != QueuingR){
|
|
|
|
fprint(2, "wunlock: bad state\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
|
|
|
|
/* wake waiting readers */
|
|
|
|
while(q->head != nil && q->head->state == QueuingR){
|
|
|
|
p = q->head;
|
|
|
|
q->head = p->next;
|
|
|
|
q->readers++;
|
|
|
|
while((*_rendezvousp)((ulong)p, 0) == ~0)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
if(q->head == nil)
|
|
|
|
q->tail = nil;
|
|
|
|
q->writer = 0;
|
|
|
|
unlock(&q->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rsleep(Rendez *r)
|
|
|
|
{
|
|
|
|
QLp *t, *me;
|
|
|
|
|
2004-04-29 17:13:24 +00:00
|
|
|
if(!r->l){
|
|
|
|
fprint(2, "rsleep: no lock\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
lock(&r->l->lock);
|
|
|
|
/* we should hold the qlock */
|
2004-04-29 17:13:24 +00:00
|
|
|
if(!r->l->locked){
|
|
|
|
fprint(2, "rsleep: not locked\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
|
|
|
|
/* add ourselves to the wait list */
|
|
|
|
me = getqlp();
|
|
|
|
me->state = Sleeping;
|
|
|
|
if(r->head == nil)
|
|
|
|
r->head = me;
|
|
|
|
else
|
|
|
|
r->tail->next = me;
|
|
|
|
me->next = nil;
|
|
|
|
r->tail = me;
|
|
|
|
|
|
|
|
/* pass the qlock to the next guy */
|
|
|
|
t = r->l->head;
|
|
|
|
if(t){
|
|
|
|
r->l->head = t->next;
|
|
|
|
if(r->l->head == nil)
|
|
|
|
r->l->tail = nil;
|
|
|
|
unlock(&r->l->lock);
|
|
|
|
while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
|
|
|
|
;
|
|
|
|
}else{
|
|
|
|
r->l->locked = 0;
|
|
|
|
unlock(&r->l->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for a wakeup */
|
|
|
|
while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
|
|
|
|
;
|
|
|
|
me->inuse = 0;
|
2004-04-29 17:13:24 +00:00
|
|
|
if(!r->l->locked){
|
|
|
|
fprint(2, "rsleep: not locked after wakeup\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rwakeup(Rendez *r)
|
|
|
|
{
|
|
|
|
QLp *t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* take off wait and put on front of queue
|
|
|
|
* put on front so guys that have been waiting will not get starved
|
|
|
|
*/
|
|
|
|
|
2004-04-29 17:13:24 +00:00
|
|
|
if(!r->l){
|
|
|
|
fprint(2, "rwakeup: no lock\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
lock(&r->l->lock);
|
2004-04-29 17:13:24 +00:00
|
|
|
if(!r->l->locked){
|
|
|
|
fprint(2, "rwakeup: not locked\n");
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2004-04-29 17:13:24 +00:00
|
|
|
}
|
2003-09-30 17:47:41 +00:00
|
|
|
|
|
|
|
t = r->head;
|
|
|
|
if(t == nil){
|
|
|
|
unlock(&r->l->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r->head = t->next;
|
|
|
|
if(r->head == nil)
|
|
|
|
r->tail = nil;
|
|
|
|
|
|
|
|
t->next = r->l->head;
|
|
|
|
r->l->head = t;
|
|
|
|
if(r->l->tail == nil)
|
|
|
|
r->l->tail = t;
|
|
|
|
|
|
|
|
t->state = Queuing;
|
|
|
|
unlock(&r->l->lock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rwakeupall(Rendez *r)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; rwakeup(r); i++)
|
|
|
|
;
|
|
|
|
return i;
|
|
|
|
}
|