#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
struct {
ulong rlock;
ulong rlockq;
ulong wlock;
ulong wlockq;
ulong qlock;
ulong qlockq;
} rwstats;
void
qlock(QLock *q)
{
Proc *p, *mp;
lock(&q->use);
rwstats.qlock++;
if(!q->locked) {
q->locked = 1;
unlock(&q->use);
return;
}
rwstats.qlockq++;
p = q->tail;
mp = up;
if(p == 0)
q->head = mp;
else
p->qnext = mp;
q->tail = mp;
mp->qnext = 0;
mp->state = Queueing;
unlock(&q->use);
sched();
}
int
canqlock(QLock *q)
{
if(!canlock(&q->use))
return 0;
if(q->locked){
unlock(&q->use);
return 0;
}
q->locked = 1;
unlock(&q->use);
return 1;
}
void
qunlock(QLock *q)
{
Proc *p;
lock(&q->use);
p = q->head;
if(p) {
q->head = p->qnext;
if(q->head == 0)
q->tail = 0;
unlock(&q->use);
ready(p);
return;
}
q->locked = 0;
unlock(&q->use);
}
void
rlock(RWlock *q)
{
Proc *p, *mp;
lock(&q->use);
//{int i;
//for(i=0; i<nelem(q->pidr); i++)
//if(q->pidr[i]==up->pid)
//print("***already %d\n", up->pid);
//}
rwstats.rlock++;
if(q->writer == 0 && q->head == nil){
/* no writer, go for it */
//{int i;
//for(i=0; i<nelem(q->pidr); i++)
//if(q->pidr[i]==0) {
//q->pidr[i]=up->pid;
//break;
//}}
q->readers++;
unlock(&q->use);
return;
}
rwstats.rlockq++;
p = q->tail;
mp = up;
if(p == 0)
q->head = mp;
else
p->qnext = mp;
q->tail = mp;
mp->qnext = 0;
mp->state = Queueing;
//print("%d rl for w%d\n", up->pid, q->pidw);
unlock(&q->use);
sched();
}
void
runlock(RWlock *q)
{
Proc *p;
lock(&q->use);
//{int i;
//for(i=0; i<nelem(q->pidr); i++)
//if(q->pidr[i]==up->pid) {
//q->pidr[i] = 0;
//break;
//}}
p = q->head;
if(--(q->readers) > 0 || p == nil){
unlock(&q->use);
return;
}
/* start waiting writer */
if(p->state != QueueingW)
panic("runlock");
q->head = p->qnext;
if(q->head == 0)
q->tail = 0;
q->writer = 1;
//q->pidw = p->pid;
unlock(&q->use);
ready(p);
}
void
wlock(RWlock *q)
{
Proc *p, *mp;
lock(&q->use);
rwstats.wlock++;
if(q->readers == 0 && q->writer == 0){
/* noone waiting, go for it */
//q->pidw = up->pid;
q->writer = 1;
unlock(&q->use);
return;
}
/* wait */
//rwstats.wlockq++;
p = q->tail;
mp = up;
if(p == nil)
q->head = mp;
else
p->qnext = mp;
q->tail = mp;
mp->qnext = 0;
mp->state = QueueingW;
//print("%d wl for %d%d", up->pid, q->readers, q->writer);
//if(q->pidw) print(" w%d", q->pidw);
//{int i;
//for(i=0; i<nelem(q->pidr); i++)
//if(q->pidr[i])
//print(" %d", q->pidr[i]);
//print("\n");
//}
unlock(&q->use);
sched();
}
void
wunlock(RWlock *q)
{
Proc *p;
lock(&q->use);
//if(q->pidw!=up->pid)
//print("not qw\n");
//q->pidw = 0;
p = q->head;
if(p == nil){
q->writer = 0;
unlock(&q->use);
return;
}
if(p->state == QueueingW){
//q->pidw = p->pid;
/* start waiting writer */
q->head = p->qnext;
if(q->head == nil)
q->tail = nil;
unlock(&q->use);
ready(p);
return;
}
if(p->state != Queueing)
panic("wunlock");
/* waken waiting readers */
while(q->head != nil && q->head->state == Queueing){
//{int i;
//for(i=0;i<nelem(q->pidr); i++)
//if(q->pidr[i]==0) {
//q->pidr[i] = p->pid;
//break;
//}}
p = q->head;
q->head = p->qnext;
q->readers++;
ready(p);
}
if(q->head == nil)
q->tail = nil;
q->writer = 0;
unlock(&q->use);
}