summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@centraldogma>2011-11-02 21:39:30 +0100
committercinap_lenrek <cinap_lenrek@centraldogma>2011-11-02 21:39:30 +0100
commit4c05d129e20a90a2aa25d2ad947d920f5e24a1ee (patch)
tree23c3ca544f59c96fcc303323eec3ad89d1346c7d
parentb2ba90e7b6b0fc0941a2061ab038917861887f2d (diff)
eqlock: fix postnote/qunlock race
-rw-r--r--sys/src/9/port/portdat.h1
-rw-r--r--sys/src/9/port/proc.c45
-rw-r--r--sys/src/9/port/qlock.c19
3 files changed, 25 insertions, 40 deletions
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 2fcb37b0b..5aca7fb14 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -736,7 +736,6 @@ struct Proc
ulong qpc; /* pc calling last blocking qlock */
QLock *eql; /* interruptable eqlock */
- Lock eqlock;
int setargs;
diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c
index 99000a6fa..f2045e840 100644
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -948,38 +948,35 @@ postnote(Proc *p, int dolock, char *n, int flag)
unlock(&p->rlock);
splx(s);
-Pullout:
switch(p->state){
case Queueing:
/* Try and pull out of a eqlock */
- lock(&p->eqlock);
- if(p->state == Queueing && p->eql && p->notepending){
- Proc *d, *l;
+ if(p->notepending){
QLock *q;
- q = p->eql;
- if(!canlock(&q->use)){
- unlock(&p->eqlock);
- sched();
- goto Pullout;
- }
-
- 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;
+ if((q = p->eql) == nil)
+ break;
+ lock(&q->use);
+ if(p->state == Queueing && p->eql == q && p->notepending){
+ Proc *d, *l;
+
+ 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; /* not taken */
+ ready(p);
+ break;
+ }
}
+ }
unlock(&q->use);
}
- unlock(&p->eqlock);
break;
case Rendezvous:
/* Try and pull out of a rendezvous */
diff --git a/sys/src/9/port/qlock.c b/sys/src/9/port/qlock.c
index d41768435..ece5488b1 100644
--- a/sys/src/9/port/qlock.c
+++ b/sys/src/9/port/qlock.c
@@ -42,28 +42,22 @@ eqlock(QLock *q)
error(Eintr);
}
rwstats.qlockq++;
-
p = q->tail;
if(p == 0)
q->head = up;
else
p->qnext = up;
q->tail = up;
-
+ up->eql = q;
up->qnext = 0;
up->qpc = getcallerpc(&q);
up->state = Queueing;
-
- lock(&up->eqlock);
- up->eql = q;
- unlock(&up->eqlock);
-
unlock(&q->use);
-
sched();
-
if(up->notepending){
up->notepending = 0;
+ if(up->eql == q)
+ qunlock(q);
error(Eintr);
}
}
@@ -96,6 +90,7 @@ qlock(QLock *q)
else
p->qnext = up;
q->tail = up;
+ up->eql = 0;
up->qnext = 0;
up->state = Queueing;
up->qpc = getcallerpc(&q);
@@ -128,12 +123,6 @@ qunlock(QLock *q)
getcallerpc(&q));
p = q->head;
if(p){
- if(p->eql){
- lock(&p->eqlock);
- if(p->eql == q)
- p->eql = 0;
- unlock(&p->eqlock);
- }
q->head = p->qnext;
if(q->head == 0)
q->tail = 0;