M boot/boot.c => boot/boot.c +95 -3
@@ 25,9 25,96 @@ static void recover(Method*);
static Method *rootserver(char*);
void
+pipetest(void)
+{
+ int i, n, p[2];
+ ulong buf[1];
+
+ if(bind("#c", "/dev", MREPL) < 0)
+ print("can't bind #c\n");
+
+ if(pipe(p) < 0){
+ print("pipe fails\n");
+ exits(0);
+ }
+ switch(fork()){
+ case -1:
+ print("fork fails\n");
+ exits(0);
+ case 0:
+ close(p[0]);
+ for(;;){
+ n = read(p[1], buf, 1);
+ if(n <= 0){
+ print("1 exiting %d\n", time(0));
+ exits(0);
+ }
+ write(p[1], buf, 1);
+ }
+ default:
+ close(p[1]);
+ print("start %d\n", time(0));
+ for(i = 0; i < 100000; i++){
+ if(write(p[0], buf, 1) != 1){
+ print("sndr broke\n");
+ exits(0);
+ }
+ n = read(p[0], buf, 1);
+ if(n <= 0){
+ print("0 exiting %d\n", time(0));
+ exits(0);
+ }
+ }
+ close(p[0]);
+ sleep(1000);
+ }
+}
+
+void
+pipetest2(void)
+{
+ int i, n, p[2];
+ uchar buf[4096];
+
+ if(bind("#c", "/dev", MREPL) < 0)
+ print("can't bind #c\n");
+
+ if(pipe(p) < 0){
+ print("pipe fails\n");
+ exits(0);
+ }
+ switch(fork()){
+ case -1:
+ print("fork fails\n");
+ exits(0);
+ case 0:
+ close(p[0]);
+ for(;;){
+ n = read(p[1], buf, sizeof(buf));
+ if(n <= 0){
+ print("1 exiting %d\n", time(0));
+ exits(0);
+ }
+ }
+ default:
+ close(p[1]);
+ print("start %d\n", time(0));
+ for(i = 0; i < 40000; i++){
+ if(write(p[0], buf, sizeof(buf)) != sizeof(buf)){
+ print("sndr broke\n");
+ exits(0);
+ }
+ }
+ close(p[0]);
+ sleep(1000);
+ }
+
+}
+
+void
ethertest(void)
{
- int cf, df, n, t;
+ int cf, df, n, t, i;
char buf[64];
struct Etherpkt
{
@@ 58,7 145,7 @@ ethertest(void)
exits(0);
}
close(cf);
- for(;;){
+ for(i=0;i<20;i++){
n = read(df, &p, sizeof(p));
if(n <= 0){
print("read returns %d: %r\n", n);
@@ 67,6 154,7 @@ ethertest(void)
t = (p.type[0]<<8) | p.type[1];
print("%d %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux -> %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux %ux\n", n, p.s[0], p.s[1], p.s[2], p.s[3], p.s[4], p.s[5], p.d[0], p.d[1], p.d[2], p.d[3], p.d[4], p.d[5], t);
}
+ close(df);
}
void
@@ 83,11 171,15 @@ boot(int argc, char *argv[])
open("#c/cons", OREAD);
open("#c/cons", OWRITE);
open("#c/cons", OWRITE);
+#ifdef DEBUG
print("argc=%d\n", argc);
for(fd = 0; fd < argc; fd++)
print("%s ", argv[fd]);
- print("\n");/**/
+ print("\n");
+#endif DEBUG
+ pipetest();
+ pipetest2();
ethertest();
if(argc <= 1)
M port/devpipe.c => port/devpipe.c +120 -138
@@ 6,14 6,17 @@
#include "../port/error.h"
#include "devtab.h"
+#include "netif.h"
typedef struct Pipe Pipe;
struct Pipe
{
- Ref;
QLock;
Pipe *next;
+ int ref;
ulong path;
+ Queue *q[2];
+ int qref[2];
};
struct
@@ 23,26 26,17 @@ struct
ulong path;
} pipealloc;
-static Pipe *getpipe(ulong);
-static void pipeiput(Queue*, Block*);
-static void pipeoput(Queue*, Block*);
-static void pipestclose(Queue *);
-
-Qinfo pipeinfo =
+enum
{
- pipeiput,
- pipeoput,
- 0,
- pipestclose,
- "pipe"
+ Qdir,
+ Qdata0,
+ Qdata1,
};
Dirtab pipedir[] =
{
- "data", {Sdataqid}, 0, 0600,
- "ctl", {Sctlqid}, 0, 0600,
- "data1", {Sdataqid}, 0, 0600,
- "ctl1", {Sctlqid}, 0, 0600,
+ "data", {Qdata0}, 0, 0600,
+ "data1", {Qdata1}, 0, 0600,
};
#define NPIPEDIR 4
@@ 66,16 60,33 @@ pipeattach(char *spec)
Chan *c;
c = devattach('|', spec);
- p = smalloc(sizeof(Pipe));
+ p = malloc(sizeof(Pipe));
+ if(p == 0)
+ exhausted("memory");
p->ref = 1;
+ p->q[0] = qopen(64*1024, 0, 0);
+ if(p->q[0] == 0){
+ free(p);
+ exhausted("memory");
+ }
+ p->q[0]->state &= ~Qmsg;
+ p->q[1] = qopen(32*1024, 0, 0);
+ if(p->q[1] == 0){
+ free(p->q[0]);
+ free(p);
+ exhausted("memory");
+ }
+ p->q[1]->state &= ~Qmsg;
+
lock(&pipealloc);
p->path = ++pipealloc.path;
p->next = pipealloc.pipe;
pipealloc.pipe = p;
unlock(&pipealloc);
- c->qid = (Qid){CHDIR|STREAMQID(2*p->path, 0), 0};
+ c->qid = (Qid){CHDIR|NETQID(2*p->path, Qdir), 0};
+ c->aux = p;
c->dev = 0;
return c;
}
@@ 85,10 96,11 @@ pipeclone(Chan *c, Chan *nc)
{
Pipe *p;
- p = getpipe(STREAMID(c->qid.path)/2);
+ p = c->aux;
nc = devclone(c, nc);
- if(incref(p) <= 1)
- panic("pipeclone");
+ qlock(p);
+ p->ref++;
+ qunlock(p);
return nc;
}
@@ 97,13 109,13 @@ pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
int id;
- id = STREAMID(c->qid.path);
+ id = NETID(c->qid.path);
if(i > 1)
id++;
if(tab==0 || i>=ntab)
return -1;
tab += i;
- devdir(c, (Qid){STREAMQID(id, tab->qid.path),0}, tab->name, tab->length, eve, tab->perm, dp);
+ devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, tab->length, eve, tab->perm, dp);
return 1;
}
@@ 117,7 129,25 @@ pipewalk(Chan *c, char *name)
void
pipestat(Chan *c, char *db)
{
- streamstat(c, db, "pipe", 0666);
+ Pipe *p;
+ Dir dir;
+
+ p = c->aux;
+
+ switch(NETTYPE(c->qid.path)){
+ case Qdir:
+ devdir(c, c->qid, ".", 2*DIRLEN, eve, CHDIR|0555, &dir);
+ break;
+ case Qdata0:
+ devdir(c, c->qid, "data", p->q[0]->len, eve, 0660, &dir);
+ break;
+ case Qdata1:
+ devdir(c, c->qid, "data1", p->q[1]->len, eve, 0660, &dir);
+ break;
+ default:
+ panic("pipestat");
+ }
+ convD2M(&dir, db);
}
/*
@@ 127,8 157,6 @@ Chan *
pipeopen(Chan *c, int omode)
{
Pipe *p;
- int other;
- Stream *local, *remote;
if(c->qid.path & CHDIR){
if(omode != OREAD)
@@ 139,36 167,17 @@ pipeopen(Chan *c, int omode)
return c;
}
- p = getpipe(STREAMID(c->qid.path)/2);
- if(waserror()){
- qunlock(p);
- nexterror();
- }
+ p = c->aux;
qlock(p);
- streamopen(c, &pipeinfo);
- local = c->stream;
- if(local->devq->ptr == 0){
- /*
- * first open, create the other end also
- */
- other = STREAMID(c->qid.path)^1;
- remote = streamnew(c->type, c->dev, other, &pipeinfo,1);
-
- /*
- * connect the device ends of both streams
- */
- local->devq->ptr = remote;
- remote->devq->ptr = local;
- local->devq->other->next = remote->devq;
- remote->devq->other->next = local->devq;
- } else if(local->opens == 1){
- /*
- * keep other side around till last close of this side
- */
- streamenter(local->devq->ptr);
+ switch(NETTYPE(c->qid.path)){
+ case Qdata0:
+ p->qref[0]++;
+ break;
+ case Qdata1:
+ p->qref[1]++;
+ break;
}
qunlock(p);
- poperror();
c->mode = omode&~OTRUNC;
c->flag |= COPEN;
@@ 201,27 210,44 @@ void
pipeclose(Chan *c)
{
Pipe *p, *f, **l;
- Stream *remote;
- p = getpipe(STREAMID(c->qid.path)/2);
+ p = c->aux;
+ qlock(p);
/*
- * take care of local and remote streams
+ * closing either side hangs up the stream
*/
- if(c->stream){
- qlock(p);
- remote = c->stream->devq->ptr;
- if(streamclose(c) == 0){
- if(remote)
- streamexit(remote);
+ switch(NETTYPE(c->qid.path)){
+ case Qdata0:
+ p->qref[0]--;
+ if(p->qref[0] == 0){
+ qclose(p->q[0]);
+ qhangup(p->q[1]);
}
- qunlock(p);
+ break;
+ case Qdata1:
+ p->qref[1]--;
+ if(p->qref[1] == 0){
+ qclose(p->q[1]);
+ qhangup(p->q[0]);
+ }
+ break;
}
/*
- * free the structure
+ * if both sides are closed, they are reusable
*/
- if(decref(p) == 0){
+ if(p->qref[0] == 0 && p->qref[1] == 0){
+ qreopen(p->q[0]);
+ qreopen(p->q[1]);
+ }
+
+ /*
+ * free the structure on last close
+ */
+ p->ref--;
+ if(p->ref == 0){
+ qunlock(p);
lock(&pipealloc);
l = &pipealloc.pipe;
for(f = *l; f; f = f->next) {
@@ 232,18 258,34 @@ pipeclose(Chan *c)
l = &f->next;
}
unlock(&pipealloc);
+ free(p->q[0]);
+ free(p->q[1]);
free(p);
}
+
+ qunlock(p);
}
long
piperead(Chan *c, void *va, long n, ulong offset)
{
+ Pipe *p;
+
USED(offset);
- if(c->qid.path & CHDIR)
- return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
- return streamread(c, va, n);
+ p = c->aux;
+
+ switch(NETTYPE(c->qid.path)){
+ case Qdir:
+ return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
+ case Qdata0:
+ return qread(p->q[0], va, n);
+ case Qdata1:
+ return qread(p->q[1], va, n);
+ default:
+ panic("piperead");
+ }
+ return -1; /* not reached */
}
/*
@@ 253,79 295,19 @@ piperead(Chan *c, void *va, long n, ulong offset)
long
pipewrite(Chan *c, void *va, long n, ulong offset)
{
+ Pipe *p;
+
USED(offset);
- /* avoid notes when pipe is a mounted stream */
- if(c->flag & CMSG)
- return streamwrite(c, va, n, 0);
+ p = c->aux;
- if(waserror()) {
- postnote(up, 1, "sys: write on closed pipe", NUser);
- error(Egreg);
+ switch(NETTYPE(c->qid.path)){
+ case Qdata0:
+ return qwrite(p->q[1], va, n);
+ case Qdata1:
+ return qwrite(p->q[0], va, n);
+ default:
+ panic("piperead");
}
- n = streamwrite(c, va, n, 0);
- poperror();
return n;
}
-
-/*
- * send a block upstream to the process.
- * sleep until there's room upstream.
- */
-static void
-pipeiput(Queue *q, Block *bp)
-{
- FLOWCTL(q, bp);
-}
-
-/*
- * send the block to the other side
- */
-static void
-pipeoput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-/*
- * send a hangup and disconnect the streams
- */
-static void
-pipestclose(Queue *q)
-{
- Block *bp;
-
- /*
- * point to the bit-bucket and let any in-progress
- * write's finish.
- */
- q->put = nullput;
- wakeup(&q->r);
-
- /*
- * send a hangup
- */
- q = q->other;
- if(q->next == 0)
- return;
- bp = allocb(0);
- bp->type = M_HANGUP;
- PUTNEXT(q, bp);
-}
-
-Pipe*
-getpipe(ulong path)
-{
- Pipe *p;
-
- lock(&pipealloc);
- for(p = pipealloc.pipe; p; p = p->next) {
- if(path == p->path) {
- unlock(&pipealloc);
- return p;
- }
- }
- unlock(&pipealloc);
- panic("getpipe");
- return 0; /* not reached */
-}
M port/netif.c => port/netif.c +4 -0
@@ 269,6 269,8 @@ netifclose(Netif *nif, Chan *c)
qunlock(nif);
}
f->owner[0] = 0;
+ f->type = 0;
+ qclose(f->in);
}
qunlock(f);
}
@@ 320,6 322,7 @@ openfile(Netif *nif, int id)
if(f == 0)
error(Enodev);
qlock(f);
+ qreopen(f->in);
f->inuse++;
qunlock(f);
return id;
@@ 346,6 349,7 @@ openfile(Netif *nif, int id)
}
}
f->inuse = 1;
+ qreopen(f->in);
netown(f, up->user, 0);
qunlock(f);
qunlock(nif);
M port/portdat.h => port/portdat.h +8 -8
@@ 656,11 656,6 @@ struct Block
struct Queue
{
Lock;
- QLock rlock; /* mutex for reading processes */
- QLock wlock; /* mutex for writing processes */
-
- Block *rfirst; /* waiting readers */
- Block *rlast;
Block *bfirst; /* buffer */
Block *blast;
@@ 672,7 667,10 @@ struct Queue
void (*kick)(void*); /* restart output */
void *arg; /* argument to kick */
- Rendez r;
+ QLock rlock; /* mutex for reading processes */
+ Rendez rr; /* process waiting to read */
+ QLock wlock; /* mutex for writing processes */
+ Rendez wr; /* process waiting to write */
};
enum
@@ 681,8 679,10 @@ enum
Bfilled=1, /* block filled */
/* Queue.state */
- Qstarve=1, /* consumer starved */
- Qmsg=2, /* message stream */
+ Qstarve= (1<<0), /* consumer starved */
+ Qmsg= (1<<1), /* message stream */
+ Qclosed= (1<<2),
+ Qflow= (1<<3),
};
M port/portfns.h => port/portfns.h +3 -0
@@ 170,11 170,14 @@ void putstr(char*);
void putstrn(char*, long);
void putswap(Page*);
ulong pwait(Waitmsg*);
+void qclose(Queue*);
int qconsume(Queue*, uchar*, int);
+void qhangup(Queue*);
void qlock(QLock*);
Queue* qopen(int, void (*)(void*), void*);
int qproduce(Queue*, uchar*, int);
long qread(Queue*, char*, int);
+void qreopen(Queue*);
void qunlock(QLock*);
long qwrite(Queue*, char*, int);
int readnum(ulong, char*, ulong, ulong, int);
M port/proc.c => port/proc.c +2 -0
@@ 160,6 160,8 @@ loop:
/* p->mach==0 only when process state is saved */
if(p == 0 || p->mach){
unlock(&runhiq);
+ if(conf.nmach > 1)
+ delay(7); /* keep off the bus (tuned for everest) */
goto loop;
}
if(p->rnext == 0)
M port/qio.c => port/qio.c +163 -216
@@ 150,10 150,10 @@ iallocb(int size)
cl->first = p->next;
unlock(cl);
b = (Block *)p;
+ memset(b, 0, sizeof(Block));
b->base = (uchar*)(b+1);
b->wp = b->rp = b->base;
b->lim = b->base + (1<<pow) - sizeof(Block);
- b->flag = 0;
return b;
}
panic("iallocb %d\n", size);
@@ 186,6 186,7 @@ allocb(int size)
if(b == 0)
exhausted("Blocks");
+ memset(b, 0, sizeof(Block));
b->base = (uchar*)(b+1);
b->rp = b->wp = b->base;
b->lim = b->base + size;
@@ 202,7 203,7 @@ int
qconsume(Queue *q, uchar *p, int len)
{
Block *b;
- int n;
+ int n, dowakeup;
/* sync with qwrite */
lock(q);
@@ 213,6 214,7 @@ qconsume(Queue *q, uchar *p, int len)
unlock(q);
return -1;
}
+
n = BLEN(b);
if(n < len)
len = n;
@@ 223,42 225,34 @@ qconsume(Queue *q, uchar *p, int len)
b->rp += len;
q->len -= len;
- /* wakeup flow controlled writers (with a bit of histeresis) */
- if(q->len+len >= q->limit && q->len < q->limit/2)
- wakeup(&q->r);
+ /* if writer flow controlled, restart */
+ if((q->state & Qflow) && q->len < q->limit/2){
+ q->state &= ~Qflow;
+ dowakeup = 1;
+ } else
+ dowakeup = 0;
unlock(q);
+ if(dowakeup)
+ wakeup(&q->wr);
+
+ /* discard the block if we're done with it */
if((q->state & Qmsg) || len == n)
ifree(b);
return len;
}
-static int
-qproduce0(Queue *q, uchar *p, int len)
+int
+qproduce(Queue *q, uchar *p, int len)
{
Block *b;
- int n;
+ int dowakeup;
/* sync with qread */
lock(q);
- b = q->rfirst;
- if(b){
- /* hand to waiting receiver */
- q->rfirst = b->next;
- unlock(q);
- n = b->lim - b->wp;
- if(n < len)
- len = n;
- memmove(b->wp, p, len);
- b->wp += len;
- b->flag |= Bfilled;
- wakeup(&b->r);
- return len;
- }
-
/* no waiting receivers, room in buffer? */
if(q->len >= q->limit){
unlock(q);
@@ 279,7 273,6 @@ qproduce0(Queue *q, uchar *p, int len)
}
memmove(b->wp, p, len);
b->wp += len;
- b->flag |= Bfilled;
if(q->bfirst)
q->blast->next = b;
else
@@ 287,24 280,17 @@ qproduce0(Queue *q, uchar *p, int len)
q->blast = b;
}
q->len += len;
+ if(q->state & Qstarve){
+ q->state &= ~Qstarve;
+ dowakeup = 1;
+ } else
+ dowakeup = 0;
unlock(q);
- return len;
-}
-
-int
-qproduce(Queue *q, uchar *p, int len)
-{
- int n, sofar;
+ if(dowakeup)
+ wakeup(&q->rr);
- sofar = 0;
- do {
- n = qproduce0(q, p + sofar, len - sofar);
- if(n < 0)
- break;
- sofar += n;
- } while(sofar < len && (q->state & Qmsg) == 0);
- return sofar;
+ return len;
}
/*
@@ 317,7 303,9 @@ qopen(int limit, void (*kick)(void*), void *arg)
q = malloc(sizeof(Queue));
if(q == 0)
- exhausted("Queues");
+ return 0;
+
+ memset(q, 0, sizeof(Queue));
q->limit = limit;
q->kick = kick;
q->arg = arg;
@@ 326,248 314,207 @@ qopen(int limit, void (*kick)(void*), void *arg)
return q;
}
-ulong qrtoomany;
-ulong qrtoofew;
-
static int
-bfilled(void *a)
+notempty(void *a)
{
- Block *b = a;
+ Queue *q = a;
- return b->flag & Bfilled;
+ return q->bfirst != 0;
}
+/*
+ * read a queue. if no data is queued, post a Block
+ * and wait on its Rendez.
+ */
long
qread(Queue *q, char *p, int len)
{
- Block *b, *bb, **l;
- int x, n;
+ Block *b;
+ int x, n, dowakeup;
qlock(&q->rlock);
- b = 0;
if(waserror()){
qunlock(&q->rlock);
- if(b)
- free(b);
nexterror();
}
- /*
- * If there are no buffered blocks, allocate a block
- * for the qproducer/qwrite to fill. This is
- * optimistic and and we will
- * sometimes be wrong: after locking we may either
- * have to throw away or allocate one.
- *
- * We hope to replace the allocb with a kmap later on.
- */
-retry:
- if(q->bfirst == 0)
- b = allocb(len);
-
- /* sync with qwrite/qproduce */
- x = splhi();
- lock(q);
+ /* wait for data */
+ for(;;){
+ /* sync with qwrite/qproduce */
+ x = splhi();
+ lock(q);
- bb = q->bfirst;
- if(bb == 0){
- if(b == 0){
- /* we guessed wrong, drop the locks and try again */
+ if(q->state & Qclosed){
unlock(q);
splx(x);
- qrtoofew++;
- goto retry;
+ return 0;
}
- /* add ourselves to the list of readers */
- if(q->rfirst)
- q->rlast->next = b;
- else
- q->rfirst = b;
- q->rlast = b;
+ b = q->bfirst;
+ if(b)
+ break;
+ q->state |= Qstarve;
unlock(q);
splx(x);
- qunlock(&q->rlock);
- poperror();
-
- if(waserror()){
- /* on error, unlink us from the chain */
- x = splhi();
- lock(q);
- l = &q->rfirst;
- for(bb = q->rfirst; bb; bb = bb->next){
- if(b == bb){
- *l = bb->next;
- break;
- } else
- l = &bb->next;
- }
- unlock(q);
- splx(x);
- free(b);
- nexterror();
- }
-
- /* wait for the producer */
- sleep(&b->r, bfilled, b);
- n = BLEN(b);
- memmove(p, b->rp, n);
- poperror();
- free(b);
-
- return n;
+ sleep(&q->rr, notempty, q);
}
- /* copy from a buffered block */
- q->bfirst = bb->next;
- n = BLEN(bb);
- if(n > len)
- n = len;
+ /* remove a buffered block */
+ q->bfirst = b->next;
+ n = BLEN(b);
q->len -= n;
+
+ /* if writer flow controlled, restart */
+ if((q->state & Qflow) && q->len < q->limit/2){
+ q->state &= ~Qflow;
+ dowakeup = 1;
+ } else
+ dowakeup = 0;
unlock(q);
splx(x);
/* do this outside of the lock(q)! */
- memmove(p, bb->rp, n);
- bb->rp += n;
+ if(n > len)
+ n = len;
+ memmove(p, b->rp, n);
+ b->rp += n;
- /* free it or put it back on the queue */
- if(bb->rp >= bb->wp || (q->state&Qmsg))
- free(bb);
+ /* free it or put it what's left on the queue */
+ if(b->rp >= b->wp || (q->state&Qmsg))
+ free(b);
else {
x = splhi();
lock(q);
- bb->next = q->bfirst;
- q->bfirst = bb;
+ b->next = q->bfirst;
+ q->bfirst = b;
+ q->len += BLEN(b);
unlock(q);
splx(x);
}
+ /* wakeup flow controlled writers (with a bit of histeresis) */
+ if(dowakeup)
+ wakeup(&q->wr);
+
poperror();
qunlock(&q->rlock);
- if(b){
- qrtoomany++;
- free(b);
- }
return n;
}
-ulong qwtoomany;
-ulong qwtoofew;
-
-static long
-qwrite0(Queue *q, char *p, int len, Block *b)
+static int
+qnotfull(void *a)
{
- Block *bb;
- int x, n, sofar;
+ Queue *q = a;
- /* sync with qconsume/qread */
- x = splhi();
- lock(q);
+ return q->len < q->limit;
+}
- sofar = 0;
- while(bb = q->rfirst){
- /* hand to waiting receiver */
- q->rfirst = bb->next;
- unlock(q);
- splx(x);
+/*
+ * write to a queue. if no reader blocks are posted
+ * queue the data.
+ */
+long
+qwrite(Queue *q, char *p, int len)
+{
+ int x, dowakeup;
+ Block *b;
- n = bb->lim - bb->wp;
- if(n > len-sofar)
- n = len - sofar;
- memmove(bb->wp, p+sofar, n);
- bb->wp += n;
- bb->flag |= Bfilled;
- wakeup(&bb->r);
-
- sofar += n;
- if(sofar == len){
- if(b){
- free(b); /* we were wrong to allocate */
- qwtoomany++;
- }
- return len;
- }
+ b = allocb(len);
+ memmove(b->wp, p, len);
+ b->wp += len;
+
+ /* flow control */
+ while(!qnotfull(q)){
+ qlock(&q->wlock);
+ q->state |= Qflow;
+ sleep(&q->wr, qnotfull, q);
+ qunlock(&q->wlock);
}
- /* buffer what ever is left */
- if(b == 0){
- /* we should have alloc'd, return to qwrite and have it do it */
+ x = splhi();
+ lock(q);
+
+ if(q->state & Qclosed){
unlock(q);
splx(x);
- qwtoofew++;
- return sofar;
+ error(Ehungup);
}
- b->rp += sofar;
- x = splhi();
- lock(q);
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
+ b->next = q->bfirst;
+ q->bfirst = b;
q->len += len;
- if((q->state & Qstarve) && q->kick){
+
+ if(q->state & Qstarve){
q->state &= ~Qstarve;
- (*q->kick)(q->arg);
- }
+ dowakeup = 1;
+ } else
+ dowakeup = 0;
+
unlock(q);
splx(x);
+ if(dowakeup)
+ wakeup(&q->rr);
+
return len;
}
-static int
-qnotfull(void *a)
+/*
+ * Mark a queue as closed. No further IO is permitted.
+ * All blocks are released.
+ */
+void
+qclose(Queue *q)
{
- Queue *q = a;
+ int x;
+ Block *b, *bfirst;
- return q->len < q->limit;
-}
+ /* mark it */
+ x = splhi();
+ lock(q);
+ q->state |= Qclosed;
+ bfirst = q->bfirst;
+ q->bfirst = 0;
+ unlock(q);
+ splx(x);
-long
-qwrite(Queue *q, char *p, int len)
-{
- int n, i;
- Block *b;
+ /* free queued blocks */
+ while(b = bfirst){
+ bfirst = b->next;
+ free(b);
+ }
- /*
- * If there are no readers, grab a buffer and copy
- * into it before locking anything down. This
- * provides the highest concurrency but we will
- * sometimes be wrong: after locking we may either
- * have to throw away or allocate one.
- */
- if(q->rfirst == 0){
- b = allocb(len);
- memmove(b->wp, p, len);
- b->wp += len;
- } else
- b = 0;
+ /* wake up readers/writers */
+ wakeup(&q->rr);
+ wakeup(&q->wr);
+}
- /* ensure atomic writes */
- qlock(&q->wlock);
- if(waserror()){
- qunlock(&q->wlock);
- nexterror();
- }
+/*
+ * Mark a queue as closed. Wakeup any readers. Don't remove queued
+ * blocks.
+ */
+void
+qhangup(Queue *q)
+{
+ int x;
- /* flow control */
- sleep(&q->r, qnotfull, q);
-
- n = qwrite0(q, p, len, b);
- if(n != len){
- /* no readers and we need a buffer */
- i = len - n;
- b = allocb(i);
- memmove(b->wp, p + n, i);
- b->wp += n;
- n += qwrite0(q, p + n, i, b);
- }
+ /* mark it */
+ x = splhi();
+ lock(q);
+ q->state |= Qclosed;
+ unlock(q);
+ splx(x);
- qunlock(&q->wlock);
- poperror();
+ /* wake up readers/writers */
+ wakeup(&q->rr);
+ wakeup(&q->wr);
+}
- return n;
+/*
+ * mark a queue as no longer hung up
+ */
+void
+qreopen(Queue *q)
+{
+ q->state &= ~Qclosed;
}
M port/taslock.c => port/taslock.c +1 -1
@@ 13,7 13,7 @@ lock(Lock *l)
pc = getcallerpc(((uchar*)&l) - sizeof(l));
- for(i = 0; i < 10000000; i++){
+ for(i = 0; i < 20000000; i++){
if (tas(&l->key) == 0){
l->pc = pc;
return;