added eqlock(), a interruptable version of qlock. addresses issue #81

This commit is contained in:
cinap_lenrek 2011-08-10 16:21:17 +02:00
parent 5cf6f8c096
commit 70e4b8d1f9
7 changed files with 120 additions and 22 deletions

View file

@ -204,7 +204,7 @@ audioread(Chan *c, void *a, long n, vlong off)
if(fn == nil)
error(Egreg);
qlock(ac);
eqlock(ac);
if(waserror()){
qunlock(ac);
nexterror();
@ -260,7 +260,7 @@ audiowrite(Chan *c, void *a, long n, vlong off)
if(fn == nil)
error(Egreg);
qlock(ac);
eqlock(ac);
if(waserror()){
qunlock(ac);
nexterror();

View file

@ -105,7 +105,7 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
uvlong oo;
char buf[128];
qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
eqlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
if(waserror()){
qunlock(&c->umqlock);
nexterror();

View file

@ -735,6 +735,7 @@ struct Proc
int trace; /* process being traced? */
ulong qpc; /* pc calling last blocking qlock */
QLock *eql; /* interruptable eqlock, protected by rlock */
int setargs;

View file

@ -98,6 +98,7 @@ int eqchan(Chan*, Chan*, int);
int eqchantdqid(Chan*, int, int, Qid, int);
int eqqid(Qid, Qid);
void error(char*);
void eqlock(QLock*);
long execregs(ulong, ulong, ulong);
void exhausted(char*);
void exit(int);

View file

@ -900,8 +900,6 @@ int
postnote(Proc *p, int dolock, char *n, int flag)
{
int s, ret;
Rendez *r;
Proc *d, **l;
if(dolock)
qlock(&p->debug);
@ -921,6 +919,8 @@ postnote(Proc *p, int dolock, char *n, int flag)
/* this loop is to avoid lock ordering problems. */
for(;;){
Rendez *r;
s = splhi();
lock(&p->rlock);
r = p->r;
@ -948,24 +948,59 @@ postnote(Proc *p, int dolock, char *n, int flag)
unlock(&p->rlock);
splx(s);
if(p->state != Rendezvous)
return ret;
Pullout:
switch(p->state){
case Queueing:
/* Try and pull out of a eqlock */
lock(&p->rlock);
if(p->state == Queueing && p->eql && p->notepending){
Proc *d, *l;
QLock *q;
/* Try and pull out of a rendezvous */
lock(p->rgrp);
if(p->state == Rendezvous) {
p->rendval = ~0;
l = &REND(p->rgrp, p->rendtag);
for(d = *l; d; d = d->rendhash) {
if(d == p) {
*l = p->rendhash;
break;
q = p->eql;
if(!canlock(&q->use)){
unlock(&p->rlock);
sched();
goto Pullout;
}
l = &d->rendhash;
for(l = nil, d = q->head; d; l = d, d = d->qnext)
if(d == p){
if(l)
l->qnext = p->qnext;
else
q->head = p->qnext;
if(p->qnext == 0)
q->tail = l;
p->qnext = 0;
p->eql = 0;
ready(p);
break;
}
unlock(&q->use);
break;
}
ready(p);
unlock(&p->rlock);
break;
case Rendezvous:
/* Try and pull out of a rendezvous */
lock(p->rgrp);
if(p->state == Rendezvous) {
Proc *d, **l;
p->rendval = ~0;
l = &REND(p->rgrp, p->rendtag);
for(d = *l; d; d = d->rendhash) {
if(d == p) {
*l = p->rendhash;
break;
}
l = &d->rendhash;
}
ready(p);
}
unlock(p->rgrp);
break;
}
unlock(p->rgrp);
return ret;
}

View file

@ -1017,7 +1017,7 @@ qbread(Queue *q, int len)
Block *b, *nb;
int n;
qlock(&q->rlock);
eqlock(&q->rlock);
if(waserror()){
qunlock(&q->rlock);
nexterror();
@ -1072,7 +1072,7 @@ qread(Queue *q, void *vp, int len)
Block *b, *first, **l;
int m, n;
qlock(&q->rlock);
eqlock(&q->rlock);
if(waserror()){
qunlock(&q->rlock);
nexterror();
@ -1173,7 +1173,7 @@ qbwrite(Queue *q, Block *b)
}
dowakeup = 0;
qlock(&q->wlock);
eqlock(&q->wlock);
if(waserror()){
if(b != nil)
freeb(b);

View file

@ -4,6 +4,8 @@
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
struct {
ulong rlock;
ulong rlockq;
@ -13,6 +15,59 @@ struct {
ulong qlockq;
} rwstats;
void
eqlock(QLock *q)
{
Proc *p;
if(m->ilockdepth != 0)
print("eqlock: %#p: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
if(up != nil && up->nlocks.ref)
print("eqlock: %#p: nlocks %lud\n", getcallerpc(&q), up->nlocks.ref);
if(q->use.key == 0x55555555)
panic("eqlock: q %#p, key 5*\n", q);
lock(&q->use);
rwstats.qlock++;
if(!q->locked) {
q->locked = 1;
unlock(&q->use);
return;
}
if(up == 0)
panic("eqlock");
if(up->notepending){
unlock(&q->use);
error(Eintr);
}
rwstats.qlockq++;
p = q->tail;
if(p == 0)
q->head = up;
else
p->qnext = up;
q->tail = up;
up->qnext = 0;
up->qpc = getcallerpc(&q);
up->state = Queueing;
lock(&up->rlock);
up->eql = q;
unlock(&up->rlock);
unlock(&q->use);
sched();
if(up->notepending){
up->notepending = 0;
error(Eintr);
}
}
void
qlock(QLock *q)
{
@ -73,6 +128,12 @@ qunlock(QLock *q)
getcallerpc(&q));
p = q->head;
if(p){
if(p->eql){
lock(&p->rlock);
if(p->eql == q)
p->eql = 0;
unlock(&p->rlock);
}
q->head = p->qnext;
if(q->head == 0)
q->tail = 0;