From 7ebeec62c723e19c9fdc452cbce9aac8b7de857e Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 1 Nov 1990 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1990-11-01 --- gnot/devdk.c | 68 ++++--- gnot/devincon.c | 59 +++++- gnot/stream.c | 1 - port/devdk.c | 472 ++++++++++++++++++++++++++++++------------------ port/page.c | 11 +- port/proc.c | 83 ++++++--- port/stream.c | 7 +- power/devhs.c | 12 ++ power/fns.h | 3 +- 9 files changed, 473 insertions(+), 243 deletions(-) diff --git a/gnot/devdk.c b/gnot/devdk.c index 1183a078939652f0cc9a246bf0ea9205adcfdc33..dcc0a268a499f59beae941fcd401102cdefe04c3 100644 --- a/gnot/devdk.c +++ b/gnot/devdk.c @@ -369,17 +369,17 @@ dkstopen(Queue *q, Stream *s) Line *lp; dp = &dk[s->dev]; + q->other->ptr = q->ptr = lp = &dp->line[s->id]; + lp->dp = dp; lock(dp); if(dp->opened==0 || streamenter(dp->s)<0){ unlock(dp); error(0, Ehungup); } unlock(dp); - q->other->ptr = q->ptr = lp = &dp->line[s->id]; - lp->dp = dp; - lp->rq = q; - if(lp->state == Lclosed) + if(lp->state==Lclosed) lp->state = Lopened; + lp->rq = q; } /* @@ -395,22 +395,35 @@ dkstclose(Queue *q) lp = (Line *)q->ptr; dp = lp->dp; + /* + * if we never got going, we're done + */ + if(lp->rq == 0){ + lp->state = Lclosed; + return; + } + /* * decrement ref count on mux'd line */ streamexit(dp->s, 0); /* - * don't tell controller about closing down the csc + * these states don't need the datakit */ - if(lp - dp->line == dp->ncsc) + switch(lp->state){ + case Lclosed: + case Llclose: + case Lopened: + lp->state = Lclosed; goto out; + } c = 0; if(waserror()){ + lp->state = Lclosed; if(c) close(c); - lp->state = Lclosed; goto out; } c = dkopenline(dp, dp->ncsc); @@ -419,10 +432,6 @@ dkstclose(Queue *q) * shake hands with dk */ switch(lp->state){ - case Lclosed: - case Llclose: - break; - case Lrclose: dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Lclosed; @@ -442,9 +451,6 @@ dkstclose(Queue *q) dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; - - case Lopened: - lp->state = Lclosed; } poperror(); close(c); @@ -769,9 +775,10 @@ dkopen(Chan *c, int omode) } if(lp == end) error(0, Enodev); + lp->state = Lopened; + qunlock(lp); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); - qunlock(lp); break; case Dlistenqid: /* @@ -819,8 +826,6 @@ dkcreate(Chan *c, char *name, int omode, ulong perm) void dkclose(Chan *c) { - Dk *dp; - if(c->stream) streamclose(c); } @@ -1183,13 +1188,11 @@ dklisten(Chan *c) /* * open the data file */ - dc = dkattach(dp->name); + dc = dkopenline(dp, STREAMID(c->qid)); if(waserror()){ close(dc); nexterror(); } - dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); - dkopen(dc, ORDWR); /* * wait for a call in @@ -1448,11 +1451,8 @@ dkcsckproc(void *a) break; case T_RESTART: /* datakit reboot */ - print("dk restart\n"); - if(line >=0 && linelines){ - print("maxlines=%d\n", line+1); + if(line >=0 && linelines) dp->lines=line+1; - } break; default: @@ -1530,6 +1530,9 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) break; case D_CLOSEALL: + /* + * datakit wants us to close all lines + */ for(line = dp->ncsc+1; line < dp->lines; line++){ lp = &dp->line[line]; switch (lp->state) { @@ -1544,8 +1547,8 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) case Lconnected: case Llistening: case Lackwait: - dkhangup(lp); lp->state = Lrclose; + dkhangup(lp); break; case Lopened: @@ -1618,6 +1621,21 @@ dktimer(void *a) c = 0; if(waserror()){ + /* + * hang up any calls waiting for the dk + */ + for (i=dp->ncsc+1; ilines; i++){ + lp = &dp->line[i]; + switch(lp->state){ + case Llclose: + lp->state = Lclosed; + break; + + case Ldialing: + dkreplymesg(dp, (Dkmsg *)0, i); + break; + } + } if(c) close(c); return; diff --git a/gnot/devincon.c b/gnot/devincon.c index e2b479cc67b8aa3ea17ce51c3f83fdc74aab7c2e..a00c40fc1e575044f0a5993fb65c34d41b30f8a3 100644 --- a/gnot/devincon.c +++ b/gnot/devincon.c @@ -158,6 +158,41 @@ inconset(Incon *ip, int cnt, int del) dev->cmd = INCON_RUN | ENABLE_IRQ; } +/* + * parse a set request + */ +void +inconsetctl(Incon *ip, Block *bp) +{ + char *field[3]; + int n; + int del; + int cnt; + + del = 15; + n = getfields((char *)bp->rptr, field, 3, ' '); + switch(n){ + default: + freeb(bp); + error(0, Ebadarg); + case 2: + del = strtol(field[1], 0, 0); + if(del<0 || del>15){ + freeb(bp); + error(0, Ebadarg); + } + /* fall through */ + case 1: + cnt = strtol(field[0], 0, 0); + if(cnt<0 || cnt>15){ + freeb(bp); + error(0, Ebadarg); + } + } + inconset(ip, cnt, del); + freeb(bp); +} + static void nop(void) { @@ -463,8 +498,13 @@ inconoput(Queue *q, Block *bp) int ctl; int n, size; + ip = (Incon *)q->ptr; + if(bp->type != M_DATA){ - freeb(bp); + if(streamparse("inconset", bp)) + inconsetctl(ip, bp); + else + freeb(bp); return; } @@ -477,7 +517,6 @@ inconoput(Queue *q, Block *bp) /* * one transmitter at a time */ - ip = (Incon *)q->ptr; qlock(&ip->xmit); dev = ip->dev; @@ -598,6 +637,7 @@ inconkproc(void *arg) Incon *ip; Block *bp, *nbp; int i, n; + int locked; ip = (Incon *)arg; ip->kstarted = 1; @@ -610,11 +650,14 @@ inconkproc(void *arg) bp->wptr += 3; } - /* - * ignore errors - */ - if(waserror()) - ; + locked = 0; + if(waserror()){ + if(locked) + qunlock(ip); + ip->kstarted = 0; + wakeup(&ip->r); + return; + } for(;;){ /* @@ -625,6 +668,7 @@ inconkproc(void *arg) /* * die if the device is closed */ + locked = 1; qlock(ip); if(ip->rq == 0){ qunlock(ip); @@ -646,6 +690,7 @@ inconkproc(void *arg) ip->ri = (ip->ri+1)%Nin; } qunlock(ip); + locked = 0; } } diff --git a/gnot/stream.c b/gnot/stream.c index d4380b8da0ddea6ca3fdd6b509c6c068c049b07f..367a86acf4e2e8697cd95119330fa96acc8f6a49 100644 --- a/gnot/stream.c +++ b/gnot/stream.c @@ -794,7 +794,6 @@ streamclose1(Stream *s) for(q = s->procq; q; q = q->next){ if(q->info->close) (*q->info->close)(q->other); - RD(q)->put = nullput; WR(q)->put = nullput; /* diff --git a/port/devdk.c b/port/devdk.c index c492391c541978c6d95227b7d84ed86ed3e68141..dcc0a268a499f59beae941fcd401102cdefe04c3 100644 --- a/port/devdk.c +++ b/port/devdk.c @@ -116,18 +116,21 @@ struct Line { * dkmux line discipline is pushed onto. */ struct Dk { - QLock; - int ref; + Lock; + int opened; char name[64]; /* dk name */ Queue *wq; /* dk output queue */ + Stream *s; int lines; /* number of lines */ int ncsc; /* csc line number */ - Chan *csc; /* common signalling line */ + Chan *csc; Line line[Nline]; int restart; int urpwindow; + Rendez timer; }; static Dk dk[Ndk]; +static Lock dklock; /* * conversation states (for Line.state) @@ -178,17 +181,19 @@ extern Qinfo urpinfo; * predeclared */ Chan* dkattach(char*); -static void dkmuxconfig(Dk*, Block*); -static int dkmesg(Dk*, int, int, int, int); +static void dkmuxconfig(Queue*, Block*); +static Chan* dkopenline(Dk*, int); +static int dkmesg(Chan*, int, int, int, int); static void dkcsckproc(void*); static int dklisten(Chan*); static void dkanswer(Chan*, int, int); static void dkwindow(Chan*); static void dkcall(int, Chan*, char*, char*, char*); static void dktimer(void*); -static void dkchgmesg(Dk*, Dkmsg*, int); +static void dkchgmesg(Chan*, Dk*, Dkmsg*, int); static void dkreplymesg(Dk*, Dkmsg*, int); Chan* dkopen(Chan*, int); +static void dkhangup(Line*); /* * the datakit multiplexor stream module definition @@ -200,33 +205,46 @@ static void dkmuxiput(Queue *, Block *); Qinfo dkmuxinfo = { dkmuxiput, dkmuxoput, dkmuxopen, dkmuxclose, "dkmux" }; /* - * a new dkmux. find a free dk structure and assign it to this queue. - */ -static void -dkmuxopen(Queue *q, Stream *s) + * Look for a dk struct with a name. If none exists, create one. + */ +static Dk * +dkalloc(char *name) { Dk *dp; - int i; + Dk *freep; + lock(&dklock); + freep = 0; for(dp = dk; dp < &dk[Ndk]; dp++){ - if(dp->wq == 0){ - qlock(dp); - if(dp->wq) { - /* someone was faster than us */ - qunlock(dp); - continue; - } - q->ptr = q->other->ptr = (void *)dp; - dp->csc = 0; - dp->ncsc = 4; - dp->lines = 16; - dp->name[0] = 0; - dp->wq = WR(q); - qunlock(dp); - return; + if(strcmp(name, dp->name) == 0){ + unlock(&dklock); + return dp; } + if(dp->name[0] == 0) + freep = dp; + } + if(freep == 0){ + unlock(&dklock); + error(0, Enoifc); } - error(0, Enoifc); + dp = freep; + dp->opened = 0; + dp->s = 0; + dp->ncsc = 1; + strncpy(dp->name, name, sizeof(freep->name)); + unlock(&dklock); + return dp; +} + +/* + * a new dkmux. find a free dk structure and assign it to this queue. + * when we get though here dp->s is meaningful and the name is set to "/". + */ +static void +dkmuxopen(Queue *q, Stream *s) +{ + RD(q)->ptr = s; + WR(q)->ptr = 0; } /* @@ -236,13 +254,30 @@ static void dkmuxclose(Queue *q) { Dk *dp; + int i; - dp = (Dk *)q->ptr; - qlock(dp); - if(dp->csc) - close(dp->csc); - dp->wq = 0; - qunlock(dp); + dp = WR(q)->ptr; + if(dp == 0) + return; + + /* + * 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->line[i]); + + /* + * wakeup the timer so it can die + */ + wakeup(&dp->timer); } /* @@ -251,12 +286,9 @@ dkmuxclose(Queue *q) static void dkmuxoput(Queue *q, Block *bp) { - Dk *dp; - - dp = (Dk *)q->ptr; if(bp->type != M_DATA){ if(streamparse("config", bp)) - dkmuxconfig(dp, bp); + dkmuxconfig(q, bp); else PUTNEXT(q, bp); return; @@ -272,7 +304,7 @@ dkmuxoput(Queue *q, Block *bp) * * Simplifying assumption: one put == one message && the channel number * is in the first block. If this isn't true, demultiplexing will not - * work. + * work. */ static void dkmuxiput(Queue *q, Block *bp) @@ -281,6 +313,14 @@ dkmuxiput(Queue *q, Block *bp) Line *lp; int line; + /* + * not configured yet + */ + if(q->other->ptr == 0){ + freeb(bp); + return; + } + dp = (Dk *)q->ptr; if(bp->type != M_DATA){ PUTNEXT(q, bp); @@ -331,9 +371,15 @@ dkstopen(Queue *q, Stream *s) dp = &dk[s->dev]; q->other->ptr = q->ptr = lp = &dp->line[s->id]; lp->dp = dp; - lp->rq = q; - if(lp->state == Lclosed) + lock(dp); + if(dp->opened==0 || streamenter(dp->s)<0){ + unlock(dp); + error(0, Ehungup); + } + unlock(dp); + if(lp->state==Lclosed) lp->state = Lopened; + lp->rq = q; } /* @@ -344,42 +390,72 @@ dkstclose(Queue *q) { Dk *dp; Line *lp; + Chan *c; lp = (Line *)q->ptr; dp = lp->dp; /* - * shake hands with dk + * if we never got going, we're done + */ + if(lp->rq == 0){ + lp->state = Lclosed; + return; + } + + /* + * decrement ref count on mux'd line + */ + streamexit(dp->s, 0); + + /* + * these states don't need the datakit */ switch(lp->state){ case Lclosed: case Llclose: - break; + case Lopened: + lp->state = Lclosed; + goto out; + } + c = 0; + if(waserror()){ + lp->state = Lclosed; + if(c) + close(c); + goto out; + } + c = dkopenline(dp, dp->ncsc); + + /* + * shake hands with dk + */ + switch(lp->state){ case Lrclose: - dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); + dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Lclosed; break; case Lackwait: - dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); + dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Llistening: - dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); + dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lconnected: - dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); + dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; - - case Lopened: - lp->state = Lclosed; } + poperror(); + close(c); +out: qlock(lp); lp->rq = 0; qunlock(lp); @@ -436,87 +512,102 @@ dkoput(Queue *q, Block *bp) * we can configure only once */ static void -dkmuxconfig(Dk *dp, Block *bp) +dkmuxconfig(Queue *q, Block *bp) { - Chan *c; + Dk *dp; char *fields[5]; int n; char buf[64]; - static int dktimeron; + char name[NAMELEN]; + int lines; + int ncsc; + int restart; + int window; - if(dp->csc != 0){ + if(WR(q)->ptr){ freeb(bp); - error(0, Ebadarg); + error(0, Egreg); } + /* + * defaults + */ + ncsc = 1; + restart = 1; + lines = 16; + window = WS_2K; + strcpy(name, "dk"); + /* * parse */ - dp->restart = 1; n = getfields((char *)bp->rptr, fields, 5, ' '); - strcpy(dp->name, "dk"); - dp->urpwindow = WS_2K; switch(n){ case 5: - dp->urpwindow = strtoul(fields[4], 0, 0); + window = strtoul(fields[4], 0, 0); case 4: - strncpy(dp->name, fields[3], sizeof(dp->name)); + strncpy(name, fields[3], sizeof(name)); case 3: if(strcmp(fields[2], "restart")!=0) - dp->restart = 0; + restart = 0; case 2: - dp->lines = strtoul(fields[1], 0, 0); + lines = strtoul(fields[1], 0, 0); case 1: - dp->ncsc = strtoul(fields[0], 0, 0); + ncsc = strtoul(fields[0], 0, 0); break; default: freeb(bp); error(0, Ebadarg); } freeb(bp); - if(dp->ncsc <= 0 || dp->lines <= dp->ncsc){ - dp->lines = 16; + if(ncsc <= 0 || lines <= ncsc) error(0, Ebadarg); - } - DPRINT("dkmuxconfig: ncsc=%d, lines=%d, restart=%d, name=\"%s\"\n", - dp->ncsc, dp->lines, dp->restart, dp->name); /* - * open a stream for the csc and push urp onto it + * set up */ - c = 0; - if(waserror()){ - if(c) - close(c); - nexterror(); + dp = dkalloc(name); + lock(dp); + if(dp->opened){ + unlock(dp); + error(0, Ebadarg); } - c = dkattach(dp->name); - c->qid = STREAMQID(dp->ncsc, Sdataqid); - dkopen(c, ORDWR); - dp->csc = c; + dp->ncsc = ncsc; + dp->lines = lines; + dp->restart = restart; + dp->urpwindow = window; + dp->s = RD(q)->ptr; + q->ptr = q->other->ptr = dp; + dp->opened = 1; + dp->wq = WR(q); + unlock(dp); + + /* + * open csc here so that boot, dktimer, and dkcsckproc aren't + * all fighting for it at once. + */ + dp->csc = dkopenline(dp, dp->ncsc); /* * tell datakit we've rebooted. It should close all channels. + * do this here to get it done before trying to open a channel. */ if(dp->restart) { - DPRINT("dkmuxconfig: restart %s\n", dp->name); - dkmesg(dp, T_ALIVE, D_RESTART, 0, 0); + DPRINT("dktimer: restart %s\n", dp->name); + dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0); } /* - * start a process to deal with it + * start a process to listen to csc messages */ sprint(buf, "csc.%s.%d", dp->name, dp->ncsc); kproc(buf, dkcsckproc, dp); - poperror(); /* - * start a keepalive process if one doesn't exist + * start a keepalive process */ - if(dktimeron == 0){ - dktimeron = 1; - kproc("dktimer", dktimer, 0); - } + sprint(buf, "timer.%s.%d", dp->name, dp->ncsc); + kproc(buf, dktimer, dp); } /* @@ -607,17 +698,11 @@ dkattach(char *spec) */ if(*spec == 0) spec = "dk"; - for(dp = dk; dp < &dk[Ndk]; dp++){ - qlock(dp); - if(dp->wq && strcmp(spec, dp->name)==0) { - dp->ref++; - qunlock(dp); - break; - } - qunlock(dp); - } - if(dp == &dk[Ndk]) - error(0, Enoifc); + dp = dkalloc(spec); + + /* + * return the new channel + */ c = devattach('k', spec); c->dev = dp - dk; return c; @@ -626,12 +711,6 @@ dkattach(char *spec) Chan* dkclone(Chan *c, Chan *nc) { - Dk *dp; - - dp = &dk[c->dev]; - qlock(dp); - dp->ref++; - qunlock(dp); return devclone(c, nc); } @@ -679,10 +758,10 @@ dkopen(Chan *c, int omode) error(0, Ebadarg); } else switch(STREAMTYPE(c->qid)){ case Dcloneqid: + dp = &dk[c->dev]; /* * get an unused device and open it's control file */ - dp = &dk[c->dev]; end = &dp->line[dp->lines]; for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){ if(lp->state == Lclosed && canqlock(lp)){ @@ -696,9 +775,10 @@ dkopen(Chan *c, int omode) } if(lp == end) error(0, Enodev); + lp->state = Lopened; + qunlock(lp); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); - qunlock(lp); break; case Dlistenqid: /* @@ -746,16 +826,8 @@ dkcreate(Chan *c, char *name, int omode, ulong perm) void dkclose(Chan *c) { - Dk *dp; - - /* real closing happens in dkstclose */ if(c->stream) streamclose(c); - - dp = &dk[c->dev]; - qlock(dp); - dp->ref--; - qunlock(dp); } long @@ -861,17 +933,36 @@ dkuserstr(Error *e, char *buf) consuserstr(e, buf); } +/* + * open the common signalling channel + */ +static Chan* +dkopenline(Dk *dp, int line) +{ + Chan *c; + + c = 0; + if(waserror()){ + if(c) + close(c); + nexterror(); + } + c = dkattach(dp->name); + c->qid = STREAMQID(line, Sdataqid); + dkopen(c, ORDWR); + poperror(); + + return c; +} + /* * send a message to the datakit on the common signaling line */ static int -dkmesg(Dk *dp, int type, int srv, int p0, int p1) +dkmesg(Chan *c, int type, int srv, int p0, int p1) { Dkmsg d; - Block *bp; - if(dp->csc == 0) - return -1; if(waserror()){ print("dkmesg: error\n"); return -1; @@ -888,7 +979,7 @@ dkmesg(Dk *dp, int type, int srv, int p0, int p1) d.param3h = 0; d.param4l = 0; d.param4h = 0; - streamwrite(dp->csc, (char *)&d, sizeof(Dkmsg), 1); + streamwrite(c, (char *)&d, sizeof(Dkmsg), 1); poperror(); return 0; } @@ -914,8 +1005,9 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) Dk *dp; Line *lp; Chan *dc; + Chan *csc; char *bang, *dot; - + line = STREAMID(c->qid); dp = &dk[c->dev]; lp = &dp->line[line]; @@ -968,16 +1060,22 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) } /* - * open the data file + * close temporary channels on error */ - dc = dkattach(dp->name); + dc = 0; + csc = 0; if(waserror()){ - close(dc); + if(csc) + close(csc); + if(dc) + close(dc); nexterror(); } - dc->qid = STREAMQID(line, Sdataqid); - dkopen(dc, ORDWR); + /* + * open the data file + */ + dc = dkopenline(dp, line); lp->calltolive = 4; lp->state = Ldialing; @@ -985,7 +1083,10 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) * tell the controller we want to make a call */ DPRINT("dialout\n"); - dkmesg(dp, t_val, d_val, line, W_WINDOW(dp->urpwindow,dp->urpwindow,2)); + csc = dkopenline(dp, dp->ncsc); + dkmesg(csc, t_val, d_val, line, W_WINDOW(dp->urpwindow,dp->urpwindow,2)); + close(csc); + csc = 0; /* * if redial, wait for a dial tone (otherwise we might send @@ -1087,13 +1188,11 @@ dklisten(Chan *c) /* * open the data file */ - dc = dkattach(dp->name); + dc = dkopenline(dp, STREAMID(c->qid)); if(waserror()){ close(dc); nexterror(); } - dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); - dkopen(dc, ORDWR); /* * wait for a call in @@ -1316,9 +1415,13 @@ dkcsckproc(void *a) Dk *dp; Dkmsg d; int line; - int i; - dp = (Dk *)a; + dp = a; + + if(waserror()){ + close(dp->csc); + return; + } /* * loop forever listening @@ -1326,6 +1429,8 @@ dkcsckproc(void *a) for(;;){ n = streamread(dp->csc, (char *)&d, (long)sizeof(d)); if(n != sizeof(d)){ + if(n == 0) + error(0, Ehungup); print("strange csc message %d\n", n); continue; } @@ -1334,7 +1439,7 @@ dkcsckproc(void *a) switch (d.type) { case T_CHG: /* controller wants to close a line */ - dkchgmesg(dp, &d, line); + dkchgmesg(dp->csc, dp, &d, line); break; case T_REPLY: /* reply to a dial request */ @@ -1346,11 +1451,8 @@ dkcsckproc(void *a) break; case T_RESTART: /* datakit reboot */ - print("dk restart\n"); - if(line >=0 && linelines){ - print("maxlines=%d\n", line+1); + if(line >=0 && linelines) dp->lines=line+1; - } break; default: @@ -1364,7 +1466,7 @@ dkcsckproc(void *a) * datakit requests or confirms closing a line */ static void -dkchgmesg(Dk *dp, Dkmsg *dialp, int line) +dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) { Line *lp; @@ -1373,7 +1475,7 @@ dkchgmesg(Dk *dp, Dkmsg *dialp, int line) case D_CLOSE: /* remote shutdown */ if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ - dkmesg(dp, T_CHG, D_CLOSE, line, 0); + dkmesg(c, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; @@ -1394,13 +1496,13 @@ dkchgmesg(Dk *dp, Dkmsg *dialp, int line) break; case Lopened: - dkmesg(dp, T_CHG, D_CLOSE, line, 0); + dkmesg(c, T_CHG, D_CLOSE, line, 0); break; case Llclose: case Lclosed: dkhangup(lp); - dkmesg(dp, T_CHG, D_CLOSE, line, 0); + dkmesg(c, T_CHG, D_CLOSE, line, 0); lp->state = Lclosed; break; } @@ -1409,7 +1511,7 @@ dkchgmesg(Dk *dp, Dkmsg *dialp, int line) case D_ISCLOSED: /* acknowledging a local shutdown */ if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ - dkmesg(dp, T_CHG, D_CLOSE, line, 0); + dkmesg(c, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; @@ -1428,6 +1530,9 @@ dkchgmesg(Dk *dp, Dkmsg *dialp, int line) break; case D_CLOSEALL: + /* + * datakit wants us to close all lines + */ for(line = dp->ncsc+1; line < dp->lines; line++){ lp = &dp->line[line]; switch (lp->state) { @@ -1442,8 +1547,8 @@ dkchgmesg(Dk *dp, Dkmsg *dialp, int line) case Lconnected: case Llistening: case Lackwait: - dkhangup(lp); lp->state = Lrclose; + dkhangup(lp); break; case Lopened: @@ -1503,57 +1608,72 @@ dkreplymesg(Dk *dp, Dkmsg *dialp, int line) } /* - * 15-second timer for all interfaces + * send a I'm alive message every 7.5 seconds and remind the dk of + * any closed channels it hasn't acknowledged. */ -static Rendez dkt; -static int -fuckit(void *a) -{ - return 0; -} static void dktimer(void *a) { int dki, i; Dk *dp; Line *lp; + Chan *c; - while(waserror()) - print("dktimer: error\n"); + c = 0; + if(waserror()){ + /* + * hang up any calls waiting for the dk + */ + for (i=dp->ncsc+1; ilines; i++){ + lp = &dp->line[i]; + switch(lp->state){ + case Llclose: + lp->state = Lclosed; + break; + + case Ldialing: + dkreplymesg(dp, (Dkmsg *)0, i); + break; + } + } + if(c) + close(c); + return; + } + + /* + * open csc + */ + dp = (Dk *)a; + c = dkopenline(dp, dp->ncsc); for(;;){ + if(dp->opened==0) + error(0, Ehungup); + /* - * loop through the active dks + * send keep alive */ - for(dki=0; dkicsc==0) - continue; - - /* - * send keep alive - */ - dkmesg(dp, T_ALIVE, D_CONTINUE, 0, 0); + dkmesg(c, T_ALIVE, D_CONTINUE, 0, 0); - /* - * remind controller of dead lines and - * timeout calls that take to long - */ - for (i=dp->ncsc+1; ilines; i++){ - lp = &dp->line[i]; - switch(lp->state){ - case Llclose: - dkmesg(dp, T_CHG, D_CLOSE, i, 0); - break; + /* + * remind controller of dead lines and + * timeout calls that take to long + */ + for (i=dp->ncsc+1; ilines; i++){ + lp = &dp->line[i]; + switch(lp->state){ + case Llclose: + dkmesg(c, T_CHG, D_CLOSE, i, 0); + break; - case Ldialing: - if(lp->calltolive==0 || --lp->calltolive!=0) - break; - dkreplymesg(dp, (Dkmsg *)0, i); + case Ldialing: + if(lp->calltolive==0 || --lp->calltolive!=0) break; - } + dkreplymesg(dp, (Dkmsg *)0, i); + break; } } - tsleep(&dkt, fuckit, 0, 7500); + tsleep(&dp->timer, return0, 0, 7500); } } diff --git a/port/page.c b/port/page.c index 193be982432f5dd33db77a3b41becfbd92272422..f4f991761c35c245f95765149fad2e3be863a078 100644 --- a/port/page.c +++ b/port/page.c @@ -190,11 +190,13 @@ loop: } #endif } - print("no physical memory\n"); - pprint("no physical memory\n"); unlock(&palloc); + if(freebroken()) + goto loop; if(u == 0) panic("newpage"); + print("no physical memory\n"); + pprint("no physical memory\n"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); @@ -316,6 +318,7 @@ neworig(ulong va, ulong npte, int flag, Chan *c) Orig *o; int i, freed; +lockloop: lock(&origalloc); loop: if(o = origalloc.free){ /* assign = */ @@ -370,8 +373,10 @@ o->nmod = 0; } if(freed) goto loop; - print("no origs freed\n"); unlock(&origalloc); + if(freebroken()) + goto lockloop; + print("no origs freed\n"); if(u == 0) panic("neworig"); u->p->state = Wakeme; diff --git a/port/proc.c b/port/proc.c index 625c711f4a9c53fbbfa7a8a2abad27eaf774ed52..577c5afec7f9699c2fc69ea516979c3d822dcb6d 100644 --- a/port/proc.c +++ b/port/proc.c @@ -343,6 +343,59 @@ postnote(Proc *p, int dolock, char *n, int flag) return 1; } + +/* + * weird thing: keep at most NBROKEN around + */ +#define NBROKEN 4 +struct{ + Lock; + int n; + Proc *p[NBROKEN]; +}broken; + +void +addbroken(Proc *c) +{ + int b; + + lock(&broken); + if(broken.n == NBROKEN){ + ready(broken.p[0]); + memcpy(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); + --broken.n; + } + broken.p[broken.n++] = c; + unlock(&broken); + c->state = Broken; + sched(); /* until someone lets us go */ + lock(&broken); + for(b=0; b 0){ + ready(broken.p[0]); + memcpy(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); + --broken.n; + } + unlock(&broken); + return n; +} + void pexit(char *s, int freemem) { @@ -418,35 +471,7 @@ pexit(char *s, int freemem) } out: if(!freemem){ - /* - * weird thing: keep at most NBROKEN around - */ - #define NBROKEN 4 - static struct{ - Lock; - int n; - Proc *p[NBROKEN]; - }broken; - int b; - - lock(&broken); - if(broken.n == NBROKEN){ - ready(broken.p[0]); - memcpy(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); - --broken.n; - } - broken.p[broken.n++] = c; - unlock(&broken); - c->state = Broken; - sched(); /* until someone lets us go */ - lock(&broken); - for(b=0; bpgrp); close(u->dot); diff --git a/port/stream.c b/port/stream.c index bd317bf6e200f6cbff3bab455c07c1d55394e138..367a86acf4e2e8697cd95119330fa96acc8f6a49 100644 --- a/port/stream.c +++ b/port/stream.c @@ -746,11 +746,12 @@ streamenter(Stream *s) * Decrement the reference count on a stream. If the count is * zero, free the stream. */ -void +int streamexit(Stream *s, int locked) { Queue *q; Queue *nq; + int rv; if(!locked) lock(s); @@ -765,8 +766,10 @@ streamexit(Stream *s, int locked) s->id = s->dev = s->type = 0; } s->inuse--; + rv = s->inuse; if(!locked) unlock(s); + return rv; } /* @@ -791,6 +794,8 @@ streamclose1(Stream *s) for(q = s->procq; q; q = q->next){ if(q->info->close) (*q->info->close)(q->other); + WR(q)->put = nullput; + /* * this may be 2 streams joined device end to device end */ diff --git a/power/devhs.c b/power/devhs.c index 3f322aed9c48712190bfc20ce259ba02726dac58..6f9d3f11785ffc44ab436e8c53df23fb562b9979 100644 --- a/power/devhs.c +++ b/power/devhs.c @@ -466,17 +466,28 @@ hsvmekproc(void *arg) Device *addr; unsigned int c; int miss; + int locked; hp = (Hsvme *)arg; addr = hp->addr; hp->kstarted = 1; hp->wptr = hp->buf; + locked = 0; + if(waserror()){ + if(locked) + qunlock(hp); + hp->kstarted = 0; + wakeup(&hp->r); + return; + } + for(;;){ /* * die if the device is closed */ qlock(hp); + locked = 1; if(hp->rq == 0){ qunlock(hp); hp->kstarted = 0; @@ -515,6 +526,7 @@ hsvmekproc(void *arg) } } qunlock(hp); + locked = 0; /* * sleep if input fifo empty diff --git a/power/fns.h b/power/fns.h index 41db55d7d12768b130d7f1b0c52ab710eee7e1f7..b15717e9aa24c49086be899cff5c4c3ae366e791 100644 --- a/power/fns.h +++ b/power/fns.h @@ -61,6 +61,7 @@ void flowctl(Queue*); void flushmmu(void); void forkmod(Seg*, Seg*, Proc*); void freeb(Block*); +int freebroken(void); void freepage(Orig*); void freepte(Orig*); void freesegs(int); @@ -171,7 +172,7 @@ Devgen streamgen; void streamclose(Chan*); void streamclose1(Stream*); int streamenter(Stream*); -void streamexit(Stream*, int); +int streamexit(Stream*, int); void streaminit(void); long streamread(Chan*, void*, long); long streamwrite(Chan*, void*, long, int);