eqlock: fix postnote/qunlock race

This commit is contained in:
cinap_lenrek 2011-11-02 21:39:30 +01:00
parent b2ba90e7b6
commit 4c05d129e2
3 changed files with 24 additions and 39 deletions

View file

@ -736,7 +736,6 @@ struct Proc
ulong qpc; /* pc calling last blocking qlock */ ulong qpc; /* pc calling last blocking qlock */
QLock *eql; /* interruptable eqlock */ QLock *eql; /* interruptable eqlock */
Lock eqlock;
int setargs; int setargs;

View file

@ -948,38 +948,35 @@ postnote(Proc *p, int dolock, char *n, int flag)
unlock(&p->rlock); unlock(&p->rlock);
splx(s); splx(s);
Pullout:
switch(p->state){ switch(p->state){
case Queueing: case Queueing:
/* Try and pull out of a eqlock */ /* Try and pull out of a eqlock */
lock(&p->eqlock); if(p->notepending){
if(p->state == Queueing && p->eql && p->notepending){
Proc *d, *l;
QLock *q; QLock *q;
q = p->eql; if((q = p->eql) == nil)
if(!canlock(&q->use)){ break;
unlock(&p->eqlock); lock(&q->use);
sched(); if(p->state == Queueing && p->eql == q && p->notepending){
goto Pullout; Proc *d, *l;
}
for(l = nil, d = q->head; d; l = d, d = d->qnext) for(l = nil, d = q->head; d; l = d, d = d->qnext){
if(d == p){ if(d == p){
if(l) if(l)
l->qnext = p->qnext; l->qnext = p->qnext;
else else
q->head = p->qnext; q->head = p->qnext;
if(p->qnext == 0) if(p->qnext == 0)
q->tail = l; q->tail = l;
p->qnext = 0; p->qnext = 0;
p->eql = 0; p->eql = 0; /* not taken */
ready(p); ready(p);
break; break;
}
} }
}
unlock(&q->use); unlock(&q->use);
} }
unlock(&p->eqlock);
break; break;
case Rendezvous: case Rendezvous:
/* Try and pull out of a rendezvous */ /* Try and pull out of a rendezvous */

View file

@ -42,28 +42,22 @@ eqlock(QLock *q)
error(Eintr); error(Eintr);
} }
rwstats.qlockq++; rwstats.qlockq++;
p = q->tail; p = q->tail;
if(p == 0) if(p == 0)
q->head = up; q->head = up;
else else
p->qnext = up; p->qnext = up;
q->tail = up; q->tail = up;
up->eql = q;
up->qnext = 0; up->qnext = 0;
up->qpc = getcallerpc(&q); up->qpc = getcallerpc(&q);
up->state = Queueing; up->state = Queueing;
lock(&up->eqlock);
up->eql = q;
unlock(&up->eqlock);
unlock(&q->use); unlock(&q->use);
sched(); sched();
if(up->notepending){ if(up->notepending){
up->notepending = 0; up->notepending = 0;
if(up->eql == q)
qunlock(q);
error(Eintr); error(Eintr);
} }
} }
@ -96,6 +90,7 @@ qlock(QLock *q)
else else
p->qnext = up; p->qnext = up;
q->tail = up; q->tail = up;
up->eql = 0;
up->qnext = 0; up->qnext = 0;
up->state = Queueing; up->state = Queueing;
up->qpc = getcallerpc(&q); up->qpc = getcallerpc(&q);
@ -128,12 +123,6 @@ qunlock(QLock *q)
getcallerpc(&q)); getcallerpc(&q));
p = q->head; p = q->head;
if(p){ if(p){
if(p->eql){
lock(&p->eqlock);
if(p->eql == q)
p->eql = 0;
unlock(&p->eqlock);
}
q->head = p->qnext; q->head = p->qnext;
if(q->head == 0) if(q->head == 0)
q->tail = 0; q->tail = 0;