From 70e4b8d1f957b900f784d9f7205ab2a96d7e440a Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Wed, 10 Aug 2011 16:21:17 +0200 Subject: [PATCH] added eqlock(), a interruptable version of qlock. addresses issue #81 --- sys/src/9/port/devaudio.c | 4 +-- sys/src/9/port/devmnt.c | 2 +- sys/src/9/port/portdat.h | 1 + sys/src/9/port/portfns.h | 1 + sys/src/9/port/proc.c | 67 +++++++++++++++++++++++++++++---------- sys/src/9/port/qio.c | 6 ++-- sys/src/9/port/qlock.c | 61 +++++++++++++++++++++++++++++++++++ 7 files changed, 120 insertions(+), 22 deletions(-) diff --git a/sys/src/9/port/devaudio.c b/sys/src/9/port/devaudio.c index 5dd1065d0..c9fbcad30 100644 --- a/sys/src/9/port/devaudio.c +++ b/sys/src/9/port/devaudio.c @@ -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(); diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c index 129d06e2a..6f06e0d55 100644 --- a/sys/src/9/port/devmnt.c +++ b/sys/src/9/port/devmnt.c @@ -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(); diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h index bef56c086..633ce28d0 100644 --- a/sys/src/9/port/portdat.h +++ b/sys/src/9/port/portdat.h @@ -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; diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 6e6653901..a62e24040 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -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); diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c index de08fe72d..2cfa6faec 100644 --- a/sys/src/9/port/proc.c +++ b/sys/src/9/port/proc.c @@ -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; } diff --git a/sys/src/9/port/qio.c b/sys/src/9/port/qio.c index aa4de59f3..c91cad04c 100644 --- a/sys/src/9/port/qio.c +++ b/sys/src/9/port/qio.c @@ -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); diff --git a/sys/src/9/port/qlock.c b/sys/src/9/port/qlock.c index 3d666516d..9c0059044 100644 --- a/sys/src/9/port/qlock.c +++ b/sys/src/9/port/qlock.c @@ -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;