M gnot/devincon.c => gnot/devincon.c +13 -11
@@ 409,7 409,7 @@ inconread(Chan *c, void *buf, long n, ulong offset)
i = &incon[c->dev];
sprint(b, "in: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", i->in,
i->out, i->overflow, i->crc, i->wait);
- return stringread(buf, n, b, offset);
+ return readstr(offset, buf, n, b);
} else
return streamread(c, buf, n);
}
@@ 525,6 525,13 @@ inconoput(Queue *q, Block *bp)
freeb(bp);
return;
}
+ if(BLEN(bp) < 3){
+ bp = pullup(bp, 3);
+ if(bp == 0){
+ print("inconoput pullup failed\n");
+ return;
+ }
+ }
/*
* get a whole message before handing bytes to the device
@@ 542,11 549,6 @@ inconoput(Queue *q, Block *bp)
* parse message
*/
bp = getq(q);
- if(bp->wptr - bp->rptr < 3){
- freemsg(q, bp);
- qunlock(&ip->xmit);
- return;
- }
chan = bp->rptr[0] | (bp->rptr[1]<<8);
ctl = bp->rptr[2];
bp->rptr += 3;
@@ 767,15 769,15 @@ nextin(Incon *ip, unsigned int c)
int next;
bp = ip->inb[ip->wi];
- bp->base[0] = ip->chan;
- bp->base[1] = ip->chan>>8;
- bp->base[2] = c;
+ bp->rptr[0] = ip->chan;
+ bp->rptr[1] = ip->chan>>8;
+ bp->rptr[2] = c;
if(incondebug)
print("<-(%d)%uo %d\n", ip->chan, c, bp->wptr-bp->rptr);
next = (ip->wi+1)%Nin;
if(next == ip->ri){
- bp->wptr = bp->base+3;
+ bp->wptr = bp->rptr+3;
return bp;
}
ip->wi = next;
@@ 862,7 864,7 @@ rdpackets(Incon *ip)
}
}
bp->wptr = p;
- if(bp->wptr != bp->base+3)
+ if(bp->wptr != bp->rptr+3)
nextin(ip, 0);
if(first != ip->wi)/**/
M gnot/main.c => gnot/main.c +4 -2
@@ 161,8 161,10 @@ userinit(void)
p = newproc();
p->pgrp = newpgrp();
- p->egrp = newegrp();
- p->fgrp = newfgrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
+ p->fgrp = smalloc(sizeof(Fgrp));
+ p->fgrp->ref = 1;
p->procmode = 0640;
strcpy(p->text, "*init*");
M pc/devincon.c => pc/devincon.c +7 -5
@@ 730,6 730,13 @@ inconoput(Queue *q, Block *bp)
freeb(bp);
return;
}
+ if(BLEN(bp) < 3){
+ bp = pullup(bp, 3);
+ if(bp == 0){
+ print("inconoput pullup failed\n");
+ return;
+ }
+ }
/*
* get a whole message before handing bytes to the device
@@ 747,11 754,6 @@ inconoput(Queue *q, Block *bp)
* parse message
*/
bp = getq(q);
- if(bp->wptr - bp->rptr < 3){
- freemsg(q, bp);
- qunlock(&ip->xmit);
- return;
- }
chan = bp->rptr[0] | (bp->rptr[1]<<8);
ctl = bp->rptr[2];
bp->rptr += 3;
M port/alloc.c => port/alloc.c +12 -1
@@ 166,11 166,11 @@ xalloc(ulong size)
h->link = xlists.flist;
xlists.flist = h;
}
+ unlock(&xlists);
p = KADDR(p);
memset(p, 0, size);
p->magix = Magichole;
p->size = size;
- unlock(&xlists);
return p->data;
}
l = &h->link;
@@ 298,6 298,17 @@ smalloc(ulong size)
return p;
}
+int
+msize(void *ptr)
+{
+ Bucket *bp;
+
+ bp = (Bucket*)((ulong)ptr - bdatoff);
+ if(bp->magic != Magic2n)
+ panic("msize");
+ return 1<<bp->size;
+}
+
void
free(void *ptr)
{
M port/devarp.c => port/devarp.c +1 -1
@@ 240,7 240,7 @@ arpread(Chan *c, void *a, long n, ulong offset)
sprint(buf, "hits: %d miss: %d failed: %d\n",
arpstats.hit, arpstats.miss, arpstats.failed);
- return stringread(a, n, buf, offset);
+ return readstr(offset, a, n, buf);
default:
n=0;
break;
M port/devdk.c => port/devdk.c +77 -134
@@ 15,7 15,7 @@ typedef struct Line Line;
typedef struct Dk Dk;
enum {
- Maxlines = 256,
+ Maxdk = 4,
};
/*
@@ 84,6 84,7 @@ struct Dkmsg {
struct Line {
QLock;
+ Netprot; /* stat info */
int lineno;
Rendez r; /* wait here for dial */
int state; /* dial state */
@@ 104,11 105,13 @@ struct Line {
* dkmux line discipline is pushed onto.
*/
struct Dk {
- QLock;
- Lock;
+ QLock netlock;
+ Network net;
+
+ QLock csclock;
Chan *csc;
- int ref;
+ Lock;
int opened;
char name[64]; /* dk name */
@@ 122,10 125,6 @@ struct Dk {
Rendez timer;
int closeall; /* set when we receive a closeall message */
Rendez closeallr; /* wait here for a closeall */
- Network net;
- Netprot *prot;
-
- Block *alloc; /* blocks containing Line structs */
};
static Dk *dk;
static Lock dklock;
@@ 209,7 208,6 @@ extern Qinfo dkinfo;
* the datakit multiplexor stream module definition
*/
static void dkmuxopen(Queue *, Stream *);
-static void dkmuxclose(Queue *);
static void dkmuxoput(Queue *, Block *);
static void dkmuxiput(Queue *, Block *);
Qinfo dkmuxinfo =
@@ 217,14 215,14 @@ Qinfo dkmuxinfo =
dkmuxiput,
dkmuxoput,
dkmuxopen,
- dkmuxclose,
+ 0,
"dkmux"
};
/*
* Look for a dk struct with a name. If none exists, create one.
*/
-static Dk *
+static Dk*
dkalloc(char *name, int ncsc, int lines)
{
Dk *dp;
@@ 234,12 232,12 @@ dkalloc(char *name, int ncsc, int lines)
lock(&dklock);
freep = 0;
- for(dp = dk; dp < &dk[conf.dkif]; dp++){
+ for(dp = dk; dp < &dk[Maxdk]; dp++){
if(strcmp(name, dp->name) == 0){
unlock(&dklock);
return dp;
}
- if(dp->name[0] == 0 && dp->ref == 0)
+ if(dp->name[0] == 0)
freep = dp;
}
if(freep == 0 || lines == 0){
@@ 247,9 245,6 @@ dkalloc(char *name, int ncsc, int lines)
error(Enoifc);
}
- /*
- * init the structures
- */
dp = freep;
dp->opened = 0;
dp->s = 0;
@@ 258,18 253,10 @@ dkalloc(char *name, int ncsc, int lines)
strncpy(dp->name, name, sizeof(freep->name));
/*
- * allocate memory for line structures
+ * allocate memory for array of pointers to lines.
+ * line structures are allocated as needed.
*/
- dp->linep = (Line **)xalloc(sizeof(Line*) * dp->lines);
- if(dp->linep == 0)
- error(Enomem);
- lp = xalloc(dp->lines*sizeof(Line));
- if(lp == 0)
- error(Enomem);
- for(i = 0; i < dp->lines; i++) {
- lp->lineno = i;
- dp->linep[i] = lp++;
- }
+ dp->linep = smalloc(sizeof(Line*) * dp->lines);
/*
* fill in the network structure
@@ 280,7 267,6 @@ dkalloc(char *name, int ncsc, int lines)
dp->net.protop = &urpinfo;
dp->net.listen = dklisten;
dp->net.clone = dkcloneline;
- dp->net.prot = dp->prot;
dp->net.ninfo = 5;
dp->net.info[0].name = "addr";
dp->net.info[0].fill = dkfilladdr;
@@ 298,50 284,42 @@ dkalloc(char *name, int ncsc, int lines)
}
/*
- * a new dkmux. hold the stream in place so it can never be closed down.
+ * allocate a line if it doesn't exist
*/
-static void
-dkmuxopen(Queue *q, Stream *s)
+static Line*
+linealloc(Dk *dp, int lineno, int dolock)
{
- RD(q)->ptr = s;
- WR(q)->ptr = 0;
+ Line *lp;
- s->opens++; /* Hold this queue in place */
- s->inuse++;
+ if(dp->opened == 0)
+ error(Enoifc);
+ if(dolock)
+ qlock(&dp->netlock);
+ if(lineno > dp->lines)
+ panic("linealloc");
+ lp = dp->linep[lineno];
+ if(lp == 0){
+ lp = smalloc(sizeof(Line));
+ lp->lineno = lineno;
+ netadd(&dp->net, lp, lineno);
+ dp->linep[lineno] = lp;
+ }
+ if(dolock)
+ qunlock(&dp->netlock);
+ return lp;
}
/*
- * close down a dkmux, this shouldn't happen
+ * a new dkmux. hold the stream in place so it can never be closed down.
*/
static void
-dkmuxclose(Queue *q)
+dkmuxopen(Queue *q, Stream *s)
{
- Dk *dp;
- int i;
-
- dp = WR(q)->ptr;
- if(dp == 0)
- return;
- dp->name[0] = 0;
-
- /*
- * disallow new dkstopens() on this line.
- * the lock syncs with dkstopen().
- */
- lock(dp);
- dp->opened = 0;
- unlock(dp);
-
- /*
- * hang up all datakit connections
- */
- for(i=dp->ncsc; i < dp->lines; i++)
- dkhangup(dp->linep[i]);
+ RD(q)->ptr = s;
+ WR(q)->ptr = 0;
- /*
- * wakeup the timer so it can die
- */
- wakeup(&dp->timer);
+ s->opens++; /* Hold this queue in place */
+ s->inuse++;
}
/*
@@ 399,8 377,8 @@ dkmuxiput(Queue *q, Block *bp)
return;
}
- lp = dp->linep[line];
- if(canqlock(lp)){
+ lp = linealloc(dp, line, 1);
+ if(lp && canqlock(lp)){
if(lp->rq)
PUTNEXT(lp->rq, bp);
else{
@@ 442,13 420,6 @@ dkstopen(Queue *q, Stream *s)
dp = &dk[s->dev];
q->other->ptr = q->ptr = lp = dp->linep[s->id];
lp->dp = dp;
- lock(dp);
- dp->ref++;
- if(dp->opened==0 || streamenter(dp->s)<0){
- unlock(dp);
- error(Ehungup);
- }
- unlock(dp);
lp->rq = q;
if(lp->state==Lclosed)
lp->state = Lopened;
@@ 476,11 447,6 @@ dkstclose(Queue *q)
}
/*
- * decrement ref count on mux'd line
- */
- streamexit(dp->s, 0);
-
- /*
* these states don't need the datakit
*/
switch(lp->state){
@@ 534,14 500,8 @@ out:
if(lp->lineno == dp->ncsc)
dp->csc = 0;
- netdisown(&dp->net, lp->lineno);
+ netdisown(lp);
lp->window = 0;
-
- lock(dp);
- dp->ref--;
- if(dp->ref == 0)
- freeb(dp->alloc);
- unlock(dp);
}
/*
@@ 557,7 517,8 @@ dkiput(Queue *q, Block *bp)
* we assume that each put is a message.
*
* add a 2 byte channel number to the start of each message,
- * low order byte first.
+ * low order byte first. Make sure the first block contains
+ * both the 2 channel bytes and the control byte.
*/
static void
dkoput(Queue *q, Block *bp)
@@ 706,9 667,8 @@ void
dkreset(void)
{
int i;
- dk = (Dk*)xalloc(conf.dkif*sizeof(Dk));
- for(i = 0; i < conf.dkif; i++)
- dk[i].prot = (Netprot*)xalloc(conf.nurp*sizeof(Netprot));
+
+ dk = (Dk*)xalloc(Maxdk*sizeof(Dk));
newqinfo(&dkmuxinfo);
}
@@ 759,7 719,11 @@ dkstat(Chan *c, char *dp)
Chan*
dkopen(Chan *c, int omode)
{
- return netopen(c, omode, &dk[c->dev].net);
+ Dk *dp;
+
+ dp = &dk[c->dev];
+ linealloc(dp, STREAMID(c->qid.path), 1);
+ return netopen(c, omode, &dp->net);
}
void
@@ 866,22 830,21 @@ dkcloneline(Chan *c)
/*
* get an unused device and open its control file
*/
+ qlock(&dp->netlock);
for(line = dp->ncsc+1; line < dp->lines; line++){
lp = dp->linep[line];
- if(lp->state == Lclosed && canqlock(lp)){
- if(lp->state != Lclosed){
- qunlock(lp);
- continue;
- }
+ if(lp == 0 || lp->state == Lclosed){
+ lp = linealloc(dp, line, 0);
lp->state = Lopened;
/* current user becomes owner */
- netown(&dp->net, lp->lineno, u->p->user, 0);
+ netown(lp, u->p->user, 0);
- qunlock(lp);
+ qunlock(&dp->netlock);
return lp->lineno;
}
}
+ qunlock(&dp->netlock);
error(Enodev);
return -1; /* never reached */
}
@@ 911,12 874,14 @@ dkopenline(Dk *dp, int line)
static Chan*
dkopencsc(Dk *dp)
{
- qlock(dp);
+ Line *lp;
+
+ qlock(&dp->csclock);
if(dp->csc == 0)
dp->csc = dkopenline(dp, dp->ncsc);
else
incref(dp->csc);
- qunlock(dp);
+ qunlock(&dp->csclock);
return dp->csc;
}
@@ 999,7 964,7 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
line = STREAMID(c->qid.path);
dp = &dk[c->dev];
- lp = dp->linep[line];
+ lp = linealloc(dp, line, 1);
/*
* only dial on virgin lines
@@ 1247,7 1212,7 @@ dklisten(Chan *c)
print("dklisten: illegal line %d\n", lineno);
continue;
}
- lp = dp->linep[lineno];
+ lp = linealloc(dp, lineno, 1);
ts = strtoul(field[1], 0, 0);
/*
@@ 1321,7 1286,7 @@ dklisten(Chan *c)
lp->state = Lconnected;
/* listener becomes owner */
- netown(&dp->net, lp->lineno, dp->prot[from].owner, 0);
+ netown(lp, dp->linep[from]->owner, 0);
qunlock(lp);
close(dc);
@@ 1340,12 1305,12 @@ static void
dkanswer(Chan *c, int line, int code)
{
char reply[64];
- Dk *dp;
Chan *dc;
Line *lp;
+ Dk *dp;
dp = &dk[c->dev];
- lp = dp->linep[line];
+ lp = linealloc(dp, line, 1);
/*
* open the data file (c is a control file)
@@ 1394,7 1359,7 @@ dkwindow(Chan *c)
long wins;
Line *lp;
- lp = dk[c->dev].linep[STREAMID(c->qid.path)];
+ lp = linealloc(&dk[c->dev], STREAMID(c->qid.path), 1);
if(lp->window == 0)
lp->window = 64;
sprint(buf, "init %d %d", lp->window, Streamhi);
@@ 1488,12 1453,11 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
switch (dialp->srv) {
case D_CLOSE: /* remote shutdown */
- if (line <= 0 || line >= dp->lines) {
+ if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
/* tell controller this line is not in use */
dkmesg(c, T_CHG, D_CLOSE, line, 0);
return;
}
- lp = dp->linep[line];
switch (lp->state) {
case Ldialing:
@@ 1524,12 1488,11 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
break;
case D_ISCLOSED: /* acknowledging a local shutdown */
- if (line <= 0 || line >= dp->lines) {
+ if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
/* tell controller this line is not in use */
dkmesg(c, T_CHG, D_CLOSE, line, 0);
return;
}
- lp = dp->linep[line];
switch (lp->state) {
case Llclose:
case Lclosed:
@@ 1550,6 1513,8 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
*/
for(line = dp->ncsc+1; line < dp->lines; line++){
lp = dp->linep[line];
+ if(lp == 0)
+ continue;
switch (lp->state) {
case Ldialing:
@@ 1595,10 1560,9 @@ dkreplymesg(Dk *dp, Dkmsg *dialp, int line)
DPRINT("dkreplymesg(%d)\n", line);
- if(line < 0 || line >= dp->lines)
+ if(line < 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
return;
- lp = dp->linep[line];
if(lp->state != Ldialing)
return;
@@ 1637,34 1601,11 @@ dktimer(void *a)
Chan *c;
dp = (Dk *)a;
- c = 0;
- if(waserror()){
- /*
- * hang up any calls waiting for the dk
- */
- for (i=dp->ncsc+1; i<dp->lines; i++){
- lp = dp->linep[i];
- switch(lp->state){
- case Llclose:
- lp->state = Lclosed;
- break;
-
- case Ldialing:
- dkreplymesg(dp, (Dkmsg *)0, i);
- break;
- }
- }
- if(c)
- close(c);
- return;
- }
-
c = dkopencsc(dp);
- for(;;){
- if(dp->opened==0)
- error(Ehungup);
+ while(waserror());
+ for(;;){
/*
* send keep alive
*/
@@ 1677,6 1618,8 @@ dktimer(void *a)
*/
for (i=dp->ncsc+1; i<dp->lines; i++){
lp = dp->linep[i];
+ if(lp == 0)
+ continue;
switch(lp->state){
case Llclose:
dkmesg(c, T_CHG, D_CLOSE, i, 0);
M port/devenv.c => port/devenv.c +115 -267
@@ 7,42 7,14 @@
#include "devtab.h"
-struct Envval
+enum
{
- Envval *next; /* for hashing & easy deletion from hash list */
- Envval *prev;
- ulong len; /* length of val that is valid */
- int ref;
- char *val;
+ Maxenvsize = 16300,
};
-enum{
- MAXENV = (BY2PG - sizeof(Envval)),
- EVHASH = 64,
- EVFREE = 16,
- ALIGN = 16,
-};
-
-struct
-{
- Envval *free[EVFREE+1];
- char *block; /* the free page we are allocating from */
- char *lim; /* end of block */
- int npage; /* total pages gotten from newpage() */
-}envalloc;
-
-QLock evlock;
-Envval evhash[EVHASH];
-char *evscratch; /* for constructing the contents of a file */
-
-Envval *newev(char*, ulong);
-Envval *evalloc(ulong);
-void evfree(Envval*);
-
void
envreset(void)
{
- evscratch = xalloc(BY2PG);
}
void
@@ 54,24 26,22 @@ int
envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
{
Egrp *eg;
- Env *e;
- int ans;
+ Evalue *e;
eg = u->p->egrp;
- qlock(&eg->ev);
- if(s >= eg->nenv)
- ans = -1;
- else{
- e = &eg->etab[s];
- if(!e->name)
- ans = 0;
- else{
- devdir(c, (Qid){s+1, (ulong)e->name}, e->name->val, e->val? e->val->len : 0, eve, 0666, dp);
- ans = 1;
- }
+ qlock(eg);
+
+ for(e = eg->entries; e && s; e = e->link)
+ s--;
+
+ if(e == 0) {
+ qunlock(eg);
+ return -1;
}
- qunlock(&eg->ev);
- return ans;
+
+ devdir(c, (Qid){e->path, 0}, e->name, e->len, eve, 0666, dp);
+ qunlock(eg);
+ return 1;
}
Chan*
@@ 103,30 73,31 @@ Chan *
envopen(Chan *c, int omode)
{
Egrp *eg;
- Env *e;
- int mode;
-
- mode = openmode(omode);
+ Evalue *e;
+
+ eg = u->p->egrp;
if(c->qid.path & CHDIR){
if(omode != OREAD)
error(Eperm);
- }else{
- eg = u->p->egrp;
- qlock(&eg->ev);
- e = &eg->etab[c->qid.path-1];
- if(!e->name){
- qunlock(&eg->ev);
+ }
+ else {
+ qlock(eg);
+ for(e = eg->entries; e; e = e->link)
+ if(e->path == c->qid.path)
+ break;
+
+ if(e == 0) {
+ qunlock(eg);
error(Enonexist);
}
- if(omode == (OWRITE|OTRUNC) && e->val){
- qlock(&evlock);
- evfree(e->val);
- qunlock(&evlock);
- e->val = 0;
+ if(omode == (OWRITE|OTRUNC) && e->value) {
+ free(e->value);
+ e->value = 0;
+ e->len = 0;
}
- qunlock(&eg->ev);
+ qunlock(eg);
}
- c->mode = mode;
+ c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
@@ 136,39 107,36 @@ void
envcreate(Chan *c, char *name, int omode, ulong perm)
{
Egrp *eg;
- Env *e, *ne;
- int i;
+ Evalue *e;
if(c->qid.path != CHDIR)
error(Eperm);
+
omode = openmode(omode);
eg = u->p->egrp;
- qlock(&eg->ev);
- e = eg->etab;
- ne = 0;
- for(i = 0; i < eg->nenv; i++, e++)
- if(e->name == 0)
- ne = e;
- else if(strcmp(e->name->val, name) == 0){
- qunlock(&eg->ev);
- error(Einuse);
- }
- if(ne)
- e = ne;
- else if(eg->nenv == conf.npgenv){
- qunlock(&eg->ev);
- print("out of egroup envs\n");
- error(Enoenv);
+
+ qlock(eg);
+ if(waserror()) {
+ qunlock(eg);
+ nexterror();
}
- i = e - eg->etab + 1;
- e->val = 0;
- qlock(&evlock);
- e->name = newev(name, strlen(name)+1);
- qunlock(&evlock);
- if(i > eg->nenv)
- eg->nenv = i;
- qunlock(&eg->ev);
- c->qid = (Qid){i, 0};
+
+ for(e = eg->entries; e; e = e->link)
+ if(strcmp(e->name, name) == 0)
+ error(Einuse);
+
+ e = smalloc(sizeof(Evalue));
+ e->name = smalloc(strlen(name)+1);
+ strcpy(e->name, name);
+
+ e->path = ++eg->path;
+ e->link = eg->entries;
+ eg->entries = e;
+ c->qid = (Qid){e->path, 0};
+
+ qunlock(eg);
+ poperror();
+
c->offset = 0;
c->mode = omode;
c->flag |= COPEN;
@@ 178,19 146,32 @@ void
envremove(Chan *c)
{
Egrp *eg;
- Env *e;
+ Evalue *e, **l;
if(c->qid.path & CHDIR)
error(Eperm);
+
eg = u->p->egrp;
- qlock(&eg->ev);
- e = &eg->etab[c->qid.path-1];
- if(!e->name){
- qunlock(&eg->ev);
+ qlock(eg);
+
+ l = &eg->entries;
+ for(e = *l; e; e = e->link) {
+ if(e->path == c->qid.path)
+ break;
+ l = &e->link;
+ }
+
+ if(e == 0) {
+ qunlock(eg);
error(Enonexist);
}
- envpgclose(e);
- qunlock(&eg->ev);
+
+ *l = e->link;
+ qunlock(eg);
+ free(e->name);
+ if(e->value)
+ free(e->value);
+ free(e);
}
void
@@ 206,206 187,73 @@ envclose(Chan * c)
USED(c);
}
-void
-envpgcopy(Env *t, Env *f)
-{
- qlock(&evlock);
- if(t->name = f->name)
- t->name->ref++;
- if(t->val = f->val)
- t->val->ref++;
- qunlock(&evlock);
-}
-
-void
-envpgclose(Env *e)
-{
- qlock(&evlock);
- if(e->name)
- evfree(e->name);
- if(e->val)
- evfree(e->val);
- e->name = e->val = 0;
- qunlock(&evlock);
-}
-
long
envread(Chan *c, void *a, long n, ulong offset)
{
Egrp *eg;
- Env *e;
- Envval *ev;
- long vn;
+ Evalue *e;
if(c->qid.path & CHDIR)
return devdirread(c, a, n, 0, 0, envgen);
+
eg = u->p->egrp;
- qlock(&eg->ev);
- e = &eg->etab[c->qid.path-1];
- if(!e->name){
- qunlock(&eg->ev);
+ qlock(eg);
+ for(e = eg->entries; e; e = e->link)
+ if(e->path == c->qid.path)
+ break;
+
+ if(e == 0) {
+ qunlock(eg);
error(Enonexist);
}
- ev = e->val;
- vn = ev ? ev->len : 0;
- if(offset + n > vn)
- n = vn - offset;
+
+ if(offset + n > e->len)
+ n = e->len - offset;
if(n <= 0)
n = 0;
else
- memmove(a, ev->val + offset, n);
- qunlock(&eg->ev);
+ memmove(a, e->value+offset, n);
+ qunlock(eg);
return n;
}
long
envwrite(Chan *c, void *a, long n, ulong offset)
{
+ char *s;
+ int vend;
Egrp *eg;
- Env *e;
- Envval *ev;
- ulong olen;
+ Evalue *e;
if(n <= 0)
return 0;
- olen = (offset + n + ALIGN - 1) & ~(ALIGN - 1);
- if(olen > MAXENV)
+
+ vend = offset+n;
+ if(vend > Maxenvsize)
error(Etoobig);
- eg = u->p->egrp;
- qlock(&eg->ev);
- e = &eg->etab[c->qid.path-1];
- if(!e->name){
- qunlock(&eg->ev);
- error(Enonexist);
- }
- ev = e->val;
- olen = ev ? ev->len : 0;
- qlock(&evlock);
- if(offset == 0 && n >= olen)
- e->val = newev(a, n);
- else{
- if(olen > offset)
- olen = offset;
- if(ev)
- memmove(evscratch, ev->val, olen);
- if(olen < offset)
- memset(evscratch + olen, '\0', offset - olen);
- memmove(evscratch + offset, a, n);
- e->val = newev(evscratch, offset + n);
- }
- if(ev)
- evfree(ev);
- qunlock(&evlock);
- qunlock(&eg->ev);
- return n;
-}
-/*
- * called with evlock qlocked
- */
-Envval *
-newev(char *s, ulong n)
-{
- Envval *ev;
- uchar *t;
- int h;
-
- h = 0;
- for(t = (uchar*)s; t - (uchar*)s < n; t++)
- h = (h << 1) ^ *t;
- h &= EVHASH - 1;
- for(ev = evhash[h].next; ev; ev = ev->next)
- if(ev->len == n && memcmp(ev->val, s, n) == 0){
- ev->ref++;
- return ev;
- }
- ev = evalloc(n);
- ev->len = n;
- memmove(ev->val, s, n);
- if(ev->next = evhash[h].next)
- ev->next->prev = ev;
- evhash[h].next = ev;
- ev->prev = &evhash[h];
- return ev;
-}
+ eg = u->p->egrp;
+ qlock(eg);
+ for(e = eg->entries; e; e = e->link)
+ if(e->path == c->qid.path)
+ break;
-/*
- * called only from newev
- */
-Envval *
-evalloc(ulong n)
-{
- Envval *ev, **p;
- char *b, *lim;
- ulong size;
-
- size = (n + ALIGN - 1) & ~(ALIGN - 1);
- n = (size - 1) / ALIGN;
- p = &envalloc.free[n < EVFREE ? n : EVFREE];
- for(ev = *p; ev; ev = *p){
- if(ev->len == size){
- *p = ev->next;
- ev->ref = 1;
- return ev;
- }
- p = &ev->next;
+ if(e == 0) {
+ qunlock(eg);
+ error(Enonexist);
}
- /*
- * make sure we have enough space to allocate the buffer.
- * if not, use the remaining space for the smallest buffers
- */
- if(size > MAXENV)
- panic("evalloc");
- b = envalloc.block;
- lim = envalloc.lim;
- if(!b || lim < b + size + sizeof *ev){
- p = &envalloc.free[0];
- while(lim >= b + ALIGN + sizeof *ev){
- ev = (Envval*)b;
- ev->len = ALIGN;
- ev->val = b + sizeof *ev;
- ev->next = *p;
- *p = ev;
- b += ALIGN + sizeof *ev;
- }
- b = (char*)VA(kmap(newpage(0, 0, 0)));
- envalloc.npage++;
- envalloc.lim = b + BY2PG;
+ if(vend > e->len) {
+ s = smalloc(offset+n);
+ memmove(s, e->value, e->len);
+ if(e->value)
+ free(e->value);
+ e->value = s;
+ e->len = vend;
}
-
- ev = (Envval*)b;
- ev->val = b + sizeof *ev;
- ev->ref = 1;
- envalloc.block = b + size + sizeof *ev;
- return ev;
-}
-
-/*
- * called with evlock qlocked
- */
-void
-evfree(Envval *ev)
-{
- int n;
-
- if(--ev->ref > 0)
- return;
-
- if(ev->prev)
- ev->prev->next = ev->next;
- else
- panic("evfree");
- if(ev->next)
- ev->next->prev = ev->prev;
- n = (ev->len + ALIGN - 1) & ~(ALIGN - 1);
- ev->len = n;
- n = (n - 1) / ALIGN;
- if(n > EVFREE)
- n = EVFREE;
- ev->next = envalloc.free[n];
- ev->prev = 0;
- envalloc.free[n] = ev;
+ memmove(e->value+offset, a, n);
+ qunlock(eg);
+ return n;
}
/*
M port/devip.c => port/devip.c +3 -5
@@ 57,9 57,9 @@ ipinitnet(Network *np, Qinfo *stproto, Ipconv *cp)
int j;
for(j = 0; j < conf.ip; j++, cp++){
- cp->index = j;
cp->stproto = stproto;
cp->net = np;
+ netadd(np, cp, j);
}
np->name = stproto->name;
np->nconv = conf.ip;
@@ 68,7 68,6 @@ ipinitnet(Network *np, Qinfo *stproto, Ipconv *cp)
if(stproto != &udpinfo)
np->listen = iplisten;
np->clone = ipclonecon;
- np->prot = (Netprot *)xalloc(sizeof(Netprot) * conf.ip);
np->ninfo = 3;
np->info[0].name = "remote";
np->info[0].fill = ipremotefill;
@@ 172,10 171,9 @@ ipincoming(Ipconv *base, Ipconv *from)
continue;
}
if(from) /* copy ownership from listening channel */
- netown(new->net, new->index,
- new->net->prot[from->index].owner, 0);
+ netown(new, from->owner, 0);
else /* current user becomes owner */
- netown(new->net, new->index, u->p->user, 0);
+ netown(new, u->p->user, 0);
new->ref = 1;
qunlock(new);
M port/devlance.c => port/devlance.c +6 -4
@@ 76,6 76,7 @@ typedef struct Ethertype Ethertype;
struct Ethertype
{
QLock;
+ Netprot; /* stat info */
int type; /* ethernet type */
int prom; /* promiscuous mode */
Queue *q;
@@ 96,7 97,6 @@ typedef struct {
int all; /* number of channels listening to all packets */
int wedged; /* the lance is wedged */
Network net;
- Netprot prot[Ntypes];
int inited;
uchar *lmp; /* location of parity test */
@@ 268,7 268,7 @@ lancestclose(Queue *q)
et->q = 0;
et->prom = 0;
et->inuse = 0;
- netdisown(&l.net, et - l.e);
+ netdisown(et);
}
/*
@@ 416,6 416,7 @@ void
lancereset(void)
{
static int already;
+ int i;
if(already == 0){
already = 1;
@@ 428,11 429,12 @@ lancereset(void)
l.net.listen = 0;
l.net.clone = lanceclonecon;
l.net.ninfo = 2;
- l.net.prot = l.prot;
l.net.info[0].name = "stats";
l.net.info[0].fill = lancestatsfill;
l.net.info[1].name = "type";
l.net.info[1].fill = lancetypefill;
+ for(i = 0; i < Ntypes; i++)
+ netadd(&l.net, &l.e[i], i);
memset(l.bcast, 0xff, sizeof l.bcast);
}
@@ 671,7 673,7 @@ lanceclonecon(Chan *c)
continue;
}
e->inuse = 1;
- netown(&l.net, e - l.e, u->p->user, 0);
+ netown(e, u->p->user, 0);
qunlock(e);
return e - l.e;
}
M port/devpipe.c => port/devpipe.c +2 -4
@@ 161,9 161,7 @@ pipeopen(Chan *c, int omode)
remote->devq->ptr = local;
local->devq->other->next = remote->devq;
remote->devq->other->next = local->devq;
- }
- else
- if(local->opens == 1){
+ } else if(local->opens == 1){
/*
* keep other side around till last close of this side
*/
@@ 321,6 319,6 @@ getpipe(ulong path)
}
}
unlock(&pipealloc);
- panic("getpipe");
+ error(Enonexist);
return 0;
}
M port/devscc.c => port/devscc.c +1 -1
@@ 754,7 754,7 @@ sccread(Chan *c, void *buf, long n, ulong offset)
return streamread(c, buf, n);
case Sctlqid:
sprint(b, "%d", STREAMID(c->qid.path));
- return stringread(buf, n, b, offset);
+ return readstr(offset, buf, n, b);
}
error(Egreg);
return 0; /* not reached */
M port/ipdat.h => port/ipdat.h +1 -1
@@ 278,8 278,8 @@ struct Reseq
struct Ipconv
{
QLock; /* Ref count lock */
+ Netprot; /* stat info */
int ref;
- int index;
Qinfo *stproto; /* Stream protocol for this device */
Network *net; /* user level network interface */
Ipaddr dst; /* Destination from connect */
M port/net.c => port/net.c +51 -18
@@ 15,6 15,20 @@ enum
};
/*
+ * find protection structure
+ */
+static Netprot*
+findprot(Network *np, int id)
+{
+ Netprot *p;
+
+ for(p = np->prot; p; p = p->next)
+ if(p->id == id)
+ break;
+ return p;
+}
+
+/*
* generate a 3 level directory
*/
int
@@ 24,7 38,6 @@ netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
char buf[32];
Network *np = vp;
int t;
- int id;
Netprot *p;
int perm;
char *o;
@@ 61,9 74,8 @@ netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
}
/* third level depends on the number of info files */
- id = STREAMID(c->qid.path);
- p = &np->prot[id];
- if(*p->owner){
+ p = findprot(np, STREAMID(c->qid.path));
+ if(p && *p->owner){
o = p->owner;
perm = p->mode;
} else {
@@ 153,7 165,9 @@ netwstat(Chan *c, char *db, Network *np)
Dir dir;
Netprot *p;
- p = &np->prot[STREAMID(c->qid.path)];
+ p = findprot(np, STREAMID(c->qid.path));
+ if(p == 0)
+ error(Enonexist);
lock(np);
if(strncmp(p->owner, u->p->user, NAMELEN)){
unlock(np);
@@ 169,6 183,7 @@ Chan *
netopen(Chan *c, int omode, Network *np)
{
int id = 0;
+ Netprot *p;
if(c->qid.path & CHDIR){
if(omode != OREAD)
@@ 199,7 214,9 @@ netopen(Chan *c, int omode, Network *np)
streamopen(c, np->devp);
if(np->protop && c->stream->devq->next->info != np->protop)
pushq(c->stream, np->protop);
- if(netown(np, id, u->p->user, omode&7) < 0)
+ p = findprot(np, id);
+if(p == 0) print("netopen: can't find %d\n", id);
+ if(netown(p, u->p->user, omode&7) < 0)
error(Eperm);
break;
}
@@ 227,19 244,36 @@ netread(Chan *c, void *a, long n, ulong offset, Network *np)
error(Ebadusefd);
(*np->info[t-Qinf].fill)(c, buf, sizeof(buf));
- return stringread(a, n, buf, offset);
+ return readstr(offset, a, n, buf);
}
+void
+netadd(Network *np, Netprot *p, int id)
+{
+ Netprot **l, *pp;
+
+ memset(p, 0, sizeof(Netprot));
+ p->id = id;
+
+ l = &np->prot;
+ for(pp = np->prot; pp; pp = pp->next){
+ if(pp->id == id)
+ panic("netadd");
+ l = &pp->next;
+ }
+ *l = p;
+}
+
+Lock netlock;
+
int
-netown(Network *np, int id, char *o, int omode)
+netown(Netprot *p, char *o, int omode)
{
static int access[] = { 0400, 0200, 0600, 0100 };
- Netprot *p;
int mode;
int t;
- p = &np->prot[id];
- lock(np);
+ lock(&netlock);
if(*p->owner){
if(strncmp(o, p->owner, NAMELEN) == 0) /* User */
mode = p->mode;
@@ 250,22 284,21 @@ netown(Network *np, int id, char *o, int omode)
t = access[omode&3];
if((t & mode) == t){
- unlock(np);
+ unlock(&netlock);
return 0;
} else {
- unlock(np);
+ unlock(&netlock);
return -1;
}
}
strncpy(p->owner, o, NAMELEN);
- np->prot[id].mode = 0660;
- unlock(np);
+ p->mode = 0660;
+ unlock(&netlock);
return 0;
}
void
-netdisown(Network *np, int id)
+netdisown(Netprot *p)
{
-if(np == 0) panic("np == 0");
- *np->prot[id].owner = 0;
+ p->owner[0] = 0;
}
M port/pgrp.c => port/pgrp.c +28 -41
@@ 52,29 52,6 @@ newpgrp(void)
return p;
}
-Egrp*
-newegrp(void)
-{
- Egrp *e;
-
- e = smalloc(sizeof(Egrp)+sizeof(Env)*conf.npgenv);
-
- /* This is a sleazy hack to make malloc work .. devenv need rewriting. */
- e->etab = (Env*)((uchar*)e+sizeof(Egrp));
- e->ref = 1;
- return e;
-}
-
-Fgrp*
-newfgrp(void)
-{
- Fgrp *f;
-
- f = smalloc(sizeof(Fgrp));
- f->ref = 1;
- return f;
-}
-
Fgrp*
dupfgrp(Fgrp *f)
{
@@ 82,7 59,8 @@ dupfgrp(Fgrp *f)
Chan *c;
int i;
- new = newfgrp();
+ new = smalloc(sizeof(Fgrp));
+ new->ref = 1;
lock(f);
new->maxfd = f->maxfd;
@@ 139,14 117,16 @@ closepgrp(Pgrp *p)
void
closeegrp(Egrp *eg)
{
- Env *e;
- int i;
+ Evalue *e, *next;
if(decref(eg) == 0) {
- e = eg->etab;
- for(i=0; i<eg->nenv; i++, e++)
- envpgclose(e);
-
+ for(e = eg->entries; e; e = next) {
+ next = e->link;
+ free(e->name);
+ if(e->value)
+ free(e->value);
+ free(e);
+ }
free(eg);
}
}
@@ 183,17 163,24 @@ newmount(Mhead *mh, Chan *to)
void
envcpy(Egrp *to, Egrp *from)
{
- Env *te, *fe;
- int i, nenv;
-
- qlock(&from->ev);
- nenv = from->nenv;
- to->nenv = nenv;
- te = to->etab;
- fe = from->etab;
- for(i=0; i < nenv; i++, te++, fe++)
- envpgcopy(te, fe);
- qunlock(&from->ev);
+ Evalue **l, *ne, *e;
+
+ l = &to->entries;
+ qlock(from);
+ for(e = from->entries; e; e = e->link) {
+ ne = smalloc(sizeof(Evalue));
+ ne->name = smalloc(strlen(e->name)+1);
+ strcpy(ne->name, e->name);
+ if(e->value) {
+ ne->value = smalloc(e->len);
+ memmove(ne->value, e->value, e->len);
+ ne->len = e->len;
+ }
+ ne->path = ++to->path;
+ *l = ne;
+ l = &ne->link;
+ }
+ qunlock(from);
}
void
M port/portdat.h => port/portdat.h +16 -12
@@ 6,8 6,7 @@ typedef struct Crypt Crypt;
typedef struct Dev Dev;
typedef struct Dirtab Dirtab;
typedef struct Egrp Egrp;
-typedef struct Env Env;
-typedef struct Envval Envval;
+typedef struct Evalue Evalue;
typedef struct Etherpkt Etherpkt;
typedef struct Fgrp Fgrp;
typedef struct Image Image;
@@ 192,12 191,6 @@ struct Dirtab
long perm;
};
-struct Env
-{
- Envval *name;
- Envval *val;
-};
-
/*
* Ethernet packet buffers.
*/
@@ 394,9 387,18 @@ struct Pgrp
struct Egrp
{
Ref;
- int nenv; /* highest active env table entry, +1 */
- QLock ev; /* for all of etab */
- Env *etab;
+ QLock;
+ Evalue *entries;
+ ulong path;
+};
+
+struct Evalue
+{
+ char *name;
+ char *value;
+ int len;
+ ulong path;
+ Evalue *link;
};
#define NFD 100
@@ 651,6 653,8 @@ enum
*/
struct Netprot
{
+ int id;
+ Netprot *next; /* linked list of protections */
ulong mode;
char owner[NAMELEN];
};
@@ 672,7 676,7 @@ struct Network
int (*clone)(Chan*);
int ninfo;
Netinf info[5];
- Netprot *prot; /* protections */
+ Netprot *prot; /* linked list of protections */
};
#define MAJOR(q) ((q) >> 8)
#define MINOR(q) ((q) & 0xff)
M port/portfns.h => port/portfns.h +6 -8
@@ 28,7 28,6 @@ void confinit1(int);
int consactive(void);
void consdebug(void);
Block* copyb(Block*, int);
-Env* copyenv(Env*, int);
void copypage(Page*, Page*);
int decref(Ref*);
int decrypt(void*, void*, int);
@@ 50,8 49,6 @@ void duppage(Page*);
void dupswap(Page*);
int encrypt(void*, void*, int);
void envcpy(Egrp*, Egrp*);
-void envpgclose(Env*);
-void envpgcopy(Env*, Env*);
int eqchan(Chan*, Chan*, long);
int eqqid(Qid, Qid);
void error(char*);
@@ 114,19 111,19 @@ int mount(Chan*, Chan*, int);
void mountfree(Mount*);
void mouseclock(void);
int mouseputc(IOQ*, int);
+int msize(void*);
Chan* namec(char*, int, int, ulong);
void nameok(char*);
-void netdisown(Network*, int);
+void netdisown(Netprot*);
int netgen(Chan*, void*, int, int, Dir*);
Chan* netopen(Chan*, int, Network*);
-int netown(Network*, int, char*, int);
+int netown(Netprot*, char*, int);
+void netadd(Network*, Netprot*, int);
long netread(Chan*, void*, long, ulong, Network*);
void netstat(Chan*, char*, Network*);
int netwalk(Chan*, char*, Network*);
void netwstat(Chan*, char*, Network*);
Chan* newchan(void);
-Egrp* newegrp(void);
-Fgrp* newfgrp(void);
Mount* newmount(Mhead*, Chan*);
Page* newpage(int, Segment **, ulong);
Pgrp* newpgrp(void);
@@ 180,6 177,7 @@ Qinfo* qinfofind(char*);
void qlock(QLock*);
void qunlock(QLock*);
int readnum(ulong, char*, ulong, ulong, int);
+int readstr(ulong, char*, ulong, char*);
void ready(Proc*);
void relocateseg(Segment*, ulong);
void resched(char*);
@@ 213,7 211,7 @@ void splx(int);
int streamclose(Chan*);
int streamclose1(Stream*);
int streamenter(Stream*);
-int streamexit(Stream*, int);
+void streamexit(Stream*, int);
Devgen streamgen;
void streaminit(void);
void streaminit0(void);
M port/stasync.c => port/stasync.c +34 -17
@@ 24,8 24,12 @@ enum
Escape
};
-typedef struct Async {
+typedef struct Async Async;
+struct Async
+{
QLock;
+ Async *list;
+ int id;
int inuse;
Queue *wq;
@@ 51,9 55,16 @@ typedef struct Async {
ulong badescape;
ulong in; /* bytes in */
ulong out; /* bytes out */
-} Async;
+};
+
+int nasync;
-Async *async;
+/* list of allocated async structures (never freed) */
+struct
+{
+ Lock;
+ Async *async;
+} asyncalloc;
/*
* async stream module definition
@@ 97,7 108,6 @@ static ushort crc_table[256] = {
static void
asyncreset(void)
{
- async = (Async *)xalloc(conf.nasync*sizeof(Async));
}
/*
@@ 110,14 120,21 @@ asyncopen(Queue *q, Stream *s)
DPRINT("asyncopen %d\n", s->dev);
- for(ap = async; ap < &async[conf.nasync]; ap++){
+ for(ap = asyncalloc.async; ap; ap = ap->list){
qlock(ap);
if(ap->inuse == 0)
break;
qunlock(ap);
}
- if(ap == &async[conf.nasync])
- exhausted("async stream modules");
+ if(ap == 0){
+ ap = smalloc(sizeof(Async));
+ qlock(ap);
+ lock(&asyncalloc);
+ ap->list = asyncalloc.async;
+ asyncalloc.async = ap;
+ ap->id = nasync++;
+ unlock(&asyncalloc);
+ }
q->ptr = q->other->ptr = ap;
ap->inuse = 1;
@@ 141,7 158,7 @@ asyncclose(Queue * q)
{
Async *ap = (Async *)q->ptr;
- DPRINT("asyncstclose %d\n", ap-async);
+ DPRINT("asyncstclose %d\n", ap->id);
qlock(ap);
ap->inuse = 0;
qunlock(ap);
@@ 166,7 183,7 @@ freemsg(Queue *q, Block *bp)
static void
showframe(char *t, Async *ap, uchar *buf, int n)
{
- kprint("a%d %s [", ap-async, t);
+ kprint("a%d %s [", ap->id, t);
while (--n >= 0)
kprint(" %2.2ux", *buf++);
kprint(" ]\n");
@@ 284,7 301,7 @@ asyncoput(Queue *q, Block *bp)
if(asyncdebug > 1)
kprint("a%d->(%d)%3.3uo %d\n",
- ap-async, chan, ctl, bp->wptr-bp->rptr);
+ ap->id, chan, ctl, bp->wptr-bp->rptr);
/*
* send the 8 bit data
@@ 336,7 353,7 @@ asdeliver(Queue *q, Async *ap)
chan = *p++ & 0x7e;
chan = (chan<<5)|((*p++ & 0x7e)>>1);
if(chan==0) {
- DPRINT("a%d deliver chan 0\n", ap-async);
+ DPRINT("a%d deliver chan 0\n", ap->id);
ap->chan0++;
return;
}
@@ 355,7 372,7 @@ asdeliver(Queue *q, Async *ap)
bp->rptr[2] = c;
if(asyncdebug > 1)
kprint("a%d<-(%d)%3.3uo %d\n",
- ap-async, chan, bp->rptr[2],
+ ap->id, chan, bp->rptr[2],
bp->wptr - bp->rptr - 3);
PUTNEXT(q, bp);
bp = 0;
@@ 368,7 385,7 @@ asdeliver(Queue *q, Async *ap)
if(bp) {
if(asyncdebug > 1)
kprint("a%d<-(%d)%3.3uo %d\n",
- ap-async, chan, bp->rptr[2],
+ ap->id, chan, bp->rptr[2],
bp->wptr - bp->rptr - 3);
PUTNEXT(q, bp);
}
@@ 411,7 428,7 @@ asynciput(Queue *q, Block *bp)
}
Datachar:
if(ap->icount >= MAXFRAME) {
- DPRINT("a%d pkt too long\n", ap-async);
+ DPRINT("a%d pkt too long\n", ap->id);
ap->toolong++;
state = Hunt;
break;
@@ 426,12 443,12 @@ asynciput(Queue *q, Block *bp)
if(asyncdebug > 2)
showframe("in", ap, ap->buf, ap->icount);
if(ap->icount < 5) {
- DPRINT("a%d pkt too short\n", ap-async);
+ DPRINT("a%d pkt too short\n", ap->id);
if(asyncdebug && asyncdebug<=2)
showframe("shortin", ap, ap->buf, ap->icount);
ap->tooshort++;
} else if(ap->icrc != 0) {
- DPRINT("a%d bad crc\n", ap-async);
+ DPRINT("a%d bad crc\n", ap->id);
if(asyncdebug && asyncdebug<=2)
showframe("badin", ap, ap->buf, ap->icount);
ap->badcrc++;
@@ 445,7 462,7 @@ asynciput(Queue *q, Block *bp)
state = Data;
goto Datachar;
default:
- DPRINT("a%d bad escape\n", ap-async);
+ DPRINT("a%d bad escape\n", ap->id);
ap->badescape++;
state = Hunt;
break;
M port/stip.c => port/stip.c +1 -1
@@ 145,7 145,7 @@ ipetherclose(Queue *q)
ipc = (Ipconv *)(q->ptr);
if(ipc){
- netdisown(ipc->net, ipc->index);
+ netdisown(ipc);
ipc->ref = 0;
}
}
M port/stream.c => port/stream.c +460 -512
@@ 7,85 7,28 @@
#include "../port/error.h"
#include "devtab.h"
-enum {
- Nclass=4, /* number of block classes */
-};
-
-/*
- * process end line discipline
- */
-static void stputq(Queue*, Block*);
-Qinfo procinfo =
-{
- stputq,
- nullput,
- 0,
- 0,
- "process"
-};
-
-/*
- * line disciplines that can be pushed
- */
-static Qinfo *lds;
-
-Stream *slist;
-Queue *qlist;
-static Lock garbagelock;
-
-/*
- * Allocate streams, queues, and blocks. Allocate n block classes with
- * 1/2(m+1) to class m < n-1
- * 1/2(n-1) to class n-1
- */
-void
-streaminit(void)
-{
-
- /*
- * allocate queues, streams
- */
- slist = (Stream *)xalloc(conf.nstream * sizeof(Stream));
- qlist = (Queue *)xalloc(conf.nqueue * sizeof(Queue));
-
- /*
- * make stream modules available
- */
- streaminit0();
-}
-
/*
- * make known a stream module and call its initialization routine, if
- * it has one.
+ * Part 1) Blocks
*/
-void
-newqinfo(Qinfo *qi)
-{
- if(qi->next)
- panic("newqinfo: already configured");
-
- qi->next = lds;
- lds = qi;
- if(qi->reset)
- (*qi->reset)();
-}
/*
- * allocate a block
+ * Allocate a block. Put the data portion at the end of the smalloc'd
+ * chunk so that it can easily grow from the front to add protocol
+ * headers. Thank Larry Peterson for the suggestion.
*/
Block *
allocb(ulong size)
{
Block *bp;
- uchar *data;
+ uchar *base, *lim;
bp = smalloc(sizeof(Block)+size);
- data = (uchar*)bp + sizeof(Block);
- bp->rptr = data;
- bp->wptr = data;
- bp->base = data;
- bp->lim = data+size;
+ base = (uchar*)bp + sizeof(Block);
+ lim = (uchar*)bp + msize(bp);
+ bp->wptr = bp->rptr = lim - size;
+ bp->base = base;
+ bp->lim = lim;
bp->flags = 0;
bp->next = 0;
bp->list = 0;
@@ 95,7 38,7 @@ allocb(ulong size)
/*
* Free a block (or list of blocks). Poison its pointers so that
- * someone trying to access it after freeing will cause a dump.
+ * someone trying to access it after freeing will cause a panic.
*/
void
freeb(Block *bp)
@@ 112,7 55,8 @@ freeb(Block *bp)
}
/*
- * pad a block to the front with n bytes
+ * Pad a block to the front with n bytes. This is used to add protocol
+ * headers to the front of blocks.
*/
Block *
padb(Block *bp, int n)
@@ 132,6 76,253 @@ padb(Block *bp, int n)
}
/*
+ * make sure the first block has n bytes
+ */
+Block *
+pullup(Block *bp, int n)
+{
+ Block *nbp;
+ int i;
+
+ /*
+ * this should almost always be true, the rest it
+ * just for to avoid every caller checking.
+ */
+ if(BLEN(bp) >= n)
+ return bp;
+
+ /*
+ * if not enough room in the first block,
+ * add another to the front of the list.
+ */
+ if(bp->lim - bp->rptr < n){
+ nbp = allocb(n);
+ nbp->next = bp;
+ bp = nbp;
+ }
+
+ /*
+ * copy bytes from the trailing blocks into the first
+ */
+ n -= BLEN(bp);
+ while(nbp = bp->next){
+ i = BLEN(nbp);
+ if(i >= n) {
+ memmove(bp->wptr, nbp->rptr, n);
+ bp->wptr += n;
+ nbp->rptr += n;
+ return bp;
+ } else {
+ memmove(bp->wptr, nbp->rptr, i);
+ bp->wptr += i;
+ bp->next = nbp->next;
+ nbp->next = 0;
+ freeb(nbp);
+ n -= i;
+ }
+ }
+ freeb(bp);
+ return 0;
+}
+
+/*
+ * return the number of data bytes of a list of blocks
+ */
+int
+blen(Block *bp)
+{
+ int len;
+
+ len = 0;
+ while(bp) {
+ len += BLEN(bp);
+ bp = bp->next;
+ }
+
+ return len;
+}
+
+/*
+ * round a block chain to some even number of bytes. Used
+ * by devip.c becuase all IP packets must have an even number
+ * of bytes.
+ *
+ * The last block in the returned chain will have S_DELIM set.
+ */
+int
+bround(Block *bp, int amount)
+{
+ Block *last;
+ int len, pad;
+
+ len = 0;
+ SET(last); /* Ken's magic */
+
+ while(bp) {
+ len += BLEN(bp);
+ last = bp;
+ bp = bp->next;
+ }
+
+ pad = ((len + amount) & ~amount) - len;
+ if(pad) {
+ if(last->lim - last->wptr >= pad){
+ memset(last->wptr, 0, pad);
+ last->wptr += pad;
+ } else {
+ last->next = allocb(pad);
+ last->flags &= ~S_DELIM;
+ last = last->next;
+ last->wptr += pad;
+ last->flags |= S_DELIM;
+ }
+ }
+
+ return len + pad;
+}
+
+/*
+ * expand a block list to be one block, len bytes long. used by
+ * ethernet routines.
+ */
+Block*
+expandb(Block *bp, int len)
+{
+ Block *nbp, *new;
+ int i;
+ ulong delim = 0;
+
+ new = allocb(len);
+ if(new == 0){
+ freeb(bp);
+ return 0;
+ }
+
+ /*
+ * copy bytes into new block
+ */
+ for(nbp = bp; len>0 && nbp; nbp = nbp->next){
+ delim = nbp->flags & S_DELIM;
+ i = BLEN(nbp);
+ if(i > len) {
+ memmove(new->wptr, nbp->rptr, len);
+ new->wptr += len;
+ break;
+ } else {
+ memmove(new->wptr, nbp->rptr, i);
+ new->wptr += i;
+ len -= i;
+ }
+ }
+ if(len){
+ memset(new->wptr, 0, len);
+ new->wptr += len;
+ }
+ new->flags |= delim;
+ freeb(bp);
+ return new;
+
+}
+
+/*
+ * make a copy of the first 'count' bytes of a block chain. Use
+ * by transport protocols.
+ */
+Block *
+copyb(Block *bp, int count)
+{
+ Block *nb, *head, **p;
+ int l;
+
+ p = &head;
+ while(count) {
+ l = BLEN(bp);
+ if(count < l)
+ l = count;
+ nb = allocb(l);
+ if(nb == 0)
+ panic("copyb.1");
+ memmove(nb->wptr, bp->rptr, l);
+ nb->wptr += l;
+ count -= l;
+ if(bp->flags & S_DELIM)
+ nb->flags |= S_DELIM;
+ *p = nb;
+ p = &nb->next;
+ bp = bp->next;
+ if(bp == 0)
+ break;
+ }
+ if(count) {
+ nb = allocb(count);
+ if(nb == 0)
+ panic("copyb.2");
+ memset(nb->wptr, 0, count);
+ nb->wptr += count;
+ nb->flags |= S_DELIM;
+ *p = nb;
+ }
+ if(blen(head) == 0)
+ print("copyb: zero length\n");
+
+ return head;
+}
+
+/*
+ * Part 2) Queues
+ */
+
+/*
+ * process end line discipline
+ */
+static void stputq(Queue*, Block*);
+Qinfo procinfo =
+{
+ stputq,
+ nullput,
+ 0,
+ 0,
+ "process"
+};
+
+/*
+ * line disciplines that can be pushed
+ */
+static Qinfo *lds;
+
+/*
+ * make known a stream module and call its initialization routine, if
+ * it has one.
+ */
+void
+newqinfo(Qinfo *qi)
+{
+ if(qi->next)
+ panic("newqinfo: already configured");
+
+ qi->next = lds;
+ lds = qi;
+ if(qi->reset)
+ (*qi->reset)();
+}
+
+/*
+ * find the info structure for line discipline 'name'
+ */
+Qinfo *
+qinfofind(char *name)
+{
+ Qinfo *qi;
+
+ if(name == 0)
+ return 0;
+ for(qi = lds; qi; qi = qi->next)
+ if(strcmp(qi->name, name)==0)
+ return qi;
+ return 0;
+}
+
+/*
* allocate a pair of queues. flavor them with the requested put routines.
* the `QINUSE' flag on the read side is the only one used.
*/
@@ 140,20 331,7 @@ allocq(Qinfo *qi)
{
Queue *q, *wq;
- for(q=qlist; q<&qlist[conf.nqueue]; q++, q++) {
- if(q->flag == 0){
- if(canlock(q)){
- if(q->flag == 0)
- break;
- unlock(q);
- }
- }
- }
-
- if(q == &qlist[conf.nqueue]){
- print("no more queues\n");
- exhausted("queues");
- }
+ q = smalloc(2*sizeof(Queue));
q->flag = QINUSE;
q->r.p = 0;
@@ 173,16 351,14 @@ allocq(Qinfo *qi)
wq->len = wq->nb = 0;
wq->rp = &wq->r;
- unlock(q);
-
return q;
}
/*
- * flush a queue
+ * free a queue
*/
static void
-flushq(Queue *q)
+freeq(Queue *q)
{
Block *bp;
@@ 192,13 368,14 @@ flushq(Queue *q)
q = WR(q);
while(bp = getq(q))
freeb(bp);
+ free(RD(q));
}
/*
- * free a queue
+ * flush a queue
*/
static void
-freeq(Queue *q)
+flushq(Queue *q)
{
Block *bp;
@@ 208,7 385,6 @@ freeq(Queue *q)
q = WR(q);
while(bp = getq(q))
freeb(bp);
- RD(q)->flag = 0;
}
/*
@@ 298,52 474,6 @@ putq(Queue *q, Block *bp)
}
int
-blen(Block *bp)
-{
- int len;
-
- len = 0;
- while(bp) {
- len += BLEN(bp);
- bp = bp->next;
- }
-
- return len;
-}
-
-/*
- * bround - round a block chain to some 2^n number of bytes
- */
-int
-bround(Block *bp, int amount)
-{
- Block *last;
- int len, pad;
-
- len = 0;
- SET(last); /* Ken's magic */
-
- while(bp) {
- len += BLEN(bp);
- last = bp;
- bp = bp->next;
- }
-
- pad = ((len + amount) & ~amount) - len;
- if(pad) {
- last->next = allocb(pad);
- last->flags &= ~S_DELIM;
- last = last->next;
- memset(last->wptr, 0, pad);
- last->wptr += pad;
- last->flags |= S_DELIM;
-
- }
-
- return len + pad;
-}
-
-int
putb(Blist *q, Block *bp)
{
int delim;
@@ 440,210 570,36 @@ getb(Blist *q)
bp = q->first;
if(bp) {
- q->first = bp->next;
- if(q->first == 0)
- q->last = 0;
- q->len -= BLEN(bp);
- bp->next = 0;
- }
- return bp;
-}
-
-/*
- * make sure the first block has n bytes
- */
-Block *
-pullup(Block *bp, int n)
-{
- Block *nbp;
- int i;
-
- /*
- * this should almost always be true, the rest it
- * just for to avoid every caller checking.
- */
- if(BLEN(bp) >= n)
- return bp;
-
- /*
- * if not enough room in the first block,
- * add another to the front of the list.
- */
- if(bp->lim - bp->rptr < n){
- nbp = allocb(n);
- nbp->next = bp;
- bp = nbp;
- }
-
- /*
- * copy bytes from the trailing blocks into the first
- */
- n -= BLEN(bp);
- while(nbp = bp->next){
- i = BLEN(nbp);
- if(i >= n) {
- memmove(bp->wptr, nbp->rptr, n);
- bp->wptr += n;
- nbp->rptr += n;
- return bp;
- } else {
- memmove(bp->wptr, nbp->rptr, i);
- bp->wptr += i;
- bp->next = nbp->next;
- nbp->next = 0;
- freeb(nbp);
- }
- }
- freeb(bp);
- return 0;
-}
-
-/*
- * expand a block list to be one block, len bytes long
- */
-Block*
-expandb(Block *bp, int len)
-{
- Block *nbp, *new;
- int i;
- ulong delim = 0;
-
- new = allocb(len);
- if(new == 0){
- freeb(bp);
- return 0;
- }
-
- /*
- * copy bytes into new block
- */
- for(nbp = bp; len>0 && nbp; nbp = nbp->next){
- delim = nbp->flags & S_DELIM;
- i = BLEN(nbp);
- if(i > len) {
- memmove(new->wptr, nbp->rptr, len);
- new->wptr += len;
- break;
- } else {
- memmove(new->wptr, nbp->rptr, i);
- new->wptr += i;
- len -= i;
- }
- }
- if(len){
- memset(new->wptr, 0, len);
- new->wptr += len;
- }
- new->flags |= delim;
- freeb(bp);
- return new;
-
-}
-
-/*
- * grow the front of a list of blocks by n bytes
- */
-Block *
-prepend(Block *bp, int n)
-{
- Block *nbp;
-
- if(bp->base && (bp->rptr - bp->base)>=n){
- /*
- * room for channel number in first block of message
- */
- bp->rptr -= n;
- return bp;
- } else {
- /*
- * make new block, put message number at end
- */
- nbp = allocb(2);
- nbp->next = bp;
- nbp->wptr = nbp->lim;
- nbp->rptr = nbp->wptr - n;
- return nbp;
- }
-}
-
-
-/*
- * put a block into the bit bucket
- */
-void
-nullput(Queue *q, Block *bp)
-{
- USED(q);
- if(bp->type == M_HANGUP)
- freeb(bp);
- else {
- freeb(bp);
- error(Ehungup);
- }
-}
-
-/*
- * find the info structure for line discipline 'name'
- */
-Qinfo *
-qinfofind(char *name)
-{
- Qinfo *qi;
-
- if(name == 0)
- return 0;
- for(qi = lds; qi; qi = qi->next)
- if(strcmp(qi->name, name)==0)
- return qi;
- return 0;
-}
-
-/*
- * send a hangup up a stream
- */
-static void
-hangup(Stream *s)
-{
- Block *bp;
-
- bp = allocb(0);
- bp->type = M_HANGUP;
- (*s->devq->put)(s->devq, bp);
+ q->first = bp->next;
+ if(q->first == 0)
+ q->last = 0;
+ q->len -= BLEN(bp);
+ bp->next = 0;
+ }
+ return bp;
}
+
/*
- * parse a string and return a pointer to the second element if the
- * first matches name. bp->rptr will be updated to point to the
- * second element.
- *
- * return 0 if no match.
- *
- * it is assumed that the block data is null terminated. streamwrite
- * guarantees this.
+ * put a block into the bit bucket
*/
-int
-streamparse(char *name, Block *bp)
+void
+nullput(Queue *q, Block *bp)
{
- int len;
-
- len = strlen(name);
- if(BLEN(bp) < len)
- return 0;
- if(strncmp(name, (char *)bp->rptr, len)==0){
- if(bp->rptr[len] == ' ')
- bp->rptr += len+1;
- else if(bp->rptr[len])
- return 0;
- else
- bp->rptr += len;
- while(*bp->rptr==' ' && bp->wptr>bp->rptr)
- bp->rptr++;
- return 1;
+ USED(q);
+ if(bp->type == M_HANGUP)
+ freeb(bp);
+ else {
+ freeb(bp);
+ error(Ehungup);
}
- return 0;
}
/*
+ * Part 3) Streams
+ */
+
+/*
* the per stream directory structure
*/
Dirtab streamdir[]={
@@ 652,6 608,34 @@ Dirtab streamdir[]={
};
/*
+ * hash buckets containing all streams
+ */
+enum
+{
+ Nbits= 5,
+ Nhash= 1<<Nbits,
+ Nmask= Nhash-1,
+};
+typedef struct Sthash Sthash;
+struct Sthash
+{
+ QLock;
+ Stream *s;
+};
+static Sthash ht[Nhash];
+
+static void hangup(Stream*);
+
+void
+streaminit(void)
+{
+ /*
+ * make stream modules available
+ */
+ streaminit0();
+}
+
+/*
* A stream device consists of the contents of streamdir plus
* any directory supplied by the actual device.
*
@@ 678,6 662,15 @@ streamgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
}
/*
+ * return a hash bucket for a stream
+ */
+static Sthash*
+hash(int type, int dev, int id)
+{
+ return &ht[(type*7*7 + dev*7 + id) & Nmask];
+}
+
+/*
* create a new stream, if noopen is non-zero, don't increment the open count
*/
Stream *
@@ 685,46 678,61 @@ streamnew(ushort type, ushort dev, ushort id, Qinfo *qi, int noopen)
{
Stream *s;
Queue *q;
+ Sthash *hb;
+
+ hb = hash(type, dev, id);
/*
- * find a free stream struct
+ * if the stream already exists, just increment the reference counts.
*/
- for(s = slist; s < &slist[conf.nstream]; s++) {
- if(s->inuse == 0){
- if(canqlock(s)){
- if(s->inuse == 0)
- break;
+ qlock(hb);
+ for(s = hb->s; s; s = s->next) {
+ if(s->type == type && s->dev == dev && s->id == id){
+ s->inuse++;
+ qunlock(hb);
+ if(noopen == 0){
+ qlock(s);
+ s->opens++;
qunlock(s);
}
+ return s;
}
}
- if(s == &slist[conf.nstream]){
- print("no more streams\n");
- exhausted("streams");
- }
- if(waserror()){
- qunlock(s);
- streamclose1(s);
- nexterror();
- }
/*
- * identify the stream
+ * create and init a new stream
*/
+ s = smalloc(sizeof(Stream));
+ s->inuse = 1;
s->type = type;
s->dev = dev;
s->id = id;
s->err = 0;
+ s->hread = 0;
+ s->next = hb->s;
+ hb->s = s;
+
+ /*
+ * The ordering of these 2 instructions is very important.
+ * It makes sure we finish the stream initialization before
+ * anyone else can access it.
+ */
+ qlock(s);
+ qunlock(hb);
+
+ if(waserror()){
+ qunlock(s);
+ streamclose1(s);
+ nexterror();
+ }
/*
* hang a device and process q off the stream
*/
- s->inuse = 1;
if(noopen)
s->opens = 0;
else
s->opens = 1;
- s->hread = 0;
q = allocq(&procinfo);
WR(q)->ptr = s;
RD(q)->ptr = s;
@@ 745,72 753,58 @@ streamnew(ushort type, ushort dev, ushort id, Qinfo *qi, int noopen)
}
/*
- * (Re)open a stream. If this is the first open, create a stream.
+ * Associate a stream with a channel
*/
void
streamopen(Chan *c, Qinfo *qi)
{
- Stream *s;
- Queue *q;
-
- /*
- * if the stream already exists, just increment the reference counts.
- */
- for(s = slist; s < &slist[conf.nstream]; s++) {
- if(s->inuse && s->type == c->type && s->dev == c->dev
- && s->id == STREAMID(c->qid.path)){
- qlock(s);
- if(s->inuse && s->type == c->type
- && s->dev == c->dev
- && s->id == STREAMID(c->qid.path)){
- s->inuse++;
- s->opens++;
- c->stream = s;
- qunlock(s);
- return;
- }
- qunlock(s);
- }
- }
-
- /*
- * create a new stream
- */
c->stream = streamnew(c->type, c->dev, STREAMID(c->qid.path), qi, 0);
}
/*
- * Enter a stream. Increment the reference count so it can't disappear
- * under foot.
+ * Enter a stream only if the stream exists and is open. Increment the
+ * reference count so it can't disappear under foot.
+ *
+ * Return -1 if the stream no longer exists or is not opened.
*/
int
streamenter(Stream *s)
{
- qlock(s);
- if(s->opens == 0){
- qunlock(s);
- return -1;
- }
- s->inuse++;
- qunlock(s);
- return 0;
+ Sthash *hb;
+ Stream *ns;
+
+ hb = hash(s->type, s->dev, s->id);
+ qlock(hb);
+ for(ns = hb->s; ns; ns = ns->next)
+ if(s->type == ns->type && s->dev == ns->dev && s->id == ns->id){
+ s->inuse++;
+ qunlock(hb);
+ if(s->opens == 0){
+ streamexit(s, 1);
+ return -1;
+ }
+ return 0;
+ }
+ qunlock(hb);
+ return -1;
}
/*
* Decrement the reference count on a stream. If the count is
* zero, free the stream.
*/
-int
+void
streamexit(Stream *s, int locked)
{
Queue *q;
Queue *nq;
- int rv;
char *name;
+ Sthash *hb;
+ Stream **l, *ns;
- if(!locked)
- qlock(s);
- if(s->inuse == 1){
+ hb = hash(s->type, s->dev, s->id);
+ qlock(hb);
+ if(s->inuse-- == 1){
if(s->opens != 0)
panic("streamexit %d %s\n", s->opens, s->devq->info->name);
@@ 821,20 815,28 @@ streamexit(Stream *s, int locked)
nq = q->next;
freeq(q);
}
- s->id = s->dev = s->type = 0;
if(s->err)
freeb(s->err);
+
+ /*
+ * unchain it from the hash bucket and free
+ */
+ l = &hb->s;
+ for(ns = hb->s; ns; ns = ns->next){
+ if(s == ns){
+ *l = s->next;
+ break;
+ }
+ l = &ns->next;
+ }
+ free(s);
}
- s->inuse--;
- rv = s->inuse;
- if(!locked)
- qunlock(s);
- return rv;
+ qunlock(hb);
}
/*
- * On the last close of a stream, for each queue on the
- * stream release its blocks and call its close routine.
+ * Decrement the open count. When it goes to zero, call the close
+ * routines for each queue in the stream.
*/
int
streamclose1(Stream *s)
@@ 844,10 846,10 @@ streamclose1(Stream *s)
int rv;
/*
- * decrement the reference count
+ * decrement the open count
*/
qlock(s);
- if(s->opens == 1){
+ if(s->opens-- == 1){
/*
* descend the stream closing the queues
*/
@@ 874,13 876,13 @@ streamclose1(Stream *s)
flushq(q);
}
}
- rv = --(s->opens);
+ rv = s->opens;
+ qunlock(s);
/*
* leave it and free it
*/
streamexit(s, 1);
- qunlock(s);
return rv;
}
int
@@ 940,37 942,19 @@ stputq(Queue *q, Block *bp)
}
/*
- * read a string. update the offset accordingly.
- */
-long
-stringread(uchar *buf, long n, char *str, ulong offset)
-{
- long i;
-
- i = strlen(str);
- i -= offset;
- if(i<n)
- n = i;
- if(n<0)
- return 0;
- memmove(buf, str + offset, n);
- return n;
-}
-
-/*
* return the stream id
*/
long
streamctlread(Chan *c, void *vbuf, long n)
{
- uchar *buf = vbuf;
+ char *buf = vbuf;
char num[32];
Stream *s;
s = c->stream;
if(STREAMTYPE(c->qid.path) == Sctlqid){
sprint(num, "%d", s->id);
- return stringread(buf, n, num, c->offset);
+ return readstr(c->offset, buf, n, num);
} else {
if(CHDIR & c->qid.path)
return devdirread(c, vbuf, n, 0, 0, streamgen);
@@ 1245,26 1229,6 @@ streamwrite(Chan *c, void *a, long n, int docopy)
}
/*
- * like andrew's getmfields but no hidden state
- */
-int
-getfields(char *lp, char **fields, int n, char sep)
-{
- int i;
-
- for(i=0; lp && *lp && i<n; i++){
- while(*lp == sep)
- *lp++=0;
- if(*lp == 0)
- break;
- fields[i]=lp;
- while(*lp && *lp != sep)
- lp++;
- }
- return i;
-}
-
-/*
* stat a stream. the length is the number of bytes up to the
* first delimiter.
*/
@@ 1295,88 1259,72 @@ streamstat(Chan *c, char *db, char *name)
convD2M(&dir, db);
}
-Block *
-copyb(Block *bp, int count)
+/*
+ * send a hangup up a stream
+ */
+static void
+hangup(Stream *s)
{
- Block *nb, *head, **p;
- int l;
+ Block *bp;
- p = &head;
- while(count) {
- l = BLEN(bp);
- if(count < l)
- l = count;
- nb = allocb(l);
- if(nb == 0)
- panic("copyb.1");
- memmove(nb->wptr, bp->rptr, l);
- nb->wptr += l;
- count -= l;
- if(bp->flags & S_DELIM)
- nb->flags |= S_DELIM;
- *p = nb;
- p = &nb->next;
- bp = bp->next;
- if(bp == 0)
- break;
- }
- if(count) {
- nb = allocb(count);
- if(nb == 0)
- panic("copyb.2");
- memset(nb->wptr, 0, count);
- nb->wptr += count;
- nb->flags |= S_DELIM;
- *p = nb;
- }
- if(blen(head) == 0)
- print("copyb: zero length\n");
+ bp = allocb(0);
+ bp->type = M_HANGUP;
+ (*s->devq->put)(s->devq, bp);
+}
- return head;
+/*
+ * parse a string and return a pointer to the second element if the
+ * first matches name. bp->rptr will be updated to point to the
+ * second element.
+ *
+ * return 0 if no match.
+ *
+ * it is assumed that the block data is null terminated. streamwrite
+ * guarantees this.
+ */
+int
+streamparse(char *name, Block *bp)
+{
+ int len;
+
+ len = strlen(name);
+ if(BLEN(bp) < len)
+ return 0;
+ if(strncmp(name, (char *)bp->rptr, len)==0){
+ if(bp->rptr[len] == ' ')
+ bp->rptr += len+1;
+ else if(bp->rptr[len])
+ return 0;
+ else
+ bp->rptr += len;
+ while(*bp->rptr==' ' && bp->wptr>bp->rptr)
+ bp->rptr++;
+ return 1;
+ }
+ return 0;
}
/*
- * Dump all block information of how many blocks are in which queues
+ * like andrew's getmfields but no hidden state
*/
-void
-dumpblocks(Queue *q, char c)
+int
+getfields(char *lp, char **fields, int n, char sep)
{
- Block *bp;
- uchar *cp;
+ int i;
- lock(q);
- for(bp = q->first; bp; bp = bp->next){
- print("%c %c%d%c", c, bp->type == M_DATA ? 'd' : 'c',
- bp->wptr-bp->rptr, (bp->flags&S_DELIM)?'D':' ');
- for(cp = bp->rptr; cp<bp->wptr && cp<bp->rptr+30; cp++)
- print(" %.2x", *cp);
- print("\n");
+ for(i=0; lp && *lp && i<n; i++){
+ while(*lp == sep)
+ *lp++=0;
+ if(*lp == 0)
+ break;
+ fields[i]=lp;
+ while(*lp && *lp != sep)
+ lp++;
}
- unlock(q);
+ return i;
}
void
dumpqueues(void)
{
- Queue *q;
- int count, qcount;
- Block *bp;
-
- print("\n");
- qcount = 0;
- for(q = qlist; q < qlist + conf.nqueue; q++, q++){
- if(!(q->flag & QINUSE))
- continue;
- qcount++;
- print("%10s %ux R n %d l %d f %ux r %ux ",
- q->info->name, q,
- q->nb, q->len, q->flag, &(q->r));
- print(" W n %d l %d f %ux r %ux next %lux put %lux Rz %lux",
- WR(q)->nb, WR(q)->len,
- WR(q)->flag, &(WR(q)->r), q->next, q->put, q->rp);
- print("\n");
- dumpblocks(q, 'R');
- dumpblocks(WR(q), 'W');
- }
- print("%d queues\n", qcount);
}
M port/sturp.c => port/sturp.c +22 -26
@@ 34,6 34,7 @@ struct urpstat {
struct Urp {
QLock;
+ Urp *list; /* list of all urp structures */
short state; /* flags */
Rendez r; /* process waiting for output to finish */
@@ 60,7 61,13 @@ struct Urp {
ulong timer; /* timeout for xmit */
int rexmit;
};
-Urp *urp;
+
+/* list of allocated urp structures (never freed) */
+struct
+{
+ Lock;
+ Urp *urp;
+} urpalloc;
Rendez urpkr;
QLock urpkl;
@@ 135,7 142,6 @@ Qinfo urpinfo =
static void
urpreset(void)
{
- urp = (Urp *)xalloc(conf.nurp*sizeof(Urp));
}
static void
@@ 155,9 161,9 @@ urpopen(Queue *q, Stream *s)
}
/*
- * find a free urp structure
+ * find an unused urp structure
*/
- for(up = urp; up < &urp[conf.nurp]; up++){
+ for(up = urpalloc.urp; up; up = up->list){
if(up->state == 0){
qlock(up);
if(up->state == 0)
@@ 165,15 171,17 @@ urpopen(Queue *q, Stream *s)
qunlock(up);
}
}
- if(up == &urp[conf.nurp]){
- q->ptr = 0;
- WR(q)->ptr = 0;
- exhausted("urp structures");
+ if(up == 0){
+ /*
+ * none available, create a new one, they are never freed
+ */
+ up = smalloc(sizeof(Urp));
+ qlock(up);
+ lock(&urpalloc);
+ up->list = urpalloc.urp;
+ urpalloc.urp = up;
+ unlock(&urpalloc);
}
-/*
- q->flag |= QDEBUG;
- q->other->flag |= QDEBUG;
-*/
q->ptr = q->other->ptr = up;
q->rp = &urpkr;
up->rq = q;
@@ 993,16 1001,15 @@ initinput(Urp *up, int window)
static void
urpkproc(void *arg)
{
- Urp *up, *eup;
+ Urp *up;
USED(arg);
if(waserror())
;
- eup = urp + conf.nurp;
for(;;){
- for(up = urp; up < eup; up++){
+ for(up = urpalloc.urp; up; up = up->list){
if(up->state==0 || (up->state&HUNGUP))
continue;
if(!canqlock(up))
@@ 1044,17 1051,6 @@ urpvomit(char *msg, Urp* up)
up->rq->next->len);
}
-int
-urpdump(void)
-{
- Urp *up;
-
- for(up = urp; up < &urp[conf.nurp]; up++)
- if(up->rq)
- urpvomit("", up);
- return 0;
-}
-
void
urpfillstats(Chan *c, char *buf, int len)
{
M port/sysproc.c => port/sysproc.c +11 -9
@@ 51,7 51,8 @@ sysrfork(ulong *arg)
if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
error(Ebadarg);
oeg = p->egrp;
- p->egrp = newegrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
if(flag & RFENVG)
envcpy(p->egrp, oeg);
closeegrp(oeg);
@@ 64,7 65,8 @@ sysrfork(ulong *arg)
else
if(flag & RFCFDG) {
ofg = p->fgrp;
- p->fgrp = newfgrp();
+ p->fgrp = smalloc(sizeof(Fgrp));
+ p->fgrp->ref = 1;
closefgrp(ofg);
}
if(flag & RFNOTEG)
@@ 110,8 112,10 @@ sysrfork(ulong *arg)
if(flag & (RFFDG|RFCFDG)) {
if(flag & RFFDG)
p->fgrp = dupfgrp(parent->fgrp);
- else
- p->fgrp = newfgrp();
+ else {
+ p->fgrp = smalloc(sizeof(Fgrp));
+ p->fgrp->ref = 1;
+ }
}
else {
p->fgrp = parent->fgrp;
@@ 136,12 140,10 @@ sysrfork(ulong *arg)
/* Environment group */
if(flag & (RFENVG|RFCENVG)) {
- if(flag & RFENVG) {
- p->egrp = newegrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
+ if(flag & RFENVG)
envcpy(p->egrp, parent->egrp);
- }
- else
- p->egrp = newegrp();
}
else {
p->egrp = parent->egrp;
M power/conf.h => power/conf.h +1 -8
@@ 4,16 4,9 @@ Conftab conftab[] = {
{"npage0", &conf.npage0 },
{"npage1", &conf.npage1 },
{"npage", &conf.npage },
+ {"upages", &conf.upages },
{"nimage", &conf.nimage },
{"nswap", &conf.nswap },
- {"nenv", &conf.nenv },
- {"nenvchar", &conf.nenvchar },
- {"npgenv", &conf.npgenv },
- {"nstream", &conf.nstream },
- {"nqueue", &conf.nqueue },
- {"nsrv", &conf.nsrv },
- {"nurp", &conf.nurp },
- {"nasync", &conf.nasync },
{"base0", &conf.base0 },
{"base1", &conf.base1 },
{"copymode", &conf.copymode },
M power/dat.h => power/dat.h +0 -8
@@ 43,14 43,6 @@ struct Conf
ulong upages; /* user page pool */
ulong nimage; /* number of page cache image headers */
ulong nswap; /* number of swap pages */
- ulong nenv; /* distinct environment values */
- ulong nenvchar; /* environment text storage */
- ulong npgenv; /* environment files per process group */
- ulong nstream; /* streams */
- ulong nqueue; /* stream queues */
- ulong nsrv; /* public servers (devsrv.c) */
- ulong nurp; /* max urp conversations */
- ulong nasync; /* number of async protocol modules */
ulong base0; /* base of bank 0 */
ulong base1; /* base of bank 1 */
ulong copymode; /* 0 is copy on write, 1 is copy on reference */
M power/devhs.c => power/devhs.c +7 -6
@@ 341,6 341,13 @@ hsoput(Queue *q, Block *bp)
freeb(bp);
return;
}
+ if(BLEN(bp) < 3){
+ bp = pullup(bp, 3);
+ if(bp == 0){
+ print("hsoput pullup failed\n");
+ return;
+ }
+ }
/*
* get a whole message before handing bytes to the device
@@ 363,12 370,6 @@ hsoput(Queue *q, Block *bp)
* parse message
*/
bp = getq(q);
- if(bp->wptr - bp->rptr < 3){
- freemsg(q, bp);
- qunlock(&hp->xmit);
- poperror();
- return;
- }
chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8);
ctl = bp->rptr[2];
bp->rptr += 3;
M power/main.c => power/main.c +0 -7
@@ 30,7 30,6 @@ main(void)
printinit();
duartspecial(0, &printq, &kbdq, 9600);
pageinit();
-xsummary();
tlbinit();
vecinit();
procinit0();
@@ 536,15 535,9 @@ confinit(void)
*/
conf.nmach = 1;
conf.nproc = 100;
- conf.npgenv = 4 * conf.nproc;
- conf.nenv = 4 * conf.nproc;
- conf.nenvchar = 20 * conf.nenv;
conf.nswap = 262144;
conf.nimage = 200;
- conf.nstream = 2 * conf.nproc;
- conf.nurp = 25;
conf.dkif = 1;
- conf.nqueue = 5 * conf.nstream;
conf.ipif = 8;
conf.ip = 64;
conf.arp = 32;
M ss/dat.h => ss/dat.h +0 -10
@@ 67,16 67,6 @@ struct Conf
ulong nimage; /* number of page cache image headers */
ulong nswap; /* number of swap blocks */
ulong upages; /* number of user pages */
- int nenv; /* distinct environment values */
- int nenvchar; /* environment text storage */
- int npgenv; /* environment files per process group */
- int nstream; /* streams */
- int nqueue; /* stream queues */
- int nsrv; /* public servers (devsrv.c) */
- int nbitmap; /* bitmap structs (devbit.c) */
- int nbitbyte; /* bytes of bitmap data (devbit.c) */
- int nfont; /* GFont structs (devbit.c) */
- int nsubfont; /* Gsubfont structs (devbit.c) */
int nurp; /* max urp conversations */
int nasync; /* number of async protocol modules */
int copymode; /* 0 is copy on write, 1 is copy on reference */
M ss/main.c => ss/main.c +4 -9
@@ 128,8 128,10 @@ userinit(void)
p = newproc();
p->pgrp = newpgrp();
- p->egrp = newegrp();
- p->fgrp = newfgrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
+ p->fgrp = smalloc(sizeof(Fgrp));
+ p->fgrp->ref = 1;
p->procmode = 0640;
strcpy(p->text, "*init*");
@@ 210,13 212,6 @@ confinit(void)
conf.nproc = 50*mul;
conf.nswap = 4096;
conf.nimage = 50;
- conf.nenv = 100*mul;
- conf.nenvchar = 8000*mul;
- conf.npgenv = 200*mul;
- conf.nstream = 40 + 32*mul;
- conf.nqueue = 5 * conf.nstream;
- conf.nurp = 32;
- conf.nasync = 1;
conf.copymode = 0; /* copy on write */
conf.ipif = 8;
conf.ip = 64;