From f32a6c178ced813000e98e267fde50e198fc0cdf Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 10 Dec 1990 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1990-12-10 --- gnot/chan.c | 676 ------------------- gnot/dev.c | 194 ------ gnot/devdk.c | 1684 ---------------------------------------------- gnot/devdup.c | 118 ---- gnot/devenv.c | 545 --------------- gnot/devmnt.c | 888 ------------------------ gnot/devpipe.c | 312 --------- gnot/devproc.c | 431 ------------ gnot/devroot.c | 123 ---- gnot/devsrv.c | 287 -------- gnot/fcall.c | 382 ----------- gnot/pgrp.c | 236 ------- gnot/print.c | 287 -------- gnot/stasync.c | 461 ------------- gnot/stream.c | 1344 ------------------------------------ gnot/sturp.c | 987 --------------------------- gnot/sysfile.c | 508 -------------- port/devdk.c | 27 +- port/devmnt.c | 19 - port/devnonet.c | 1233 +++++++++++++++++++++++++++++++++ port/filsys.c | 250 +++++++ port/malloc.c | 430 ++++++++++++ port/service.c | 222 ++++++ port/stnoether.c | 218 ++++++ port/sturp.c | 19 +- port/sysfile.c | 18 +- 26 files changed, 2395 insertions(+), 9504 deletions(-) delete mode 100644 gnot/chan.c delete mode 100644 gnot/dev.c delete mode 100644 gnot/devdk.c delete mode 100644 gnot/devdup.c delete mode 100644 gnot/devenv.c delete mode 100644 gnot/devmnt.c delete mode 100644 gnot/devpipe.c delete mode 100644 gnot/devproc.c delete mode 100644 gnot/devroot.c delete mode 100644 gnot/devsrv.c delete mode 100644 gnot/fcall.c delete mode 100644 gnot/pgrp.c delete mode 100644 gnot/print.c delete mode 100644 gnot/stasync.c delete mode 100644 gnot/stream.c delete mode 100644 gnot/sturp.c delete mode 100644 gnot/sysfile.c create mode 100644 port/devnonet.c create mode 100644 port/filsys.c create mode 100644 port/malloc.c create mode 100644 port/service.c create mode 100644 port/stnoether.c diff --git a/gnot/chan.c b/gnot/chan.c deleted file mode 100644 index 4830e89500d9d38c2a6315382ae91b25d3fa9be7..0000000000000000000000000000000000000000 --- a/gnot/chan.c +++ /dev/null @@ -1,676 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - - -struct{ - Lock; - Chan *free; -}chanalloc; - -int -incref(Ref *r) -{ - int x; - - lock(r); - x = ++r->ref; - unlock(r); - return x; -} - -int -decref(Ref *r) -{ - int x; - - lock(r); - x = --r->ref; - unlock(r); - return x; -} - -void -chaninit(void) -{ - int i; - Chan *c; - - chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); - - c = chanalloc.free; - for(i=0; ifid = i; - c->next = c+1; - } - c->next = 0; -} - -void -chandevreset(void) -{ - int i; - - for(i=0; inext; - c->type = 0; /* if closed before changed, this calls rooterror, a nop */ - c->flag = 0; - c->ref = 1; - unlock(&chanalloc); - c->dev = 0; - c->offset = 0; - c->mnt = 0; - c->stream = 0; - c->mchan = 0; - c->mqid = (Qid){0, 0}; - return c; - } - unlock(&chanalloc); - print("no chans\n"); - if(u == 0) - panic("newchan"); - u->p->state = Wakeme; - alarm(1000, wakeme, u->p); - sched(); - goto loop; -} - -void -close(Chan *c) -{ - if(c->flag & CFREE) - panic("close"); - if(decref(c) == 0){ - if(!waserror()){ - (*devtab[c->type].close)(c); - poperror(); - } - c->flag = CFREE; - lock(&chanalloc); - c->next = chanalloc.free; - chanalloc.free = c; - unlock(&chanalloc); - } -} - -int -eqqid(Qid a, Qid b) -{ - return a.path==b.path && a.vers==b.vers; -} - -int -eqchan(Chan *a, Chan *b, int pathonly) -{ - if(a->qid.path != b->qid.path) - return 0; - if(!pathonly && a->qid.vers!=b->qid.vers) - return 0; - if(a->type != b->type) - return 0; - if(a->dev != b->dev) - return 0; - return 1; -} - -/* - * omnt is locked. return with nmnt locked. - */ -Mount* -mountsplit(Mount *omnt) -{ - Mount *nmnt; - - nmnt = newmount(); - lock(nmnt); - nmnt->term = omnt->term; - nmnt->mountid = omnt->mountid; - nmnt->next = omnt->next; - if(nmnt->next) - incref(nmnt->next); - nmnt->c = omnt->c; - incref(nmnt->c); - omnt->ref--; - unlock(omnt); - return nmnt; -} - -int -mount(Chan *new, Chan *old, int flag) -{ - int i; - Mtab *mt, *mz; - Mount *mnt, *omnt, *nmnt, *pmnt; - Pgrp *pg; - int islast; - - if(CHDIR & (old->qid.path^new->qid.path)) - error(Emount); - if((old->qid.path&CHDIR)==0 && (flag&MORDER)!=MREPL) - error(Emount); - - mz = 0; - islast = 0; - mnt = 0; - pg = u->p->pgrp; - lock(pg); - if(waserror()){ - if(mnt){ - mnt->c = 0; /* caller will close new */ - closemount(mnt); - } - unlock(pg); - nexterror(); - } - /* - * Is old already in mount table? - */ - mt = pg->mtab; - for(i=0; inmtab; i++,mt++){ - if(mt->c==0 && mz==0) - mz = mt; - else if(eqchan(mt->c, old, 1)){ - mz = 0; - goto Found; - } - } - if(mz == 0){ - if(i == conf.nmtab) - error(Enomount); - mz = &pg->mtab[i]; - islast++; - } - mz->mnt = 0; - mt = mz; - - Found: - new->flag = CMOUNT; - if(flag & MCREATE) - new->flag |= CCREATE; - mnt = newmount(); - mnt->c = new; - - switch(flag & MORDER){ - /* - * These two always go at head of list - */ - case MBEFORE: - if(mt->mnt == 0) - error(Enotunion); - /* fall through */ - - case MREPL: - mnt->next = mt->mnt; - mt->mnt = mnt; - if((flag&MORDER) == MBEFORE) - mnt->term = 0; - else - mnt->term = 1; - break; - - /* - * This one never goes at head of list - */ - case MAFTER: - if(mt->mnt == 0) - error(Enotunion); - omnt = mt->mnt; - pmnt = 0; - while(!omnt->term){ - lock(omnt); - if(omnt->ref > 1){ - omnt = mountsplit(omnt); - if(pmnt) - pmnt->next = omnt; - else - mt->mnt = omnt; - } - unlock(omnt); - nmnt = omnt->next; - if(nmnt == 0) - panic("MAFTER term"); - pmnt = omnt; - omnt = nmnt; - } - mnt->next = omnt->next; - omnt->next = mnt; - mnt->term = 1; - omnt->term = 0; - break; - } - - incref(new); - if(mz){ - mz->c = old; - incref(old); - } - if(islast) - pg->nmtab++; - unlock(pg); - poperror(); - return mnt->mountid; -} - -Chan* -clone(Chan *c, Chan *nc) -{ - return (*devtab[c->type].clone)(c, nc); -} - -Chan* -domount(Chan *c) -{ - int i; - ulong mntid; - Mtab *mt; - Mount *mnt; - Pgrp *pg; - Chan *nc, *mc; - - pg = u->p->pgrp; - /* - * Is c in in mount table? - */ - mt = pg->mtab; - for(i=0; inmtab; i++,mt++) - if(mt->c && eqchan(mt->c, c, 1)) - goto Found; - /* - * No; c is unaffected - */ - return c; - - /* - * Yes; move c through table - */ - Found: - lock(pg); - if(!eqchan(mt->c, c, 1)){ /* table changed underfoot */ - pprint("domount: changed underfoot?\n"); - unlock(pg); - return c; - } - mnt = mt->mnt; - mntid = mnt->mountid; - mc = mnt->c; - incref(mc); - unlock(pg); - if(waserror()){ - close(mc); - nexterror(); - } - nc = clone(mc, 0); - close(mc); - poperror(); - close(c); - nc->mnt = mnt; - nc->mountid = mntid; - return nc; -} - -Chan* -walk(Chan *ac, char *name, int domnt) -{ - Mount *mnt; - int first = 1; - Chan *c = ac; - Chan *nc, *mc; - Pgrp *pg = u->p->pgrp; - - /* - * name may be empty if the file name is "/", "#c" etc. - */ - Again: - if(name[0] && (*devtab[c->type].walk)(c, name)==0){ - if(!(c->flag&CMOUNT)) - goto Notfound; - mnt = c->mnt; - if(mnt == 0) - panic("walk"); - lock(pg); - if(mnt->term){ - unlock(pg); - goto Notfound; - } - if(c->mountid != mnt->mountid){ - pprint("walk: changed underfoot? '%s'\n", name); - unlock(pg); - goto Notfound; - } - mnt = mnt->next; - mc = mnt->c; - incref(mc); - unlock(pg); - if(waserror()){ - close(mc); - nexterror(); - } - if(mnt == 0) - panic("walk 1"); - nc = clone(mc, 0); - close(mc); - poperror(); - if(!first) - close(c); - nc->mnt = mnt; - nc->mountid = mnt->mountid; - c = nc; - first = 0; - goto Again; - } - - if(name[0]) /* walk succeeded */ - c->flag &= ~CMOUNT; - - if(domnt){ - if(waserror()){ - if(!first) - close(c); - return 0; - } - c = domount(c); - poperror(); - } - - if(!first) - close(ac); - - - return c; - - Notfound: - if(!first) - close(c); - return 0; -} - -/* - * c is a mounted non-creatable directory. find a creatable one. - */ -Chan* -createdir(Chan *c) -{ - Mount *mnt; - Pgrp *pg = u->p->pgrp; - Chan *mc, *nc; - - lock(pg); - if(waserror()){ - unlock(pg); - nexterror(); - } - mnt = c->mnt; - if(c->mountid != mnt->mountid){ - pprint("createdir: changed underfoot?\n"); - error(Enocreate); - } - do{ - if(mnt->term) - error(Enocreate); - mnt = mnt->next; - }while(!(mnt->c->flag&CCREATE)); - mc = mnt->c; - incref(mc); - unlock(pg); - if(waserror()){ - close(mc); - nexterror(); - } - nc = clone(mc, 0); - poperror(); - close(c); - close(mc); - nc->mnt = mnt; - return nc; -} - -void -saveregisters(void) -{ -} - -/* - * Turn a name into a channel. - * &name[0] is known to be a valid address. It may be a kernel address. - */ -Chan* -namec(char *name, int amode, int omode, ulong perm) -{ - Chan *c, *nc; - int t; - int mntok, isdot; - char *p; - char *elem; - - if(name[0] == 0) - error(Enonexist); - - /* - * Make sure all of name is o.k. first byte is validated - * externally so if it's a kernel address we know it's o.k. - */ - if(!((ulong)name & KZERO)){ - p = name; - t = BY2PG-((ulong)p&(BY2PG-1)); - while(vmemchr(p, 0, t) == 0){ - p += t; - t = BY2PG; - } - } - - elem = u->elem; - mntok = 1; - isdot = 0; - if(name[0] == '/'){ - c = clone(u->slash, 0); - /* - * Skip leading slashes. - */ - name = skipslash(name); - }else if(name[0] == '#'){ - mntok = 0; - if(name[1]=='M') - error(Enonexist); - t = devno(name[1], 1); - if(t == -1) - error(Ebadsharp); - name += 2; - if(*name == '/'){ - name = skipslash(name); - elem[0]=0; - }else - name = nextelem(name, elem); - c = (*devtab[t].attach)(elem); - }else{ - c = clone(u->dot, 0); - name = skipslash(name); /* eat leading ./ */ - if(*name == 0) - isdot = 1; - } - - if(waserror()){ - close(c); - nexterror(); - } - - name = nextelem(name, elem); - - if(mntok && !isdot) - if(!(amode==Amount && elem[0]==0)) /* don't domount on slash */ - c = domount(c); /* see case Atodir below */ - - /* - * How to treat the last element of the name depends on the operation. - * Therefore do all but the last element by the easy algorithm. - */ - while(*name){ - if((nc=walk(c, elem, mntok)) == 0) - error(Enonexist); - c = nc; - name = nextelem(name, elem); - } - - /* - * Last element; act according to type of access. - */ - - switch(amode){ - case Aaccess: - if(isdot) - c = domount(c); - else{ - if((nc=walk(c, elem, mntok)) == 0) - error(Enonexist); - c = nc; - } - break; - - case Atodir: - /* - * Directories (e.g. for cd) are left before the mount point, - * so one may mount on / or . and see the effect. - */ - if((nc=walk(c, elem, 0)) == 0) - error(Enonexist); - c = nc; - if(!(c->qid.path & CHDIR)) - error(Enotdir); - break; - - case Aopen: - if(isdot) - c = domount(c); - else{ - if((nc=walk(c, elem, mntok)) == 0) - error(Enonexist); - c = nc; - } - Open: - saveregisters(); /* else error() in open has wrong value of c saved */ - c = (*devtab[c->type].open)(c, omode); - if(omode & OCEXEC) - c->flag |= CCEXEC; - break; - - case Amount: - /* - * When mounting on an already mounted upon directory, one wants - * the second mount to be attached to the original directory, not - * the replacement. - */ - if((nc=walk(c, elem, 0)) == 0) - error(Enonexist); - c = nc; - break; - - case Acreate: - if(isdot) - error(Eisdir); - if((nc=walk(c, elem, 1)) != 0){ - c = nc; - omode |= OTRUNC; - goto Open; - } - if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) - c = createdir(c); - (*devtab[c->type].create)(c, elem, omode, perm); - if(omode & OCEXEC) - c->flag |= CCEXEC; - break; - - default: - panic("unknown namec access %d\n", amode); - } - poperror(); - return c; -} - -/* - * name[0] is addressable. - */ -char* -skipslash(char *name) -{ - Again: - while(*name == '/') - name++; - if(*name=='.' && (name[1]==0 || name[1]=='/')){ - name++; - goto Again; - } - return name; -} - -char isfrog[]={ - /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, - /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, - /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, - /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, - [' '] 1, - ['/'] 1, - [0x7f] 1, -}; - -/* - * name[0] should not be a slash. - * Advance name to next element in path, copying current element into elem. - * Return pointer to next element, skipping slashes. - */ -char* -nextelem(char *name, char *elem) -{ - int i, user, c; - char *end, *e; - - if(*name == '/') - error(Efilename); - end = memchr(name, 0, NAMELEN); - if(end == 0){ - end = memchr(name, '/', NAMELEN); - if(end == 0) - error(Efilename); - }else{ - e = memchr(name, '/', end-name); - if(e) - end = e; - } - while(name < end){ - c = *name++; - if((c&0x80) || isfrog[c]) - error(Ebadchar); - *elem++ = c; - } - *elem = 0; - return skipslash(name); -} - -void -isdir(Chan *c) -{ - if(c->qid.path & CHDIR) - return; - error(Enotdir); -} diff --git a/gnot/dev.c b/gnot/dev.c deleted file mode 100644 index 69a2a9b059f164a8a04f67f3a36ebe6940773c0d..0000000000000000000000000000000000000000 --- a/gnot/dev.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" -#define DEVTAB -#include "devtab.h" - -#include "fcall.h" - -int -devno(int c, int user) -{ - char *s; - - s = strchr(devchar, c); - if(s==0 || c==0){ - if(user) - return -1; - panic("devno %c 0x%ux", c, c); - } - return s - devchar; -} - -void -devdir(Chan *c, Qid qid, char *n, long length, long perm, Dir *db) -{ - strcpy(db->name, n); - db->qid = qid; - db->type = devchar[c->type]; - db->dev = c->dev; - if(qid.path & CHDIR) - db->mode = CHDIR|perm; - else - db->mode = perm; - db->atime = seconds(); - db->mtime = db->atime; - db->hlength = 0; - db->length = length; - memcpy(db->uid, user, NAMELEN); - memcpy(db->gid, user, NAMELEN); -} - -int -devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) -{ - if(tab==0 || i>=ntab) - return -1; - tab += i; - devdir(c, tab->qid, tab->name, tab->length, tab->perm, dp); - return 1; -} - -Chan * -devattach(int tc, char *spec) -{ - Chan *c; - - c = newchan(); - c->qid = (Qid){CHDIR, 0}; - c->type = devno(tc, 0); - return c; -} - -Chan * -devclone(Chan *c, Chan *nc) -{ - if(c->flag & COPEN) - panic("clone of open file type %c\n", devchar[c->type]); - if(nc == 0) - nc = newchan(); - nc->type = c->type; - nc->mode = c->mode; - nc->qid = c->qid; - nc->offset = c->offset; - nc->dev = c->dev; - nc->flag = c->flag; - nc->mnt = c->mnt; - nc->mchan = c->mchan; - nc->mqid = c->mqid; - return nc; -} - -int -devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) -{ - long i; - Dir dir; - - isdir(c); - if(name[0]=='.' && name[1]==0) - return 1; - for(i=0;; i++) - switch((*gen)(c, tab, ntab, i, &dir)){ - case -1: - strncpy(u->error, errstrtab[Enonexist], NAMELEN); - return 0; - case 0: - continue; - case 1: - if(strcmp(name, dir.name) == 0){ - c->qid = dir.qid; - return 1; - } - continue; - } -} - -void -devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen) -{ - int i; - Dir dir; - - for(i=0;; i++) - switch((*gen)(c, tab, ntab, i, &dir)){ - case -1: - /* - * devices with interesting directories usually don't get - * here, which is good because we've lost the name by now. - */ - if(c->qid.path & CHDIR){ - devdir(c, c->qid, ".", 0L, CHDIR|0700, &dir); - convD2M(&dir, db); - return; - } - panic("devstat"); - case 0: - break; - case 1: - if(eqqid(c->qid, dir.qid)){ - convD2M(&dir, db); - return; - } - break; - } -} - -long -devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) -{ - long k, m; - Dir dir; - - k = c->offset/DIRLEN; - for(m=0; moffset += DIRLEN; - break; - - case 1: - convD2M(&dir, d); - m += DIRLEN; - d += DIRLEN; - break; - } - return m; -} - -Chan * -devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) -{ - int i; - Dir dir; - static int access[] = { 0400, 0200, 0600, 0100 }; - - for(i=0;; i++) - switch((*gen)(c, tab, ntab, i, &dir)){ - case -1: - /* Deal with union directories? */ - goto Return; - case 0: - break; - case 1: - if(eqqid(c->qid, dir.qid)){ - if((access[omode&3] & dir.mode) == access[omode&3]) - goto Return; - error(Eperm); - } - break; - } - Return: - c->offset = 0; - if((c->qid.path&CHDIR) && omode!=OREAD) - error(Eperm); - c->mode = openmode(omode); - c->flag |= COPEN; - return c; -} diff --git a/gnot/devdk.c b/gnot/devdk.c deleted file mode 100644 index fccc15f45e915ccaf28917bdf4c5ec05e17d141b..0000000000000000000000000000000000000000 --- a/gnot/devdk.c +++ /dev/null @@ -1,1684 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "errno.h" - -#define DPRINT if(0) print - -#define NOW (MACHP(0)->ticks) - -enum { - /* - * configuration parameters - */ - Ndk = 2, /* max dks */ - - /* - * relative or immutable - */ - Nline = 256, /* max lines per dk */ - Ndir = Nline + 1, /* entries in the dk directory */ - Nsubdir = 5, /* entries in the sub directory */ -}; - -typedef struct Dkmsg Dkmsg; -typedef struct Line Line; -typedef struct Dk Dk; - -/* - * types of possible dkcalls - */ -enum { - Dial, - Announce, - Redial -}; - -/* - * format of messages to/from the datakit controller on the common - * signalling line - */ -struct Dkmsg { - uchar type; - uchar srv; - uchar param0l; - uchar param0h; - uchar param1l; - uchar param1h; - uchar param2l; - uchar param2h; - uchar param3l; - uchar param3h; - uchar param4l; - uchar param4h; -}; - -/* - * message codes (T_xxx == dialin.type, D_xxx == dialin.srv) - */ -#define T_SRV 1 /* service request */ -#define D_SERV 1 /* (host to dkmux) announce a service */ -#define D_DIAL 2 /* (host to dkmux) connect to a service */ -#define D_XINIT 7 /* (dkmux to host) line has been spliced */ -#define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */ -#define D_OK 1 /* not used */ -#define D_OPEN 2 /* (dkmux to host) connection established */ -#define D_FAIL 3 /* (dkmux to host) connection failed */ -#define T_CHG 3 /* change the status of a connection */ -#define D_CLOSE 1 /* close the connection */ -#define D_ISCLOSED 2 /* (dkmux to host) confirm a close */ -#define D_CLOSEALL 3 /* (dkmux to host) close all connections */ -#define D_REDIAL 6 /* (host to dkmux) redial a call */ -#define T_ALIVE 4 /* (host to dkmux) keep alive message */ -#define D_CONTINUE 0 /* host has not died since last msg */ -#define D_RESTART 1 /* host has restarted */ -#define D_MAXCHAN 2 /* request maximum line number */ -#define T_RESTART 8 /* (dkmux to host) datakit restarted */ - -/* - * macros for cracking/forming the window negotiation parameter - */ -#define MIN(x,y) (x < y ? x : y) -#define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000) -#define W_VALID(x) ((x) & 0100000) -#define W_ORIG(x) (((x)>>8) & 017) -#define W_DEST(x) (((x)>>4) & 017) -#define W_TRAF(x) ((x) & 017) -#define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x))) -#define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x))) -#define W_VALUE(x) (1<<((x)+4)) -#define WS_2K 7 - -/* - * one per datakit line - */ -struct Line { - QLock; - Rendez r; /* wait here for dial */ - int state; /* dial state */ - int err; /* dialing error (if non zero) */ - int window; /* negotiated window */ - int timestamp; /* timestamp of last call received on this line */ - int calltolive; /* multiple of 15 seconds for dialing state to last */ - Queue *rq; - char addr[64]; - char raddr[64]; - char ruser[32]; - char other[64]; - Dk *dp; /* interface contianing this line */ -}; - -/* - * a dkmux dk. one exists for every stream that a - * dkmux line discipline is pushed onto. - */ -struct Dk { - 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; - Line line[Nline]; - int restart; - int urpwindow; - Rendez timer; -}; -static Dk dk[Ndk]; -static Lock dklock; - -/* - * conversation states (for Line.state) - */ -typedef enum { - Lclosed=0, - Lopened, /* opened but no call out */ - Lconnected, /* opened and a call set up on htis line */ - Lrclose, /* remote end has closed down */ - Llclose, /* local end has closed down */ - Ldialing, /* dialing a new call */ - Llistening, /* this line listening for calls */ - Lackwait, /* incoming call waiting for ack/nak */ - Laccepting, /* waiting for user to accept or reject the call */ -} Lstate; - -/* - * datakit error to errno - */ -enum { - DKok, - DKbusy, - DKnetotl, - DKdestotl, - DKbadnet, - DKnetbusy, - DKinuse, - DKreject, -}; -int dkerr[]={ - [DKok]Egreg, - [DKbusy]Einuse, /* destination busy */ - [DKnetotl]Enetotl, /* network not answering */ - [DKdestotl]Edestotl, /* destination not answering */ - [DKbadnet]Ebadnet, /* unassigned destination */ - [DKnetbusy]Enetbusy, /* network overload */ - [DKinuse]Einuse, /* server already exists */ - [DKreject]Erejected /* call rejected by destination */ -}; -#define DKERRS sizeof(dkerr)/sizeof(int) - -/* - * imported - */ -extern Qinfo urpinfo; - -/* - * predeclared - */ -Chan* dkattach(char*); -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(Chan*, Dk*, Dkmsg*, int); -static void dkreplymesg(Dk*, Dkmsg*, int); -Chan* dkopen(Chan*, int); -static void dkhangup(Line*); - -/* - * 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 = -{ - dkmuxiput, - dkmuxoput, - dkmuxopen, - dkmuxclose, - "dkmux" -}; - -/* - * Look for a dk struct with a name. If none exists, create one. - */ -static Dk * -dkalloc(char *name) -{ - Dk *dp; - Dk *freep; - - lock(&dklock); - freep = 0; - for(dp = dk; dp < &dk[Ndk]; dp++){ - if(strcmp(name, dp->name) == 0){ - unlock(&dklock); - return dp; - } - if(dp->name[0] == 0) - freep = dp; - } - if(freep == 0){ - unlock(&dklock); - error(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; -} - -/* - * close down a dkmux - */ -static void -dkmuxclose(Queue *q) -{ - Dk *dp; - int i; - - 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); -} - -/* - * handle configuration - */ -static void -dkmuxoput(Queue *q, Block *bp) -{ - if(bp->type != M_DATA){ - if(streamparse("config", bp)) - dkmuxconfig(q, bp); - else - PUTNEXT(q, bp); - return; - } - PUTNEXT(q, bp); -} - -/* - * gather a message and send it up the appropriate stream - * - * The first two bytes of each message contains the channel - * number, low order byte first. - * - * Simplifying assumption: one put == one message && the channel number - * is in the first block. If this isn't true, demultiplexing will not - * work. - */ -static void -dkmuxiput(Queue *q, Block *bp) -{ - Dk *dp; - 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); - return; - } - - line = bp->rptr[0] | (bp->rptr[1]<<8); - bp->rptr += 2; - if(line<0 || line>=dp->lines){ - DPRINT("dkmuxiput bad line %d\n", line); - freeb(bp); - return; - } - - lp = &dp->line[line]; - if(canqlock(lp)){ - if(lp->rq) - PUTNEXT(lp->rq, bp); - else{ - DPRINT("dkmuxiput unopened line %d\n", line); - freeb(bp); - } - qunlock(lp); - } else { - DPRINT("dkmuxiput unopened line %d\n", line); - freeb(bp); - } -} - -/* - * the datakit line stream module definition - */ -static void dkstopen(Queue *, Stream *); -static void dkstclose(Queue *); -static void dkoput(Queue *, Block *); -static void dkiput(Queue *, Block *); -Qinfo dkinfo = -{ - dkiput, - dkoput, - dkstopen, - dkstclose, - "dk" -}; - -/* - * open and save a pointer to the conversation - */ -static void -dkstopen(Queue *q, Stream *s) -{ - Dk *dp; - 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(Ehungup); - } - unlock(dp); - lp->rq = q; - if(lp->state==Lclosed) - lp->state = Lopened; -} - -/* - * close down a datakit conversation - */ -static void -dkstclose(Queue *q) -{ - Dk *dp; - Line *lp; - Chan *c; - - 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); - - /* - * these states don't need the datakit - */ - 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); - goto out; - } - c = dkopenline(dp, dp->ncsc); - - /* - * shake hands with dk - */ - switch(lp->state){ - case Lrclose: - dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); - lp->state = Lclosed; - break; - - case Lackwait: - dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); - lp->state = Llclose; - break; - - case Llistening: - dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); - lp->state = Llclose; - break; - - case Lconnected: - dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); - lp->state = Llclose; - break; - } - poperror(); - close(c); - -out: - qlock(lp); - lp->rq = 0; - qunlock(lp); -} - -/* - * this is only called by hangup - */ -static void -dkiput(Queue *q, Block *bp) -{ - PUTNEXT(q, 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. - */ -static void -dkoput(Queue *q, Block *bp) -{ - Line *lp; - Dk *dp; - int line; - - if(bp->type != M_DATA){ - freeb(bp); - error(Ebadarg); - } - - lp = (Line *)q->ptr; - dp = lp->dp; - line = lp - dp->line; - - bp = padb(bp, 2); - bp->rptr[0] = line; - bp->rptr[1] = line>>8; - - FLOWCTL(dp->wq); - PUTNEXT(dp->wq, bp); -} - -/* - * configure a datakit multiplexor. this takes 5 arguments separated - * by spaces: - * the line number of the common signalling channel (must be > 0) - * the number of lines in the device (optional) - * the word `restart' or `norestart' (optional/default==restart) - * the name of the dk (default==dk) - * the urp window size (default==WS_2K) - * - * we can configure only once - */ -static void -dkmuxconfig(Queue *q, Block *bp) -{ - Dk *dp; - char *fields[5]; - int n; - char buf[64]; - char name[NAMELEN]; - int lines; - int ncsc; - int restart; - int window; - - if(WR(q)->ptr){ - freeb(bp); - error(Egreg); - } - - /* - * defaults - */ - ncsc = 1; - restart = 1; - lines = 16; - window = WS_2K; - strcpy(name, "dk"); - - /* - * parse - */ - n = getfields((char *)bp->rptr, fields, 5, ' '); - switch(n){ - case 5: - window = strtoul(fields[4], 0, 0); - case 4: - strncpy(name, fields[3], sizeof(name)); - case 3: - if(strcmp(fields[2], "restart")!=0) - restart = 0; - case 2: - lines = strtoul(fields[1], 0, 0); - case 1: - ncsc = strtoul(fields[0], 0, 0); - break; - default: - freeb(bp); - error(Ebadarg); - } - freeb(bp); - if(ncsc <= 0 || lines <= ncsc) - error(Ebadarg); - - /* - * set up - */ - dp = dkalloc(name); - lock(dp); - if(dp->opened){ - unlock(dp); - error(Ebadarg); - } - 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("dktimer: restart %s\n", dp->name); - dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0); - } - - /* - * start a process to listen to csc messages - */ - sprint(buf, "csc.%s.%d", dp->name, dp->ncsc); - kproc(buf, dkcsckproc, dp); - - /* - * start a keepalive process - */ - sprint(buf, "timer.%s.%d", dp->name, dp->ncsc); - kproc(buf, dktimer, dp); -} - -/* - * qid's - */ -enum { - /* - * per line - */ - Daddrqid, - Dlistenqid, - Draddrqid, - Duserqid, - Dotherqid, - Dlineqid, - - /* - * per device - */ - Dcloneqid, -}; - -/* - * the dk directory - */ -Dirtab dkdir[Ndir]; - -/* - * the per stream directory structure - */ -Dirtab dksubdir[]={ - "addr", {Daddrqid}, 0, 0600, - "listen", {Dlistenqid}, 0, 0600, - "other", {Dotherqid}, 0, 0600, - "raddr", {Draddrqid}, 0, 0600, - "ruser", {Duserqid}, 0, 0600, -}; - -/* - * dk file system. most of the calls use dev.c to access the dk - * directory and stream.c to access the dk devices. - */ -void -dkreset(void) -{ - newqinfo(&dkmuxinfo); -} - -/* - * create the dk directory. the files are `clone' and stream - * directories '1' to '32' (or whatever Nline is in decimal) - */ -void -dkinit(void) -{ - int i; - - /* - * create the directory. - */ - /* - * the circuits - */ - for(i = 1; i < Nline; i++) { - sprint(dkdir[i].name, "%d", i); - dkdir[i].qid.path = CHDIR|STREAMQID(i, Dlineqid); - dkdir[i].qid.vers = 0; - dkdir[i].length = 0; - dkdir[i].perm = 0600; - } - - /* - * the clone device - */ - strcpy(dkdir[0].name, "clone"); - dkdir[0].qid.path = Dcloneqid; - dkdir[0].qid.vers = 0; - dkdir[0].length = 0; - dkdir[0].perm = 0600; -} - -Chan* -dkattach(char *spec) -{ - Chan *c; - Dk *dp; - - /* - * find a multiplexor with the same name (default dk) - */ - if(*spec == 0) - spec = "dk"; - dp = dkalloc(spec); - - /* - * return the new channel - */ - c = devattach('k', spec); - c->dev = dp - dk; - return c; -} - -Chan* -dkclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -dkwalk(Chan *c, char *name) -{ - if(c->qid.path == CHDIR) - return devwalk(c, name, dkdir, dk[c->dev].lines, devgen); - else - return devwalk(c, name, dksubdir, Nsubdir, streamgen); -} - -void -dkstat(Chan *c, char *dp) -{ - if(c->qid.path == CHDIR) - devstat(c, dp, dkdir, dk[c->dev].lines, devgen); - else if(c->qid.path == Dcloneqid) - devstat(c, dp, dkdir, 1, devgen); - else - devstat(c, dp, dksubdir, Nsubdir, streamgen); -} - -/* - * opening a dk device allocates a Line. Opening the `clone' - * device is a ``macro'' for finding a free Line and opening - * it's ctl file. - * - * opening the `listen' sub device is a macro for listening for - * a new call. Lile `clone' the ctl file of the new channel is - * returned. - */ -Chan* -dkopen(Chan *c, int omode) -{ - extern Qinfo dkinfo; - Stream *s; - Line *lp, *end; - Dk *dp; - int line; - - if(c->qid.path & CHDIR){ - /* - * directories are read only - */ - if(omode != OREAD) - error(Ebadarg); - } else switch(STREAMTYPE(c->qid.path)){ - case Dcloneqid: - dp = &dk[c->dev]; - /* - * get an unused device and open its control file - */ - end = &dp->line[dp->lines]; - for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){ - if(lp->state == Lclosed && canqlock(lp)){ - if(lp->state != Lclosed){ - qunlock(lp); - continue; - } - c->qid.path = STREAMQID(lp-dp->line, Sctlqid); - break; - } - } - if(lp == end) - error(Enodev); - lp->state = Lopened; - qunlock(lp); - streamopen(c, &dkinfo); - pushq(c->stream, &urpinfo); - break; - case Dlistenqid: - /* - * listen for a call and open the control file for the - * channel on which the call arrived. - */ - line = dklisten(c); - c->qid.path = STREAMQID(line, Sctlqid); - streamopen(c, &dkinfo); - pushq(c->stream, &urpinfo); - dkwindow(c); - break; - case Daddrqid: - case Draddrqid: - case Duserqid: - case Dotherqid: - /* - * read only files - */ - if(omode != OREAD) - error(Ebadarg); - break; - default: - /* - * open whatever c points to, make sure it has an urp - */ - streamopen(c, &dkinfo); - if(strcmp(c->stream->procq->next->info->name, "urp")!=0) - pushq(c->stream, &urpinfo); - break; - } - - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -dkcreate(Chan *c, char *name, int omode, ulong perm) -{ - error(Eperm); -} - -void -dkclose(Chan *c) -{ - if(c->stream) - streamclose(c); -} - -long -dkread(Chan *c, void *a, long n) -{ - Line *lp; - - if(c->stream) - return streamread(c, a, n); - - if(c->qid.path & CHDIR){ - if(c->qid.path == CHDIR) - return devdirread(c, a, n, dkdir, dk[c->dev].lines, devgen); - else - return devdirread(c, a, n, dksubdir, Nsubdir, streamgen); - } - - lp = &dk[c->dev].line[STREAMID(c->qid.path)]; - switch(STREAMTYPE(c->qid.path)){ - case Daddrqid: - return stringread(c, a, n, lp->addr); - case Draddrqid: - return stringread(c, a, n, lp->raddr); - case Duserqid: - return stringread(c, a, n, lp->ruser); - } - error(Eperm); -} - -long -dkwrite(Chan *c, void *a, long n) -{ - int t; - char buf[256]; - char *field[5]; - int m; - - t = STREAMTYPE(c->qid.path); - - /* - * get data dispatched as quickly as possible - */ - if(t == Sdataqid) - return streamwrite(c, a, n, 0); - - /* - * easier to do here than in dkoput - */ - if(t == Sctlqid){ - strncpy(buf, a, sizeof buf); - m = getfields(buf, field, 5, ' '); - if(strcmp(field[0], "connect")==0){ - if(m < 2) - error(Ebadarg); - dkcall(Dial, c, field[1], 0, 0); - } else if(strcmp(field[0], "announce")==0){ - if(m < 2) - error(Ebadarg); - dkcall(Announce, c, field[1], 0, 0); - } else if(strcmp(field[0], "redial")==0){ - if(m < 4) - error(Ebadarg); - dkcall(Redial, c, field[1], field[2], field[3]); - } else if(strcmp(field[0], "accept")==0){ - if(m < 2) - error(Ebadarg); - dkanswer(c, strtoul(field[1], 0, 0), 0); - } else if(strcmp(field[0], "reject")==0){ - if(m < 3) - error(Ebadarg); - dkanswer(c, strtoul(field[1], 0, 0), strtoul(field[2], 0, 0)); - } else - return streamwrite(c, a, n, 0); - return n; - } - - error(Eperm); -} - -void -dkremove(Chan *c) -{ - error(Eperm); -} - -void -dkwstat(Chan *c, char *dp) -{ - error(Eperm); -} - -/* - * 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.path = STREAMQID(line, Sdataqid); - dkopen(c, ORDWR); - poperror(); - - return c; -} - -/* - * send a message to the datakit on the common signaling line - */ -static int -dkmesg(Chan *c, int type, int srv, int p0, int p1) -{ - Dkmsg d; - - if(waserror()){ - print("dkmesg: error\n"); - return -1; - } - d.type = type; - d.srv = srv; - d.param0l = p0; - d.param0h = p0>>8; - d.param1l = p1; - d.param1h = p1>>8; - d.param2l = 0; - d.param2h = 0; - d.param3l = 0; - d.param3h = 0; - d.param4l = 0; - d.param4h = 0; - streamwrite(c, (char *)&d, sizeof(Dkmsg), 1); - poperror(); - return 0; -} - -/* - * call out on a datakit - */ -static int -calldone(void *a) -{ - Line *lp; - - lp = (Line *)a; - return lp->state != Ldialing; -} -static void -dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) -{ - char dialstr[66]; - int line; - char dialtone; - int t_val, d_val; - Dk *dp; - Line *lp; - Chan *dc; - Chan *csc; - char *bang, *dot; - - line = STREAMID(c->qid.path); - dp = &dk[c->dev]; - lp = &dp->line[line]; - - /* - * only dial on virgin lines - */ - if(lp->state != Lopened) - error(Ebadarg); - - DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr); - - /* - * build dial string - * - guard against new lines - * - change ! into . to delimit service - */ - if(strchr(addr, '\n')) - error(Ebadarg); - if(strlen(addr)+strlen(u->p->pgrp->user)+2 >= sizeof(dialstr)) - error(Ebadarg); - strcpy(dialstr, addr); - bang = strchr(dialstr, '!'); - if(bang){ - dot = strchr(dialstr, '.'); - if(dot==0 || dot > bang) - *bang = '.'; - } - switch(type){ - case Dial: - t_val = T_SRV; - d_val = D_DIAL; - strcat(dialstr, "\n"); - strcat(dialstr, u->p->pgrp->user); - strcat(dialstr, "\n"); - break; - case Announce: - t_val = T_SRV; - d_val = D_SERV; - break; - case Redial: - t_val = T_CHG; - d_val = D_REDIAL; - strcat(dialstr, "\n"); - strcat(dialstr, nuser); - strcat(dialstr, "\n"); - strcat(dialstr, machine); - strcat(dialstr, "\n"); - break; - } - - /* - * close temporary channels on error - */ - dc = 0; - csc = 0; - if(waserror()){ - if(csc) - close(csc); - if(dc) - close(dc); - nexterror(); - } - - /* - * open the data file - */ - dc = dkopenline(dp, line); - lp->calltolive = 4; - lp->state = Ldialing; - - /* - * tell the controller we want to make a call - */ - DPRINT("dialout\n"); - 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 - * the dialstr to the previous other end and not the controller) - */ - if(type==Redial){ - if(streamread(dc, &dialtone, 1L) != 1L){ - lp->state = Lconnected; - error(Ebadarg); - } - } - - /* - * make the call - */ - DPRINT("dialstr %s\n", dialstr); - streamwrite(dc, dialstr, (long)strlen(dialstr), 1); - close(dc); - poperror(); - - /* - * redial's never get a reply, assume it worked - */ - if(type == Redial) { - lp->state = Lconnected; - return; - } - - /* - * wait for a reply - */ - DPRINT("reply wait\n"); - sleep(&lp->r, calldone, lp); - - /* - * if there was an error, translate it to a plan 9 - * errno and report it to the user. - */ - DPRINT("got reply %d\n", lp->state); - if(lp->state != Lconnected) { - if(lp->err >= DKERRS) - error(dkerr[0]); - else - error(dkerr[lp->err]); - } - - /* - * change state if serving - */ - if(type == D_SERV){ - lp->state = Llistening; - } - DPRINT("connected!\n"); - - /* - * decode the window size - */ - if (W_VALID(lp->window)){ - /* - * a 1127 window negotiation - */ - lp->window = W_VALUE(W_DEST(lp->window)); - } else if(lp->window>2 && lp->window<31){ - /* - * a generic window negotiation - */ - lp->window = 1<window; - } else - lp->window = 0; - - /* - * tag the connection - */ - strncpy(lp->addr, addr, sizeof(lp->addr)-1); - strncpy(lp->raddr, addr, sizeof(lp->raddr)-1); - - /* - * reset the protocol - */ - dkwindow(c); -} - -/* - * listen for a call, reflavor the - */ -static int -dklisten(Chan *c) -{ - char dialstr[512]; - char *line[12]; - char *field[8]; - Line *lp; - Dk *dp; - int n, lineno, ts, window; - Chan *dc; - - dp = &dk[c->dev]; - - /* - * open the data file - */ - dc = dkopenline(dp, STREAMID(c->qid.path)); - if(waserror()){ - close(dc); - nexterror(); - } - - /* - * wait for a call in - */ - for(;;){ - /* - * read the dialstring and null terminate it - */ - n = streamread(dc, dialstr, sizeof(dialstr)-1); - DPRINT("returns %d\n", n); - if(n <= 0) - error(Eio); - dialstr[n] = 0; - DPRINT("dialstr = %s\n", dialstr); - - /* - * break the dial string into lines - */ - n = getfields(dialstr, line, 12, '\n'); - if (n < 2) { - DPRINT("bad dialstr from dk (1 line)\n"); - error(Eio); - } - - /* - * line 0 is `line.tstamp.traffic[.urpparms.window]' - */ - window = 0; - switch(getfields(line[0], field, 5, '.')){ - case 5: - /* - * generic way of passing window - */ - window = strtoul(field[4], 0, 0); - if(window > 0 && window <31) - window = 1<= dp->lines){ - print("dklisten: illegal line %d\n", lineno); - continue; - } - lp = &dp->line[lineno]; - ts = strtoul(field[1], 0, 0); - - /* - * this could be a duplicate request - */ - if(ts == lp->timestamp){ - print("dklisten: repeat timestamp %d\n", lineno); - if(lp->state != Lconnected) - dkanswer(c, lineno, DKbusy); - continue; - } - - /* - * take care of glare (datakit picked an inuse channel - * for the call to come in on). - */ - if(!canqlock(lp)){ - DPRINT("DKbusy1\n"); - dkanswer(c, lineno, DKbusy); - continue; - } else { - if(lp->state != Lclosed){ - qunlock(lp); - DPRINT("DKbusy2 %ux\n", lp->state); - dkanswer(c, lineno, DKbusy); - continue; - } - } - lp->window = window; - - /* - * Line 1 is `my-dk-name.service[.more-things]'. - * Special characters are escaped by '\'s. - */ - strncpy(lp->addr, line[1], sizeof(lp->addr)-1); - - /* - * the rest is variable length - */ - switch(n) { - case 2: - /* no more lines */ - lp->ruser[0] = 0; - lp->raddr[0] = 0; - break; - case 3: - /* line 2 is `source.user.param1.param2' */ - getfields(line[2], field, 3, '.'); - strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1); - strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1); - break; - case 4: - /* line 2 is `user.param1.param2' */ - getfields(line[2], field, 2, '.'); - strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1); - - /* line 3 is `source.node.mod.line' */ - strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1); - break; - default: - print("bad message from dk(>4 line)\n"); - qunlock(lp); - error(Ebadarg); - } - - sprint(lp->other, "w(%d)", W_TRAF(lp->window)); - DPRINT("src(%s)user(%s)dest(%s)other(%s)\n", lp->raddr, lp->ruser, - lp->addr, lp->other); - - lp->timestamp = ts; - lp->state = Lconnected; - qunlock(lp); - close(dc); - poperror(); - DPRINT("dklisten returns %d\n", lineno); - return lineno; - } - panic("dklisten terminates strangely\n"); -} - -/* - * answer a call - */ -static void -dkanswer(Chan *c, int line, int code) -{ - char reply[64]; - Dk *dp; - Chan *dc; - Line *lp; - - dp = &dk[c->dev]; - lp = &dp->line[line]; - - /* - * open the data file (c is a control file) - */ - dc = dkattach(dp->name); - if(waserror()){ - close(dc); - nexterror(); - } - dc->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid); - dkopen(dc, ORDWR); - - /* - * send the reply - */ - sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code); - DPRINT("dkanswer %s\n", reply); - streamwrite(dc, reply, strlen(reply), 1); - close(dc); - poperror(); -} - -/* - * set the window size and reset the protocol - */ -static void -dkwindow(Chan *c) -{ - char buf[64]; - long wins; - Line *lp; - - lp = &dk[c->dev].line[STREAMID(c->qid.path)]; - if(lp->window == 0) - lp->window = 64; - sprint(buf, "init %d %d", lp->window, Streamhi); - streamwrite(c, buf, strlen(buf), 1); -} - -/* - * hangup a datakit connection - */ -static void -dkhangup(Line *lp) -{ - Block *bp; - - qlock(lp); - if(lp->rq){ - bp = allocb(0); - bp->type = M_HANGUP; - PUTNEXT(lp->rq, bp); - } - qunlock(lp); -} - -/* - * A process which listens to all input on a csc line - */ -static void -dkcsckproc(void *a) -{ - long n; - Dk *dp; - Dkmsg d; - int line; - - dp = a; - - if(waserror()){ - close(dp->csc); - return; - } - - /* - * loop forever listening - */ - for(;;){ - n = streamread(dp->csc, (char *)&d, (long)sizeof(d)); - if(n != sizeof(d)){ - if(n == 0) - error(Ehungup); - print("strange csc message %d\n", n); - continue; - } - line = (d.param0h<<8) + d.param0l; -/* print("t(%d)s(%d)l(%d)\n", d.type, d.srv, line); /**/ - switch (d.type) { - - case T_CHG: /* controller wants to close a line */ - dkchgmesg(dp->csc, dp, &d, line); - break; - - case T_REPLY: /* reply to a dial request */ - dkreplymesg(dp, &d, line); - break; - - case T_SRV: /* ignore it, it's useless */ - print("dksrvmesg(%d)\n", line); - break; - - case T_RESTART: /* datakit reboot */ - if(line >=0 && linelines) - dp->lines=line+1; - break; - - default: - DPRINT("unrecognized csc message %o(%o)\n", d.type, line); - break; - } - } -} - -/* - * datakit requests or confirms closing a line - */ -static void -dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) -{ - Line *lp; - - switch (dialp->srv) { - - case D_CLOSE: /* remote shutdown */ - if (line <= 0 || line >= dp->lines) { - /* tell controller this line is not in use */ - dkmesg(c, T_CHG, D_CLOSE, line, 0); - return; - } - lp = &dp->line[line]; - switch (lp->state) { - - case Ldialing: - /* simulate a failed connection */ - dkreplymesg(dp, (Dkmsg *)0, line); - lp->state = Lrclose; - break; - - case Lrclose: - case Lconnected: - case Llistening: - case Lackwait: - dkhangup(lp); - lp->state = Lrclose; - break; - - case Lopened: - dkmesg(c, T_CHG, D_CLOSE, line, 0); - break; - - case Llclose: - case Lclosed: - dkhangup(lp); - dkmesg(c, T_CHG, D_CLOSE, line, 0); - lp->state = Lclosed; - break; - } - break; - - case D_ISCLOSED: /* acknowledging a local shutdown */ - if (line <= 0 || line >= dp->lines) { - /* tell controller this line is not in use */ - dkmesg(c, T_CHG, D_CLOSE, line, 0); - return; - } - lp = &dp->line[line]; - switch (lp->state) { - case Llclose: - case Lclosed: - lp->state = Lclosed; - break; - - case Lrclose: - case Lconnected: - case Llistening: - case Lackwait: - break; - } - 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) { - - case Ldialing: - /* simulate a failed connection */ - dkreplymesg(dp, (Dkmsg *)0, line); - lp->state = Lrclose; - break; - - case Lrclose: - case Lconnected: - case Llistening: - case Lackwait: - lp->state = Lrclose; - dkhangup(lp); - break; - - case Lopened: - break; - - case Llclose: - case Lclosed: - lp->state = Lclosed; - break; - } - } - break; - - default: - print("unrecognized T_CHG\n"); - } -} - -/* - * datakit replies to a dialout. capture reply code and traffic parameters - */ -static void -dkreplymesg(Dk *dp, Dkmsg *dialp, int line) -{ - Proc *p; - Line *lp; - - DPRINT("dkreplymesg(%d)\n", line); - - if(line < 0 || line >= dp->lines) - return; - - lp=&dp->line[line]; - if(lp->state != Ldialing) - return; - - if(dialp){ - /* - * a reply from the dk - */ - lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose; - lp->err = (dialp->param1h<<8) + dialp->param1l; - lp->window = lp->err; - DPRINT("dkreplymesg: %d\n", lp->state); - } else { - /* - * a local abort - */ - lp->state = Lrclose; - lp->err = 0; - } - - if(lp->state==Lrclose){ - dkhangup(lp); - } - wakeup(&lp->r); -} - -/* - * send a I'm alive message every 7.5 seconds and remind the dk of - * any closed channels it hasn't acknowledged. - */ -static void -dktimer(void *a) -{ - int dki, i; - Dk *dp; - Line *lp; - Chan *c; - - 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(Ehungup); - - /* - * send keep alive - */ - DPRINT("keep alive\n"); - 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(c, T_CHG, D_CLOSE, i, 0); - break; - - case Ldialing: - if(lp->calltolive==0 || --lp->calltolive!=0) - break; - dkreplymesg(dp, (Dkmsg *)0, i); - break; - } - } - tsleep(&dp->timer, return0, 0, 7500); - } -} diff --git a/gnot/devdup.c b/gnot/devdup.c deleted file mode 100644 index f61cff504bead881ec0c02e57c35c9ac9f3c27a0..0000000000000000000000000000000000000000 --- a/gnot/devdup.c +++ /dev/null @@ -1,118 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#include "devtab.h" - - -int -dupgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) -{ - char buf[8]; - Chan *f; - static int perm[] = { 0400, 0200, 0600, 0 }; - - if(s >= NFD) - return -1; - if((f=u->fd[s]) == 0) - return 0; - sprint(buf, "%ld", s); - devdir(c, (Qid){s, 0}, buf, 0, perm[f->mode&3], dp); - return 1; -} - -void -dupinit(void) -{ -} - -void -dupreset(void) -{ -} - -Chan * -dupattach(char *spec) -{ - return devattach('d', spec); -} - -Chan * -dupclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -dupwalk(Chan *c, char *name) -{ - return devwalk(c, name, (Dirtab *)0, 0, dupgen); -} - -void -dupstat(Chan *c, char *db) -{ - devstat(c, db, (Dirtab *)0, 0L, dupgen); -} - -Chan * -dupopen(Chan *c, int omode) -{ - Chan *f; - - if(c->qid.path == CHDIR){ - if(omode != 0) - error(Eisdir); - c->mode = 0; - c->flag |= COPEN; - c->offset = 0; - return c; - } - fdtochan(c->qid.path, openmode(omode)); /* error check only */ - f = u->fd[c->qid.path]; - close(c); - incref(f); - return f; -} - -void -dupcreate(Chan *c, char *name, int omode, ulong perm) -{ - error(Eperm); -} - -void -dupremove(Chan *c) -{ - error(Eperm); -} - -void -dupwstat(Chan *c, char *dp) -{ - error(Egreg); -} - -void -dupclose(Chan *c) -{ -} - -long -dupread(Chan *c, void *va, long n) -{ - char *a = va; - - if(c->qid.path != CHDIR) - panic("dupread"); - return devdirread(c, a, n, (Dirtab *)0, 0L, dupgen); -} - -long -dupwrite(Chan *c, void *va, long n) -{ - panic("dupwrite"); -} diff --git a/gnot/devenv.c b/gnot/devenv.c deleted file mode 100644 index bbddae4c469c0befd15573726f63b4d3dbb3933b..0000000000000000000000000000000000000000 --- a/gnot/devenv.c +++ /dev/null @@ -1,545 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#include "devtab.h" - -/* - * An environment value is kept in some number of contiguous - * Envvals, with the Env's val pointing at the first. - * Envvals are allocated from the end of a fixed arena, which - * is compacted when the arena end is reached. - * A `piece' (number of contiguous Envvals) is free to be - * reclaimed if its e pointer is 0. - * - * Locking: an env's val can change by compaction, so lock - * an env before using its value. A pgrp env[] slot can go - * to 0 and the corresponding env freed (by envremove()), so - * lock the pgrp around the use of a value retrieved from a slot. - * Lock in order: pgrp, envalloc, env (but ok to skip envalloc - * lock if there is no possibility of blocking). - */ - -struct Envval -{ - ulong n; /* number of Envval's (including this) in this piece */ - ulong len; /* how much of dat[] is valid */ - Env *e; /* the Env whose val points here */ - char dat[4]; /* possibly extends into further envvals after this */ -}; - -/* number of contiguous Envvals needed to hold n characters */ -#define EVNEEDED(n) ((n)<4? 1 : 1+((n)+(sizeof(Envval))-1-4)/(sizeof(Envval))) - -struct -{ - Lock; - Envval *arena; - Envval *vfree; - Envval *end; - Env *efree; - Env *earena; -}envalloc; - -void compactenv(Env *, ulong); - -void -envreset(void) -{ - int i, n; - - n = EVNEEDED(conf.nenvchar); - envalloc.arena = ialloc(n*sizeof(Envval), 0); - envalloc.vfree = envalloc.arena; - envalloc.end = envalloc.arena+n; - - envalloc.earena = ialloc(conf.nenv*sizeof(Env), 0); - envalloc.efree = envalloc.earena; - for(i=0; ival points at a value big enough to hold nchars chars. - * The caller should fix e->val->len. - * envalloc and e should be locked - */ -void -growenval(Env *e, ulong nchars) -{ - Envval *p; - ulong n, nfree; - - n = EVNEEDED(nchars); - if(p = e->val){ /* assign = */ - if(p->n < n){ - if(p+p->n == envalloc.vfree){ - compactenv(e, n - p->n); - p = e->val; - envalloc.vfree += n - p->n; - }else{ - compactenv(e, n); - p = envalloc.vfree; - envalloc.vfree += n; - memcpy(p, e->val, e->val->n*sizeof(Envval)); - p->e = e; - e->val->e = 0; - e->val = p; - } - p->n = n; - } - }else{ - compactenv(e, n); - p = envalloc.vfree; - envalloc.vfree += n; - p->n = n; - p->e = e; - e->val = p; - } -} - -/* - * Make sure there is room for n Envval's at the end of envalloc.vfree. - * Call this with envalloc and e locked. - */ -void -compactenv(Env *e, ulong n) -{ - Envval *p1, *p2; - Env *p2e; - - if(envalloc.end-envalloc.vfree >= n) - return; - p1 = envalloc.arena; /* dest */ - p2 = envalloc.arena; /* source */ - while(p2 < envalloc.vfree){ - p2e = p2->e; - if(p2e == 0){ - Free: - p2 += p2->n; - continue; - } - if(p2e=envalloc.earena+conf.nenv){ - print("%lux not an env\n", p2e); - panic("compactenv"); - } - if(p1 != p2){ - if(p2e != e) - lock(p2e); - if(p2->e != p2e){ /* freed very recently */ - print("compactenv p2e moved\n"); - if(p2->e) - panic("compactenv p2->e %lux\n", p2->e); - unlock(p2e); - goto Free; - } - if(p2+p2->n > envalloc.end) - panic("compactenv copying too much"); - memcpy(p1, p2, p2->n*sizeof(Envval)); - p2e->val = p1; - if(p2e != e) - unlock(p2e); - } - p2 += p1->n; - p1 += p1->n; - } - envalloc.vfree = p1; - if(envalloc.end-envalloc.vfree < n){ - print("env compact failed\n"); - error(Enoenv); - } -} - -/* - * Return an env with a copy of e's value. - * envalloc and e should be locked, - * and the value returned will be locked too. - */ -Env * -copyenv(Env *e, int trunc) -{ - Env *ne; - int n; - - ne = envalloc.efree; - if(!ne){ - print("out of envs\n"); - error(Enoenv); - } - envalloc.efree = ne->next; - lock(ne); - if(waserror()){ - unlock(ne); - nexterror(); - } - ne->next = 0; - ne->pgref = 1; - strncpy(ne->name, e->name, NAMELEN); - if(e->val && !trunc){ - n = e->val->len; - /* - * growenval can't hold the lock on another env - * because compactenv assumes only one is held - */ - unlock(e); - growenval(ne, n); - lock(e); - if(n != e->val->len){ - print("e changed in copyenv\n"); - if(n > ne->val->len) - n = ne->val->len; - } - if((char*)(ne->val+ne->val->n) < ne->val->dat+n) - panic("copyenv corrupt"); - memcpy(ne->val->dat, e->val->dat, n); - ne->val->len = n; - } - poperror(); - return ne; -} - -int -envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) -{ - Env *e; - Pgrp *pg; - int ans; - - pg = u->p->pgrp; - lock(pg); - if(s >= pg->nenv) - ans = -1; - else{ - e = pg->etab[s].env; - if(e == 0) - ans = 0; - else{ - lock(e); - devdir(c, (Qid){s+1,0}, e->name, e->val? e->val->len : 0, 0666, dp); - unlock(e); - ans = 1; - } - } - unlock(pg); - return ans; -} - -Chan* -envattach(char *spec) -{ - return devattach('e', spec); -} - -Chan* -envclone(Chan *c, Chan *nc) -{ - Pgrp *pg; - - if(!(c->qid.path&CHDIR)){ - pg = u->p->pgrp; - lock(pg); - pg->etab[c->qid.path-1].chref++; - unlock(pg); - } - return devclone(c, nc); -} - -int -envwalk(Chan *c, char *name) -{ - Pgrp *pg; - - if(devwalk(c, name, 0, 0, envgen)){ - if(!(c->qid.path&CHDIR)){ - pg = u->p->pgrp; - lock(pg); - pg->etab[c->qid.path-1].chref++; - unlock(pg); - return 1; - } - } - return 0; -} - -void -envstat(Chan *c, char *db) -{ - devstat(c, db, 0, 0, envgen); -} - -Chan * -envopen(Chan *c, int omode) -{ - Env *e, *ne; - Envp *ep; - Pgrp *pg; - - if(omode & (OWRITE|OTRUNC)){ - if(c->qid.path & CHDIR) - error(Eperm); - pg = u->p->pgrp; - lock(pg); - ep = &pg->etab[c->qid.path-1]; - e = ep->env; - if(!e){ - unlock(pg); - error(Egreg); - } - lock(&envalloc); - lock(e); - if(waserror()){ - unlock(e); - unlock(&envalloc); - unlock(pg); - nexterror(); - } - if(e->pgref == 0) - panic("envopen"); - if(e->pgref == 1){ - if((omode&OTRUNC) && e->val){ - e->val->e = 0; - e->val = 0; - } - }else{ - ne = copyenv(e, omode&OTRUNC); - e->pgref--; /* it will still be positive */ - ep->env = ne; - unlock(ne); - } - poperror(); - unlock(e); - unlock(&envalloc); - unlock(pg); - } - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -envcreate(Chan *c, char *name, int omode, ulong perm) -{ - Env *e; - Pgrp *pg; - int i; - - if(c->qid.path != CHDIR) - error(Eperm); - pg = u->p->pgrp; - lock(pg); - lock(&envalloc); - if(waserror()){ - unlock(&envalloc); - unlock(pg); - nexterror(); - } - e = envalloc.efree; - if(e == 0){ - print("out of envs\n"); - error(Enoenv); - } - envalloc.efree = e->next; - e->next = 0; - e->pgref = 1; - strncpy(e->name, name, NAMELEN); - if(pg->nenv == conf.npgenv){ - for(i = 0; inenv; i++) - if(pg->etab[i].chref == 0) - break; - if(i == pg->nenv){ - print("out of pgroup envs\n"); - error(Enoenv); - } - }else - i = pg->nenv++; - c->qid.path = i+1; - pg->etab[i].env = e; - pg->etab[i].chref = 1; - unlock(&envalloc); - unlock(pg); - c->offset = 0; - c->mode = openmode(omode); - poperror(); - c->flag |= COPEN; -} - -void -envremove(Chan *c) -{ - Env *e; - Envp *ep; - Pgrp *pg; - - if(c->qid.path & CHDIR) - error(Eperm); - pg = u->p->pgrp; - lock(pg); - ep = &pg->etab[c->qid.path-1]; - e = ep->env; - if(!e){ - unlock(pg); - error(Enonexist); - } - ep->env = 0; - ep->chref--; - envpgclose(e); - unlock(pg); -} - -void -envwstat(Chan *c, char *db) -{ int dumpenv(void); - dumpenv(); /*DEBUG*/ - print("envwstat\n"); - error(Egreg); -} - -void -envclose(Chan * c) -{ - Pgrp *pg; - - if(c->qid.path & CHDIR) - return; - pg = u->p->pgrp; - lock(pg); - pg->etab[c->qid.path-1].chref--; - unlock(pg); -} - -void -envpgclose(Env *e) -{ - lock(&envalloc); - lock(e); - if(--e->pgref <= 0){ - if(e->val){ - e->val->e = 0; - e->val = 0; - } - e->next = envalloc.efree; - envalloc.efree = e; - } - unlock(e); - unlock(&envalloc); -} - -long -envread(Chan *c, void *va, long n) -{ - Env *e; - Envval *ev; - char *p; - long vn; - Pgrp *pg; - char *a = va; - - if(c->qid.path & CHDIR) - return devdirread(c, a, n, 0, 0, envgen); - pg = u->p->pgrp; - lock(pg); - e = pg->etab[c->qid.path-1].env; - if(!e){ - unlock(pg); - error(Eio); - } - lock(e); - ev = e->val; - vn = ev? e->val->len : 0; - if(c->offset+n > vn) - n = vn - c->offset; - if(n <= 0) - n = 0; - else - memcpy(a, ev->dat+c->offset, n); - unlock(e); - unlock(pg); - return n; -} - -long -envwrite(Chan *c, void *va, long n) -{ - Env *e; - char *p; - Envval *ev; - long vn; - Pgrp *pg; - char *a = va; - - if(n <= 0) - return 0; - pg = u->p->pgrp; - lock(pg); - e = pg->etab[c->qid.path-1].env; /* caller checks for CHDIR */ - if(!e){ - unlock(pg); - error(Eio); - } - lock(&envalloc); - lock(e); - if(waserror()){ - unlock(e); - unlock(&envalloc); - unlock(pg); - nexterror(); - } - if(e->pgref>1) - panic("envwrite to non-duped env"); - growenval(e, c->offset+n); - ev = e->val; - vn = ev? ev->len : 0; - if(c->offset > vn) - error(Egreg); /* perhaps should zero fill */ - memcpy(ev->dat+c->offset, a, n); - e->val->len = c->offset+n; - poperror(); - unlock(e); - unlock(&envalloc); - unlock(pg); - return n; -} - -void -dumpenv(void) -{ - Env *e; - Envp *ep; - Envval *ev; - Pgrp *pg; - int i; - char hold; - - pg = u->p->pgrp; - for(ep=pg->etab, i=0; inenv; i++, ep++) - print("P%d(%lux %d)",i, ep->env, ep->chref); - for(e=envalloc.earena; e<&envalloc.earena[conf.nenv]; e++) - if(e->pgref){ - print("E{%lux %d '%s'}[", e, e->pgref, e->name); - if(e->val){ - hold = e->val->dat[e->val->len]; - e->val->dat[e->val->len] = 0; - print("%s", e->val->dat); - e->val->dat[e->val->len] = hold; - } - print("]"); - }else if(e->val) - print("whoops, free env %lux has val=%lux\n",e,e->val); - for(i=0, e=envalloc.efree; e; e=e->next) - i++; - print("\n%d free envs", i); - for(i=0, ev=envalloc.arena; evn) - if(!ev->e) - i += ev->n*sizeof(Envval); - print(" %d free enval chars\n", i+((char *)envalloc.end-(char*)envalloc.vfree)); -} diff --git a/gnot/devmnt.c b/gnot/devmnt.c deleted file mode 100644 index d026eaf296f0badd4b3c59cdc1f26c3d8c13d3ae..0000000000000000000000000000000000000000 --- a/gnot/devmnt.c +++ /dev/null @@ -1,888 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#include "devtab.h" - -#include "fcall.h" - -typedef struct Mnt Mnt; -typedef struct Mnthdr Mnthdr; -typedef struct MntQ MntQ; - -struct Mnt -{ - Ref; /* for number of chans, incl. mntpt but not msg */ - ulong mntid; /* serial # */ - Chan *mntpt; /* channel in user's name space */ - MntQ *q; -}; - -struct MntQ -{ - Ref; - QLock; /* for access */ - MntQ *next; /* for allocation */ - Chan *msg; /* for reading and writing messages */ - Proc *reader; /* process reading response */ - Mnthdr *writer; /* queue of headers of written messages */ -}; - -#define BUFSIZE (MAXFDATA+500) /* BUG */ -typedef struct Mntbuf Mntbuf; -struct Mntbuf -{ - Mntbuf *next; - char buf[BUFSIZE]; -}; - -struct -{ - Lock; - Mntbuf *free; -}mntbufalloc; - -struct Mnthdr -{ - Mnthdr *next; /* in free list or writers list */ - Mnthdr *prev; /* in writers list only */ - short active; - short flushing; /* a Tflush has been sent */ - Fcall thdr; - Fcall rhdr; - Rendez r; - Proc *p; - Mntbuf *mbr; - int readreply; /* true if we are reader or our reply has come */ -}; - -struct -{ - Lock; - Mnthdr *arena; - Mnthdr *free; -}mnthdralloc; - -struct -{ - Lock; - QLock; - MntQ *arena; - MntQ *free; -}mntqalloc; - -struct -{ - Lock; - long id; -}mntid; - -Mnt *mnt; -void mntxmit(Mnt*, Mnthdr*); - -Mntbuf* -mballoc(void) -{ - Mntbuf *mb; - -loop: - lock(&mntbufalloc); - if(mb = mntbufalloc.free){ /* assign = */ - mntbufalloc.free = mb->next; - unlock(&mntbufalloc); - return mb; - } - unlock(&mntbufalloc); - print("no mntbufs\n"); - if(u == 0) - panic("mballoc"); - u->p->state = Wakeme; - alarm(1000, wakeme, u->p); - sched(); - goto loop; -} - -void -mbfree(Mntbuf *mb) -{ - lock(&mntbufalloc); - mb->next = mntbufalloc.free; - mntbufalloc.free = mb; - unlock(&mntbufalloc); -} - -Mnthdr* -mhalloc(void) -{ - Mnthdr *mh; - -loop: - lock(&mnthdralloc); - if(mh = mnthdralloc.free){ /* assign = */ - mnthdralloc.free = mh->next; - mh->flushing = 0; - unlock(&mnthdralloc); - return mh; - } - unlock(&mnthdralloc); - print("no mnthdrs\n"); - if(u == 0) - panic("mhalloc"); - u->p->state = Wakeme; - alarm(1000, wakeme, u->p); - sched(); - goto loop; -} - -void -mhfree(Mnthdr *mh) -{ - if(mh->flushing) - return; - mh->active = 0; - lock(&mnthdralloc); - mh->next = mnthdralloc.free; - mnthdralloc.free = mh; - unlock(&mnthdralloc); -} - -MntQ* -mqalloc(Chan *msg) /* mntqalloc is qlocked */ -{ - MntQ *q; - - if(q = mntqalloc.free){ /* assign = */ - mntqalloc.free = q->next; - lock(q); - q->ref = 1; - q->msg = msg; - unlock(q); - incref(msg); - q->writer = 0; - q->reader = 0; - return q; - } - panic("no mntqs\n"); /* there MUST be enough */ -} - -void -mqfree(MntQ *mq) -{ - Chan *msg = 0; - - lock(mq); - if(--mq->ref == 0){ - msg = mq->msg; - mq->msg = 0; - lock(&mntqalloc); - mq->next = mntqalloc.free; - mntqalloc.free = mq; - unlock(&mntqalloc); - } - unlock(mq); - if(msg) /* after locks are down */ - close(msg); -} - -Mnt* -mntdev(int dev, int noerr) -{ - Mnt *m; - int i; - - for(m=mnt,i=0; imntid == dev){ - if(m->q == 0) - break; - return m; - } - if(noerr) - return 0; - error(Eshutdown); -} - -void -mntreset(void) -{ - int i; - Mntbuf *mb; - Mnthdr *mh; - MntQ *mq; - - mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0); - - mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0); - for(i=0; iref == 0) - goto Found; - unlock(m); - } - error(Enomntdev); - - Found: - m->ref = 1; - unlock(m); - lock(&mntid); - m->mntid = ++mntid.id; - unlock(&mntid); - c = devattach('M', bogus.spec); - c->dev = m->mntid; - m->mntpt = c; - cm = bogus.chan; - - /* - * Look for queue to same msg channel - */ - q = mntqalloc.arena; - qlock(&mntqalloc); - for(i=0; imsg==cm){ - lock(q); - if(q->ref && q->msg==cm){ - m->q = q; - q->ref++; - unlock(q); - goto out; - } - unlock(q); - } - m->q = mqalloc(cm); - - out: - qunlock(&mntqalloc); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - close(c); - nexterror(); - } - mh->thdr.type = Tattach; - mh->thdr.fid = c->fid; - memcpy(mh->thdr.uname, u->p->pgrp->user, NAMELEN); - strcpy(mh->thdr.aname, bogus.spec); - strcpy(mh->thdr.auth, bogus.auth); - mntxmit(m, mh); - c->qid = mh->rhdr.qid; - c->mchan = m->q->msg; - c->mqid = c->qid; - mhfree(mh); - poperror(); - return c; -} - -Chan* -mntclone(Chan *c, Chan *nc) -{ - Mnt *m; - Mnthdr *mh; - int new; - - new = 0; - if(nc == 0){ - nc = newchan(); - new = 1; - if(waserror()){ - close(nc); - nexterror(); - } - } - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = Tclone; - mh->thdr.fid = c->fid; - mh->thdr.newfid = nc->fid; - mntxmit(m, mh); - nc->type = c->type; - nc->dev = c->dev; - nc->qid = c->qid; - nc->mode = c->mode; - nc->flag = c->flag; - nc->offset = c->offset; - nc->mnt = c->mnt; - nc->mchan = c->mchan; - nc->mqid = c->qid; - mhfree(mh); - poperror(); - if(new) - poperror(); - incref(m); - return nc; -} - -int -mntwalk(Chan *c, char *name) -{ - Mnt *m; - Mnthdr *mh; - int found; - - found = 1; - m = mntdev(c->dev, 0); - mh = mhalloc(); - mh->thdr.type = Twalk; - mh->thdr.fid = c->fid; - strcpy(mh->thdr.name, name); - if(waserror()){ /* BUG: can check type of error? */ - found = 0; - goto Out; - } - mntxmit(m, mh); - c->qid = mh->rhdr.qid; - poperror(); - Out: - mhfree(mh); - return found; -} - -void -mntstat(Chan *c, char *dp) -{ - Mnt *m; - Mnthdr *mh; - - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = Tstat; - mh->thdr.fid = c->fid; - mntxmit(m, mh); - memcpy(dp, mh->rhdr.stat, DIRLEN); - dp[DIRLEN-4] = devchar[c->type]; - dp[DIRLEN-3] = 0; - dp[DIRLEN-2] = c->dev; - dp[DIRLEN-1] = c->dev>>8; - mhfree(mh); - poperror(); -} - -Chan* -mntopen(Chan *c, int omode) -{ - Mnt *m; - Mnthdr *mh; - - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = Topen; - mh->thdr.fid = c->fid; - mh->thdr.mode = omode; - mntxmit(m, mh); - c->qid = mh->rhdr.qid; - mhfree(mh); - poperror(); - c->offset = 0; - c->mode = openmode(omode); - c->flag |= COPEN; - return c; -} - -void -mntcreate(Chan *c, char *name, int omode, ulong perm) -{ - Mnt *m; - Mnthdr *mh; - - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = Tcreate; - mh->thdr.fid = c->fid; - strcpy(mh->thdr.name, name); - mh->thdr.mode = omode; - mh->thdr.perm = perm; - mntxmit(m, mh); - c->qid = mh->rhdr.qid; - mhfree(mh); - poperror(); - c->flag |= COPEN; - c->mode = openmode(omode); - c->qid = mh->rhdr.qid; -} - -void -mntclunk(Chan *c, int t) -{ - Mnt *m; - Mnthdr *mh; - MntQ *q; - int waserr; - - m = mntdev(c->dev, 0); - mh = mhalloc(); - mh->thdr.type = t; - mh->thdr.fid = c->fid; - waserr = 0; - if(waserror()) /* gotta clean up as if there wasn't */ - waserr = 1; - else - mntxmit(m, mh); - mhfree(mh); - if(c == m->mntpt) - m->mntpt = 0; - lock(m); - if(--m->ref == 0){ /* BUG: need to hang up all pending i/o */ - q = m->q; - m->q = 0; - m->mntid = 0; - unlock(m); /* mqfree can take time */ - mqfree(q); - }else - unlock(m); - if(waserr) - nexterror(); - poperror(); -} - -void -mntclose(Chan *c) -{ - mntclunk(c, Tclunk); -} - -long -mntreadwrite(Chan *c, void *vbuf, long n, int type) -{ - Mnt *m; - Mnthdr *mh; - long nt, nr, count, offset; - char *buf; - - buf = vbuf; - count = 0; - offset = c->offset; - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = type; - mh->thdr.fid = c->fid; - Loop: - nt = n; - if(nt > MAXFDATA) - nt = MAXFDATA; - mh->thdr.offset = offset; - mh->thdr.count = nt; - mh->thdr.data = buf; - mntxmit(m, mh); - nr = mh->rhdr.count; - offset += nr; - count += nr; - buf += nr; - n -= nr; - if(n && nr==nt) - goto Loop; - mhfree(mh); - poperror(); - return count; -} - -long -mntread(Chan *c, void *buf, long n) -{ - long i; - uchar *b; - - n = mntreadwrite(c, buf, n, Tread); - if(c->qid.path & CHDIR){ - b = (uchar*)buf; - for(i=n-DIRLEN; i>=0; i-=DIRLEN){ - b[DIRLEN-4] = devchar[c->type]; - b[DIRLEN-3] = 0; - b[DIRLEN-2] = c->dev; - b[DIRLEN-1] = c->dev>>8; - b += DIRLEN; - } - } - return n; -} - -long -mntwrite(Chan *c, void *buf, long n) -{ - return mntreadwrite(c, buf, n, Twrite); -} - -void -mntremove(Chan *c) -{ - mntclunk(c, Tremove); -} - -void -mntwstat(Chan *c, char *dp) -{ - Mnt *m; - Mnthdr *mh; - - m = mntdev(c->dev, 0); - mh = mhalloc(); - if(waserror()){ - mhfree(mh); - nexterror(); - } - mh->thdr.type = Twstat; - mh->thdr.fid = c->fid; - memcpy(mh->thdr.stat, dp, DIRLEN); - mntxmit(m, mh); - mhfree(mh); - poperror(); -} - -void -mntwunlink(MntQ *q, Mnthdr *w) /* queue is locked and w is a writer */ -{ - if(w->next) - w->next->prev = w->prev; - if(w->prev) - w->prev->next = w->next; - else{ - q->writer = w->next; - if(q->writer) - q->writer->prev = 0; - } -} - -/* - * m->q is unlocked. Send Tflush message to flush omh->tag. - * Cut off all errors. Caller will free omh - */ -void -mntflush(Mnt *m, Mnthdr *omh) /* queue is unlocked */ -{ - Mnthdr *mh; - - if(omh->thdr.type == Tflush) - return; - - mh = mhalloc(); - if(waserror()){ - omh->flushing = 0; - mhfree(mh); - return; /* no more errors please */ - } - mh->thdr.type = Tflush; - mh->thdr.oldtag = omh->thdr.tag; - mntxmit(m, mh); - omh->flushing = 0; - mhfree(mh); - poperror(); -} - -void -mnterrdequeue(Mnt *m, Mnthdr *mh) /* queue is unlocked */ -{ - Mnthdr *w; - MntQ *q; - - mh->flushing = 1; - q = m->q; - qlock(q); - /* take self from queue if necessary */ - if(q->reader == u->p){ /* advance a writer to reader */ - w = q->writer; - if(w){ - mntwunlink(q, w); - q->reader = w->p; - wakeup(&w->r); - }else{ - q->reader = 0; - q->writer = 0; - } - }else - mntwunlink(q, mh); - qunlock(q); - mntflush(m, mh); -} - -int -mntreadreply(void *a) -{ - return ((Mnthdr *)a)->readreply; -} - -void -mntxmit(Mnt *m, Mnthdr *mh) -{ - ulong n; - Mntbuf *mbw; - Mnthdr *w, *ow; - MntQ *q; - int qlocked, tag, written; - - mh->mbr = 0; - mbw = mballoc(); - if(waserror()){ /* 1 */ - if(mh->mbr) - mbfree(mh->mbr); - mbfree(mbw); - nexterror(); - } - n = convS2M(&mh->thdr, mbw->buf); - q = m->q; - if(q == 0) - error(Eshutdown); -#ifdef BIT3 - /* - * Bit3 does its own multiplexing. (Well, the file server does.) - * The code is different enough that it's broken out separately here. - */ - if(devchar[q->msg->type] != '3') - goto Normal; - - incref(q); - if(waserror()){ /* 2 */ - mqfree(q); - nexterror(); - } - if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n) != n){ - print("short write in mntxmit\n"); - error(Eshortmsg); - } - - /* - * Read response - */ - mh->mbr = mballoc(); - n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE); - mqfree(q); - poperror(); /* 2 */ - - if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){ - print("format error in mntxmit\n"); - error(Ebadmsg); - } - - /* - * Various checks - */ - if(mh->rhdr.tag != mh->thdr.tag){ - print("tag mismatch %d %d\n", mh->rhdr.tag, mh->thdr.tag); - error(Ebadmsg); - } - if(mh->rhdr.type == Rerror){ - if(m->mntpt) - errors(mh->rhdr.ename); - error(Eshutdown); - } - if(mh->rhdr.type != mh->thdr.type+1){ - print("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1); - error(Ebadmsg); - } - if(mh->rhdr.fid != mh->thdr.fid){ - print("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type); - error(Ebadmsg); - } - - /* - * Copy out on read - */ - if(mh->thdr.type == Tread) - memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); - mbfree(mh->mbr); - mbfree(mbw); - poperror(); /* 1 */ - return; - - Normal: -#endif - incref(q); - qlock(q); - qlocked = 1; - if(waserror()){ /* 2 */ - if(qlocked) - qunlock(q); - mqfree(q); - nexterror(); - } - mh->readreply = 0; - mh->active = 1; - if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n) != n){ - print("short write in mntxmit\n"); - error(Eshortmsg); - } - if(q->reader == 0){ /* i will read */ - q->reader = u->p; - Read: - qunlock(q); - qlocked = 0; - if(waserror()){ /* 3 */ - mnterrdequeue(m, mh); - nexterror(); - } - mh->mbr = mballoc(); - n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE); - poperror(); /* 3 */ - if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){ - print("bad reply message\n"); - mnterrdequeue(m, mh); - error(Ebadmsg); - } - /* - * Response might not be mine - */ - qlock(q); - qlocked = 1; - tag = mh->rhdr.tag; - if(tag == mh->thdr.tag){ /* it's mine */ - q->reader = 0; - if(w = q->writer){ /* advance a writer to reader */ - mntwunlink(q, w); - q->reader = w->p; - w->readreply = 1; - wakeup(&w->r); - } - mh->active = 0; - qunlock(q); - qlocked = 0; - goto Respond; - } - /* - * Hand response to correct recipient - */ - if(tag<0 || tag>=conf.nmnthdr){ - print("unknown tag %d\n", tag); - goto Read; - } - w = &mnthdralloc.arena[tag]; - if(w->flushing || !w->active) /* nothing to do; mntflush will clean up */ - goto Read; - w->mbr = mh->mbr; - mh->mbr = 0; - memcpy(&w->rhdr, &mh->rhdr, sizeof mh->rhdr); - mntwunlink(q, w); - w->readreply = 1; - wakeup(&w->r); - goto Read; - }else{ - mh->p = u->p; - /* put self in queue */ - mh->next = q->writer; - mh->prev = 0; - if(q->writer) - q->writer->prev = mh; - q->writer = mh; - qunlock(q); - qlocked = 0; - if(waserror()){ /* interrupted sleep */ - mnterrdequeue(m, mh); - nexterror(); - } - sleep(&mh->r, mntreadreply, mh); - poperror(); - qlock(q); - qlocked = 1; - if(q->reader == u->p) /* i got promoted */ - goto Read; - mh->active = 0; - qunlock(q); - qlocked = 0; - goto Respond; - } - - Respond: - mqfree(q); - poperror(); /* 2 */ - if(mh->rhdr.type == Rerror){ - if(m->mntpt) - errors(mh->rhdr.ename); - error(Eshutdown); - }else if(mh->rhdr.type != mh->thdr.type+1){ - print("bad type %d not %d in mntxmit\n", mh->rhdr.type, mh->thdr.type+1); - error(Ebadmsg); - } - /* - * Copy out on read - */ - if(mh->thdr.type == Tread){ - if(mh->rhdr.count > mh->thdr.count) - error(Ebadcnt); - memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); - } - mbfree(mh->mbr); - mbfree(mbw); - poperror(); /* 1 */ -} - -mntdump() -{ - int i; - MntQ *q; - Mnthdr *h; - Proc *p; - - for(i=0; imsg) - continue; - p = q->reader; - print("q rdr %d wrtr ", p? p->pid : 0); - for(h=q->writer; h; h=h->next) - print("(%lux %lux %d)", h, &h->r, (p=h->p)? p->pid : 0); - print("\n"); - } -} diff --git a/gnot/devpipe.c b/gnot/devpipe.c deleted file mode 100644 index c827fcf165afc04c77c90c4e3c76c88b9e163c89..0000000000000000000000000000000000000000 --- a/gnot/devpipe.c +++ /dev/null @@ -1,312 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#include "devtab.h" -#include "fcall.h" - -typedef struct Pipe Pipe; - -struct Pipe -{ - Ref; - int debug; - Pipe *next; -}; - -struct Pipealloc -{ - Lock; - Pipe *pipe; - Pipe *free; -} pipealloc; - -static void pipeiput(Queue*, Block*); -static void pipeoput(Queue*, Block*); -static void pipestclose(Queue *); -Qinfo pipeinfo = -{ - pipeiput, - pipeoput, - 0, - pipestclose, - "pipe" -}; - -Dirtab pipedir[]={ - "data", {Sdataqid}, 0, 0600, - "ctl", {Sctlqid}, 0, 0600, - "data1", {Sdataqid}, 0, 0600, - "ctl1", {Sctlqid}, 0, 0600, -}; -#define NPIPEDIR 4 - -void -pipeinit(void) -{ -} - -/* - * allocate structures for conf.npipe pipes - */ -void -pipereset(void) -{ - Pipe *p, *ep; - - pipealloc.pipe = ialloc(conf.npipe * sizeof(Pipe), 0); - ep = &pipealloc.pipe[conf.npipe-1]; - for(p = pipealloc.pipe; p < ep; p++) - p->next = p+1; - pipealloc.free = pipealloc.pipe; -} - -/* - * create a pipe, no streams are created until an open - */ -Chan* -pipeattach(char *spec) -{ - Pipe *p; - Chan *c; - - c = devattach('|', spec); - - lock(&pipealloc); - if(pipealloc.free == 0){ - unlock(&pipealloc); - error(Enopipe); - } - p = pipealloc.free; - pipealloc.free = p->next; - if(incref(p) != 1) - panic("pipeattach"); - unlock(&pipealloc); - - c->qid = (Qid){CHDIR|STREAMQID(2*(p - pipealloc.pipe), 0), 0}; - return c; -} - -Chan* -pipeclone(Chan *c, Chan *nc) -{ - Pipe *p; - - p = &pipealloc.pipe[STREAMID(c->qid.path)/2]; - nc = devclone(c, nc); - if(incref(p) <= 1) - panic("pipeclone"); - return nc; -} - -int -pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) -{ - int id; - - id = STREAMID(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, tab->perm, dp); - return 1; -} - - -int -pipewalk(Chan *c, char *name) -{ - return devwalk(c, name, pipedir, NPIPEDIR, pipegen); -} - -void -pipestat(Chan *c, char *db) -{ - streamstat(c, db, "pipe"); -} - -/* - * if the stream doesn't exist, create it - */ -Chan * -pipeopen(Chan *c, int omode) -{ - Pipe *p; - Stream *local, *remote; - - if(c->qid.path & CHDIR){ - if(omode != OREAD) - error(Ebadarg); - c->mode = omode; - c->flag |= COPEN; - c->offset = 0; - return c; - } - - p = &pipealloc.pipe[STREAMID(c->qid.path)/2]; - remote = 0; - if(waserror()){ - unlock(p); - if(remote) - streamclose1(remote); - nexterror(); - } - lock(p); - streamopen(c, &pipeinfo); - local = c->stream; - if(local->devq->ptr == 0){ - /* - * First stream opened, create the other end also - */ - remote = streamnew(c->type, c->dev, STREAMID(c->qid.path)^1, &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; - - /* - * increment the inuse count to reflect the - * pointer from the other stream. - */ - if(streamenter(local)<0) - panic("pipeopen"); - } - unlock(p); - poperror(); - - c->mode = omode&~OTRUNC; - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -pipecreate(Chan *c, char *name, int omode, ulong perm) -{ - error(Egreg); -} - -void -piperemove(Chan *c) -{ - error(Egreg); -} - -void -pipewstat(Chan *c, char *db) -{ - error(Eperm); -} - -void -pipeclose(Chan *c) -{ - Pipe *p; - Stream *remote; - - p = &pipealloc.pipe[STREAMID(c->qid.path)/2]; - - /* - * take care of associated streams - */ - if(c->stream){ - remote = c->stream->devq->ptr; - if(streamclose(c) <= 0) - streamexit(remote, 0); - } - - /* - * free the structure - */ - if(decref(p) == 0){ - lock(&pipealloc); - p->next = pipealloc.free; - pipealloc.free = p; - unlock(&pipealloc); - } - if(p->ref < 0) - panic("pipeexit"); -} - -long -piperead(Chan *c, void *va, long n) -{ - if(c->qid.path & CHDIR) - return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen); - else - return streamread(c, va, n); -} - -/* - * a write to a closed pipe causes a note to be sent to - * the process. - */ -long -pipewrite(Chan *c, void *va, long n) -{ - if(waserror()){ - postnote(u->p, 1, "sys: write on closed pipe", NExit); - error(Egreg); - } - n = streamwrite(c, va, n, 0); - poperror(); - return n; -} - -/* - * stream stuff - */ -/* - * send a block up stream to the process. - * sleep untill there's room upstream. - */ -static void -pipeiput(Queue *q, Block *bp) -{ - FLOWCTL(q); - PUTNEXT(q, bp); -} - -/* - * send the block to the other side without letting the connection - * disappear in mid put. - */ -static void -pipeoput(Queue *q, Block *bp) -{ - PUTNEXT(q, bp); -} - -/* - * send a hangup and disconnect the streams - */ -static void -pipestclose(Queue *q) -{ - Block *bp; - Stream *remote; - - /* - * 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; - bp = allocb(0); - bp->type = M_HANGUP; - PUTNEXT(q, bp); -} diff --git a/gnot/devproc.c b/gnot/devproc.c deleted file mode 100644 index f0da947b85c2ddc02e1029f74d0cd19559709bff..0000000000000000000000000000000000000000 --- a/gnot/devproc.c +++ /dev/null @@ -1,431 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#include "devtab.h" - -enum{ - Qdir, - Qctl, - Qmem, - Qnote, - Qnotepg, - Qproc, - Qstatus, - Qtext, -}; - -Dirtab procdir[]={ - "ctl", {Qctl}, 0, 0600, - "mem", {Qmem}, 0, 0600, - "note", {Qnote}, 0, 0600, - "notepg", {Qnotepg}, 0, 0200, - "proc", {Qproc}, sizeof(Proc), 0600, - "status", {Qstatus}, NAMELEN+12+6*12, 0600, - "text", {Qtext}, 0, 0600, -}; - -/* - * Qids are, in path: - * 4 bits of file type (qids above) - * 23 bits of process slot number + 1 - * in vers, - * 32 bits of pid, for consistency checking - * If notepg, c->pgrpid.path is pgrp slot, .vers is pgrpid. - */ -#define NPROC (sizeof procdir/sizeof(Dirtab)) -#define QSHIFT 4 /* location in qid of proc slot # */ -#define QID(q) (((q).path&0x0000000F)>>0) -#define SLOT(q) ((((q).path&0x07FFFFFF0)>>QSHIFT)-1) -#define PID(q) ((q).vers) - -int -procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) -{ - Proc *p; - char buf[NAMELEN]; - ulong pid; - - if(c->qid.path == CHDIR){ - if(s >= conf.nproc) - return -1; - p = proctab(s); - pid = p->pid; - if(pid == 0) - return 0; - sprint(buf, "%d", pid); - devdir(c, (Qid){CHDIR|((s+1)<= NPROC) - return -1; - if(tab) - panic("procgen"); - tab = &procdir[s]; - devdir(c, (Qid){(~CHDIR)&(c->qid.path|tab->qid.path), c->qid.vers}, - tab->name, tab->length, tab->perm, dp); - return 1; -} - -void -procinit(void) -{ - if(conf.nproc >= (1<<(16-QSHIFT))-1) - print("warning: too many procs for devproc\n"); -} - -void -procreset(void) -{ -} - -Chan* -procattach(char *spec) -{ - Chan *c; - return devattach('p', spec); -} - -Chan* -procclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -procwalk(Chan *c, char *name) -{ - return devwalk(c, name, 0, 0, procgen); -} - -void -procstat(Chan *c, char *db) -{ - devstat(c, db, 0, 0, procgen); -} - -Chan * -procopen(Chan *c, int omode) -{ - Proc *p; - Pgrp *pg; - Orig *o; - Chan *tc; - - if(c->qid.path == CHDIR){ - if(omode != OREAD) - error(Eperm); - goto done; - } - p = proctab(SLOT(c->qid)); - pg = p->pgrp; - if(p->pid != PID(c->qid)) - Died: - error(Eprocdied); - omode = openmode(omode); - - switch(QID(c->qid)){ - case Qtext: - o = p->seg[TSEG].o; - if(o==0 || p->state==Dead) - goto Died; - tc = o->chan; - if(tc == 0) - goto Died; - if(incref(tc) == 0){ - Close: - close(tc); - goto Died; - } - if(!(tc->flag&COPEN) || tc->mode!=OREAD) - goto Close; - if(p->pid != PID(c->qid)) - goto Close; - qlock(tc); - tc->offset = 0; - qunlock(tc); - return tc; - case Qctl: - case Qnote: - break; - - case Qnotepg: - if(omode!=OWRITE || pg->pgrpid==1) /* easy to do by mistake */ - error(Eperm); - c->pgrpid.path = pg->index+1; - c->pgrpid.vers = pg->pgrpid; - break; - - case Qdir: - case Qmem: - case Qproc: - case Qstatus: - if(omode != OREAD) - error(Eperm); - break; - default: - pprint("unknown qid in devopen\n"); - error(Egreg); - } - /* - * Affix pid to qid - */ - if(p->state != Dead) - c->qid.vers = p->pid; - done: - c->mode = omode; - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -proccreate(Chan *c, char *name, int omode, ulong perm) -{ - error(Eperm); -} - -void -procremove(Chan *c) -{ - error(Eperm); -} - -void -procwstat(Chan *c, char *db) -{ - error(Eperm); -} - -void -procclose(Chan * c) -{ -} - -long -procread(Chan *c, void *va, long n) -{ - char *a = va, *b; - char statbuf[2*NAMELEN+12+6*12]; - Proc *p; - Seg *s; - Orig *o; - Page *pg; - KMap *k; - PTE *pte, *opte; - int i; - long l; - long pid; - User *up; - - if(c->qid.path & CHDIR) - return devdirread(c, a, n, 0, 0, procgen); - - /* - * BUG: should lock(&p->debug)? - */ - p = proctab(SLOT(c->qid)); - if(p->pid != PID(c->qid)) - error(Eprocdied); - - switch(QID(c->qid)){ - case Qmem: - /* - * One page at a time - */ - if(((c->offset+n)&~(BY2PG-1)) != (c->offset&~(BY2PG-1))) - n = BY2PG - (c->offset&(BY2PG-1)); - s = seg(p, c->offset); - if(s){ - o = s->o; - if(o == 0) - error(Eprocdied); - lock(o); - if(s->o!=o || p->pid!=PID(c->qid)){ - unlock(o); - error(Eprocdied); - } - if(seg(p, c->offset) != s){ - unlock(o); - error(Egreg); - } - pte = &o->pte[(c->offset-o->va)>>PGSHIFT]; - if(s->mod){ - opte = pte; - while(pte = pte->nextmod) /* assign = */ - if(pte->proc == p) - break; - if(pte == 0) - pte = opte; - } - pg = pte->page; - unlock(o); - if(pg == 0){ - pprint("nonresident page addr %lux (complain to rob)\n", c->offset); - memset(a, 0, n); - }else{ - k = kmap(pg); - b = (char*)VA(k); - memcpy(a, b+(c->offset&(BY2PG-1)), n); - kunmap(k); - } - return n; - } - - /* u area */ - if(c->offset>=USERADDR && c->offsetoffset+n > USERADDR+BY2PG) - n = USERADDR+BY2PG - c->offset; - pg = p->upage; - if(pg==0 || p->pid!=PID(c->qid)) - error(Eprocdied); - k = kmap(pg); - b = (char*)VA(k); - memcpy(a, b+(c->offset-USERADDR), n); - kunmap(k); - return n; - } - - /* kernel memory. BUG: shouldn't be so easygoing. BUG: mem mapping? */ - if(c->offset>=KZERO && c->offsetoffset+n > KZERO+conf.npage0*BY2PG) - n = KZERO+conf.npage0*BY2PG - c->offset; - memcpy(a, (char*)c->offset, n); - return n; - } - return 0; - break; - - case Qnote: - lock(&p->debug); - if(waserror()){ - unlock(&p->debug); - nexterror(); - } - if(p->pid != PID(c->qid)) - error(Eprocdied); - k = kmap(p->upage); - up = (User*)VA(k); - if(up->p != p){ - kunmap(k); - pprint("note read u/p mismatch"); - error(Egreg); - } - if(n < ERRLEN) - error(Etoosmall); - if(up->nnote == 0) - n = 0; - else{ - memcpy(va, up->note[0].msg, ERRLEN); - up->nnote--; - memcpy(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); - n = ERRLEN; - } - kunmap(k); - unlock(&p->debug); - return n; - - case Qproc: - if(c->offset >= sizeof(Proc)) - return 0; - if(c->offset+n > sizeof(Proc)) - n = sizeof(Proc) - c->offset; - memcpy(a, ((char*)p)+c->offset, n); - return n; - - case Qstatus: - if(c->offset >= sizeof statbuf) - return 0; - if(c->offset+n > sizeof statbuf) - n = sizeof statbuf - c->offset; - sprint(statbuf, "%-27s %-27s %-11s ", p->text, p->pgrp->user, statename[p->state]); - for(i=0; i<6; i++){ - l = p->time[i]; - if(i == TReal) - l = MACHP(0)->ticks - l; - l = TK2MS(l); - readnum(0, statbuf+2*NAMELEN+12+NUMSIZE*i, NUMSIZE, l, NUMSIZE); - } - memcpy(a, statbuf+c->offset, n); - return n; - } - error(Egreg); -} - - -long -procwrite(Chan *c, void *va, long n) -{ - Proc *p; - Pgrp *pg; - User *up; - KMap *k; - char buf[ERRLEN]; - - if(c->qid.path & CHDIR) - error(Eisdir); - - p = proctab(SLOT(c->qid)); - /* - * Special case: don't worry about process, just use remembered group - */ - if(QID(c->qid) == Qnotepg){ - pg = pgrptab(c->pgrpid.path-1); - lock(&pg->debug); - if(waserror()){ - unlock(&pg->debug); - nexterror(); - } - if(pg->pgrpid != c->pgrpid.vers){ - unlock(&pg->debug); - goto Died; - } - pgrpnote(pg, va, n, NUser); - unlock(&pg->debug); - return n; - } - - lock(&p->debug); - if(waserror()){ - unlock(&p->debug); - nexterror(); - } - if(p->pid != PID(c->qid)) - Died: - error(Eprocdied); - - switch(QID(c->qid)){ - case Qctl: - if(p->state==Broken && n>=4 && strncmp(va, "exit", 4)==0) - ready(p); - else - error(Ebadctl); - break; - case Qnote: - k = kmap(p->upage); - up = (User*)VA(k); - if(up->p != p){ - kunmap(k); - pprint("note write u/p mismatch"); - error(Egreg); - } - kunmap(k); - if(n >= ERRLEN-1) - error(Etoobig); - if(n>=4 && strncmp(va, "sys:", 4)==0) - error(Ebadarg); - memcpy(buf, va, n); - buf[n] = 0; - if(!postnote(p, 0, buf, NUser)) - error(Enonote); - break; - default: - pprint("unknown qid in procwrite\n"); - error(Egreg); - } - unlock(&p->debug); - return n; -} diff --git a/gnot/devroot.c b/gnot/devroot.c deleted file mode 100644 index 7d3ff28c191fef934b926d05e75c548a2b31f356..0000000000000000000000000000000000000000 --- a/gnot/devroot.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" -#include "devtab.h" - -enum{ - Qdir, - Qbin, - Qboot, - Qdev, - Qenv, - Qproc, -}; - -Dirtab rootdir[]={ - "bin", {Qbin|CHDIR}, 0, 0700, - "boot", {Qboot}, 0, 0700, - "dev", {Qdev|CHDIR}, 0, 0700, - "env", {Qenv|CHDIR}, 0, 0700, - "proc", {Qproc|CHDIR}, 0, 0700, -}; - -#define NROOT (sizeof rootdir/sizeof(Dirtab)) - -void -rootreset(void) -{ -} - -void -rootinit(void) -{ -} - -Chan* -rootattach(char *spec) -{ - return devattach('/', spec); -} - -Chan* -rootclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -rootwalk(Chan *c, char *name) -{ - return devwalk(c, name, rootdir, NROOT, devgen); -} - -void -rootstat(Chan *c, char *dp) -{ - devstat(c, dp, rootdir, NROOT, devgen); -} - -Chan* -rootopen(Chan *c, int omode) -{ - return devopen(c, omode, rootdir, NROOT, devgen); -} - -void -rootcreate(Chan *c, char *name, int omode, ulong perm) -{ - error(Eperm); -} - -/* - * sysremove() knows this is a nop - */ -void -rootclose(Chan *c) -{ -} - -#include "boot.h" - -long -rootread(Chan *c, void *buf, long n) -{ - - switch(c->qid.path & ~CHDIR){ - case Qdir: - return devdirread(c, buf, n, rootdir, NROOT, devgen); - - case Qboot: /* boot */ - if(c->offset >= sizeof bootcode) - return 0; - if(c->offset+n > sizeof bootcode) - n = sizeof bootcode - c->offset; - memcpy(buf, ((char*)bootcode)+c->offset, n); - return n; - - case Qdev: - return 0; - } - error(Egreg); - return 0; -} - -long -rootwrite(Chan *c, void *buf, long n) -{ - error(Egreg); -} - -void -rootremove(Chan *c) -{ - error(Eperm); -} - -void -rootwstat(Chan *c, char *dp) -{ - error(Eperm); -} diff --git a/gnot/devsrv.c b/gnot/devsrv.c deleted file mode 100644 index 2cdbc3c9e39cb968291c30e7f245c121ac549ffe..0000000000000000000000000000000000000000 --- a/gnot/devsrv.c +++ /dev/null @@ -1,287 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" -#include "devtab.h" -#include "fcall.h" - -void *calloc(unsigned, unsigned); -void free(void *); - -/* This structure holds the contents of a directory entry. Entries are kept - * in a linked list. - */ -typedef struct Entry Entry; -struct Entry { - Lock; - Entry *next; /* next entry */ - Entry **back; /* entry pointer */ - Entry *parent; /* parent directory */ - Dir dir; /* dir structure */ - union{ - Chan *chan; /* if not a subdirectory */ - Entry *entries; /* directory entries */ - }; -}; - -void -srvinit(void) -{ -} - -void -srvreset(void) -{ -} - -Entry * -srvalloc(int mode){ - Entry *e; - static Lock qidlock; - static nextqid; - - e = calloc(1, sizeof(Entry)); - e->dir.atime = e->dir.mtime = seconds(); - lock(&qidlock); /* for qid allocation */ - e->dir.qid = (Qid){mode|nextqid++, 0}; - unlock(&qidlock); - return e; -} - -Chan * -srvattach(char *spec) -{ - Chan *c; - static Lock rootlock; - static Entry *root; - - lock(&rootlock); - if(root==0){ - root = srvalloc(CHDIR); - root->dir.mode = CHDIR | 0777; - } - unlock(&rootlock); - c = devattach('s', spec); - c->qid = root->dir.qid; - c->aux = root; - return c; -} - -Chan * -srvclone(Chan *c, Chan *nc) -{ - nc = devclone(c, nc); - nc->aux = c->aux; - return nc; -} - -int -srvwalk(Chan *c, char *name) -{ - Entry *dir, *e; - - isdir(c); - if(strcmp(name, ".") == 0) - return 1; - if((dir=c->aux) == 0) - panic("bad aux pointer in srvwalk"); - if(strcmp(name, "..") == 0) - e = dir->parent; - else{ - lock(dir); - for(e=dir->entries; e; e=e->next) - if (strcmp(name, e->dir.name) == 0) - break; - unlock(dir); - } - if(e==0){ - strncpy(u->error, errstrtab[Enonexist], NAMELEN); - return 0; - } - c->qid = e->dir.qid; - c->aux = e; - return 1; -} - -void -srvstat(Chan *c, char *db) -{ - Entry *e; - - e = c->aux; - convD2M(&e->dir, db); -} - -Chan * -srvopen(Chan *c, int omode) -{ - Entry *e; - Chan *f; - - if(c->qid.path & CHDIR){ - if(omode != OREAD) - error(Eisdir); - c->mode = omode; - c->flag |= COPEN; - c->offset = 0; - return c; - } - if((e=c->aux) == 0) - error(Egreg); - if((f=e->chan) == 0) - error(Eshutdown); - if(omode & OTRUNC) - error(Eperm); - if(omode!=f->mode && f->mode!=ORDWR) - error(Eperm); - close(c); - incref(f); - return f; -} - -void -srvcreate(Chan *c, char *name, int omode, ulong perm) -{ - Entry *parent, *e; - - parent = c->aux; - isdir(c); - lock(parent); - if (waserror()){ - unlock(parent); - nexterror(); - } - for(e=parent->entries; e; e=e->next) - if(strcmp(name, e->dir.name) == 0) - error(Einuse); - e = srvalloc(perm & CHDIR); - e->parent = parent; - strcpy(e->dir.name, name); - e->dir.mode = perm & parent->dir.mode; - strcpy(e->dir.gid, parent->dir.gid); - if(e->next = parent->entries) /* assign = */ - e->next->back = &e->next; - e->back = &parent->entries; - *e->back = e; - parent->dir.mtime = e->dir.mtime; - unlock(parent); - poperror(); - c->qid = e->dir.qid; - c->aux = e; - c->flag |= COPEN; - c->mode = omode; -} - -void -srvremove(Chan *c) -{ - Entry *e; - - e = c->aux; - if(e->parent == 0) - error(Eperm); - lock(e->parent); - if(waserror()){ - unlock(e->parent); - nexterror(); - } - if(e->dir.mode & CHDIR){ - if (e->entries != 0) - error(Eperm); - }else{ - if(e->chan == 0) - error(Eshutdown); - close(e->chan); - } - if(*e->back = e->next) /* assign = */ - e->next->back = e->back; - unlock(e->parent); - poperror(); - free(e); -} - -void -srvwstat(Chan *c, char *dp) -{ - error(Egreg); -} - -void -srvclose(Chan *c) -{ -} - -/* A directory is being read. The entries must be synthesized. e points - * to a list of entries in this directory. Count is the size to be - * read. - */ -int -srvdirentry(Entry *e, char *a, long count){ - Dir dir; - int n; - - n = 0; - while(n!=count && e!=0){ - n += convD2M(&e->dir, a + n); - e = e->next; - } - return n; -} - -long -srvread(Chan *c, void *va, long n) -{ - Entry *dir, *e; - int offset; - - dir = c->aux; - offset = c->offset; - isdir(c); - if(n <= 0) - return 0; - if(offset%DIRLEN || n%DIRLEN) - error(Ebaddirread); - lock(dir); - for(e=dir->entries; e; e=e->next) - if(offset <= 0){ - n = srvdirentry(e, va, n); - unlock(dir); - c->offset += n; - return n; - }else - offset -= DIRLEN; - unlock(dir); - return 0; -} - -long -srvwrite(Chan *c, void *va, long n) -{ - Entry *e; - int i, fd; - char buf[32]; - - e = c->aux; - if(e->dir.mode & CHDIR) - panic("write to directory"); - lock(e); - if(waserror()){ - unlock(e); - nexterror(); - } - if(e->chan) - error(Egreg); - if(n >= sizeof buf) - error(Egreg); - memcpy(buf, va, n); /* so we can NUL-terminate */ - buf[n] = 0; - fd = strtoul(buf, 0, 0); - fdtochan(fd, -1); /* error check only */ - e->chan = u->fd[fd]; - incref(e->chan); - unlock(e); - poperror(); - return n; -} diff --git a/gnot/fcall.c b/gnot/fcall.c deleted file mode 100644 index 257311c7779844e8f2a8bc87a6a800e03995420d..0000000000000000000000000000000000000000 --- a/gnot/fcall.c +++ /dev/null @@ -1,382 +0,0 @@ -#include -#include -#include - -#define CHAR(x) *p++ = f->x -#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 -#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4 -#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\ - p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8 -#define STRING(x,n) memcpy(p, f->x, n); p += n - -int -convS2M(Fcall *f, char *ap) -{ - uchar *p; - - p = (uchar*)ap; - CHAR(type); - SHORT(tag); - switch(f->type) - { - default: - print("fcall: bad type: %d\n", f->type); - return 0; - - case Tnop: - break; - - case Tsession: - break; - - case Tflush: - SHORT(oldtag); - break; - - case Tattach: - SHORT(fid); - STRING(uname, sizeof(f->uname)); - STRING(aname, sizeof(f->aname)); - STRING(auth, sizeof(f->auth)); - break; - - case Tclone: - SHORT(fid); - SHORT(newfid); - break; - - case Twalk: - SHORT(fid); - STRING(name, sizeof(f->name)); - break; - - case Topen: - SHORT(fid); - CHAR(mode); - break; - - case Tcreate: - SHORT(fid); - STRING(name, sizeof(f->name)); - LONG(perm); - CHAR(mode); - break; - - case Tread: - SHORT(fid); - VLONG(offset); - SHORT(count); - break; - - case Twrite: - SHORT(fid); - VLONG(offset); - SHORT(count); - p++; /* pad(1) */ - STRING(data, f->count); - break; - - case Tclunk: - SHORT(fid); - break; - - case Tremove: - SHORT(fid); - break; - - case Tstat: - SHORT(fid); - break; - - case Twstat: - SHORT(fid); - STRING(stat, sizeof(f->stat)); - break; -/* - */ - case Rnop: - break; - - case Rsession: - break; - - case Rerror: - STRING(ename, sizeof(f->ename)); - break; - - case Rflush: - break; - - case Rattach: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rclone: - SHORT(fid); - break; - - case Rwalk: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Ropen: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rcreate: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rread: - SHORT(fid); - SHORT(count); - p++; /* pad(1) */ - STRING(data, f->count); - break; - - case Rwrite: - SHORT(fid); - SHORT(count); - break; - - case Rclunk: - SHORT(fid); - break; - - case Rremove: - SHORT(fid); - break; - - case Rstat: - SHORT(fid); - STRING(stat, sizeof(f->stat)); - break; - - case Rwstat: - SHORT(fid); - break; - } - return p - (uchar*)ap; -} - -int -convD2M(Dir *f, char *ap) -{ - uchar *p; - - p = (uchar*)ap; - STRING(name, sizeof(f->name)); - STRING(uid, sizeof(f->uid)); - STRING(gid, sizeof(f->gid)); - LONG(qid.path); - LONG(qid.vers); - LONG(mode); - LONG(atime); - LONG(mtime); - VLONG(length); - SHORT(type); - SHORT(dev); - return p - (uchar*)ap; -} - -#undef CHAR -#undef SHORT -#undef LONG -#undef VLONG -#undef STRING - -#define CHAR(x) f->x = *p++ -#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 -#define LONG(x) f->x = (p[0] | (p[1]<<8) |\ - (p[2]<<16) | (p[3]<<24)); p += 4 -#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\ - (p[2]<<16) | (p[3]<<24)); p += 8 -#define STRING(x,n) memcpy(f->x, p, n); p += n - -int -convM2S(char *ap, Fcall *f, int n) -{ - uchar *p; - - p = (uchar*)ap; - CHAR(type); - SHORT(tag); - switch(f->type) - { - default: - print("fcall: bad type: %d\n", f->type); - return 0; - - case Tnop: - break; - - case Tsession: - break; - - case Tflush: - SHORT(oldtag); - break; - - case Tattach: - SHORT(fid); - STRING(uname, sizeof(f->uname)); - STRING(aname, sizeof(f->aname)); - STRING(auth, sizeof(f->auth)); - break; - - case Tclone: - SHORT(fid); - SHORT(newfid); - break; - - case Twalk: - SHORT(fid); - STRING(name, sizeof(f->name)); - break; - - case Topen: - SHORT(fid); - CHAR(mode); - break; - - case Tcreate: - SHORT(fid); - STRING(name, sizeof(f->name)); - LONG(perm); - CHAR(mode); - break; - - case Tread: - SHORT(fid); - VLONG(offset); - SHORT(count); - break; - - case Twrite: - SHORT(fid); - VLONG(offset); - SHORT(count); - p++; /* pad(1) */ - f->data = (char*)p; p += f->count; - break; - - case Tclunk: - SHORT(fid); - break; - - case Tremove: - SHORT(fid); - break; - - case Tstat: - SHORT(fid); - break; - - case Twstat: - SHORT(fid); - STRING(stat, sizeof(f->stat)); - break; -/* - */ - case Rnop: - break; - - case Rsession: - break; - - case Rerror: - STRING(ename, sizeof(f->ename)); - break; - - case Rflush: - break; - - case Rattach: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rclone: - SHORT(fid); - break; - - case Rwalk: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Ropen: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rcreate: - SHORT(fid); - LONG(qid.path); - LONG(qid.vers); - break; - - case Rread: - SHORT(fid); - SHORT(count); - p++; /* pad(1) */ - f->data = (char*)p; p += f->count; - break; - - case Rwrite: - SHORT(fid); - SHORT(count); - break; - - case Rclunk: - SHORT(fid); - break; - - case Rremove: - SHORT(fid); - break; - - case Rstat: - SHORT(fid); - STRING(stat, sizeof(f->stat)); - break; - - case Rwstat: - SHORT(fid); - break; - } - if((uchar*)ap+n == p) - return n; - return 0; -} - -int -convM2D(char *ap, Dir *f) -{ - uchar *p; - - p = (uchar*)ap; - STRING(name, sizeof(f->name)); - STRING(uid, sizeof(f->uid)); - STRING(gid, sizeof(f->gid)); - LONG(qid.path); - LONG(qid.vers); - LONG(mode); - LONG(atime); - LONG(mtime); - VLONG(length); - SHORT(type); - SHORT(dev); - return p - (uchar*)ap; -} diff --git a/gnot/pgrp.c b/gnot/pgrp.c deleted file mode 100644 index 3f397c08f29a2728ca1b44d6620a9df38d4f1626..0000000000000000000000000000000000000000 --- a/gnot/pgrp.c +++ /dev/null @@ -1,236 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -struct{ - Lock; - Pgrp *arena; - Pgrp *free; - ulong pgrpid; -}pgrpalloc; - -struct{ - Lock; - Mount *free; - ulong mountid; -}mountalloc; - -void -pgrpinit(void) -{ - int i; - Pgrp *p; - Mount *m; - - pgrpalloc.arena = ialloc(conf.npgrp*sizeof(Pgrp), 0); - pgrpalloc.free = pgrpalloc.arena; - - p = pgrpalloc.free; - for(i=0; iindex = i; - p->next = p+1; - p->mtab = ialloc(conf.nmtab*sizeof(Mtab), 0); - p->etab = ialloc(conf.npgenv*sizeof(Envp*), 0); - } - p[-1].next = 0; - - mountalloc.free = ialloc(conf.nmount*sizeof(Mount), 0); - - m = mountalloc.free; - for(i=0; inext = m+1; - m->next = 0; -} - -Pgrp* -pgrptab(int i) -{ - return &pgrpalloc.arena[i]; -} - -void -pgrpnote(Pgrp *pg, char *a, long n, int flag) -{ - int i; - Proc *p; - char buf[ERRLEN]; - - if(n >= ERRLEN-1) - error(Etoobig); - if(n>=4 && strncmp(a, "sys:", 4)==0) - error(Ebadarg); - memcpy(buf, a, n); - buf[n] = 0; - p = proctab(0); - for(i=0; ipgrp == pg){ - lock(&p->debug); - if(p->pid==0 || p->pgrp!=pg){ - unlock(&p->debug); - continue; - } - if(waserror()){ - unlock(&p->debug); - continue; - } - postnote(p, 0, buf, flag); - unlock(&p->debug); - } - } -} - -Pgrp* -newpgrp(void) -{ - Pgrp *p; - -loop: - lock(&pgrpalloc); - if(p = pgrpalloc.free){ /* assign = */ - pgrpalloc.free = p->next; - p->ref = 1; - p->pgrpid = ++pgrpalloc.pgrpid; - p->nmtab = 0; - p->nenv = 0; - unlock(&pgrpalloc); - return p; - } - unlock(&pgrpalloc); - print("no pgrps\n"); - if(u == 0) - panic("newpgrp"); - u->p->state = Wakeme; - alarm(1000, wakeme, u->p); - sched(); - goto loop; -} - -void -closepgrp(Pgrp *p) -{ - int i; - Mtab *m; - Envp *ep; - - if(decref(p) == 0){ - lock(&p->debug); - p->pgrpid = -1; - m = p->mtab; - for(i=0; inmtab; i++,m++) - if(m->c){ - close(m->c); - closemount(m->mnt); - } - ep = p->etab; - for(i=0; inenv; i++,ep++) - if(ep->env) - envpgclose(ep->env); - lock(&pgrpalloc); - p->next = pgrpalloc.free; - pgrpalloc.free = p; - unlock(&p->debug); - unlock(&pgrpalloc); - } -} - -Mount* -newmount(void) -{ - Mount *m; - -loop: - lock(&mountalloc); - if(m = mountalloc.free){ /* assign = */ - mountalloc.free = m->next; - m->ref = 1; - m->next = 0; - m->mountid = ++mountalloc.mountid; - unlock(&mountalloc); - return m; - } - unlock(&mountalloc); - print("no mounts\n"); - if(u == 0) - panic("newmount"); - u->p->state = Wakeme; - alarm(1000, wakeme, u->p); - sched(); - goto loop; -} - -void -closemount(Mount *m) -{ - lock(m); - if(m->ref == 1){ - if(m->c) - close(m->c); - if(m->next) - closemount(m->next); - unlock(m); - lock(&mountalloc); - m->mountid = 0; - m->next = mountalloc.free; - mountalloc.free = m; - unlock(&mountalloc); - return; - } - m->ref--; - unlock(m); -} - -void -pgrpcpy(Pgrp *to, Pgrp *from) -{ - int i; - Mtab *m; - Envp *ep; - Env *e; - - lock(from); - memcpy(to->user, from->user, NAMELEN); - memcpy(to->mtab, from->mtab, from->nmtab*sizeof(Mtab)); - to->nmtab = from->nmtab; - m = to->mtab; - for(i=0; inmtab; i++,m++) - if(m->c){ - incref(m->c); - lock(m->mnt); - m->mnt->ref++; - unlock(m->mnt); - } - - to->nenv = from->nenv; - ep = to->etab; - for(i=0; inenv; i++,ep++){ - ep->chref = 0; - e = ep->env = from->etab[i].env; - if(e){ - lock(e); - if(waserror()){ - unlock(e); - unlock(from); - ep->env = 0; - nexterror(); - } - /* - * If pgrp being forked has an open channel - * on this env, it may write it after the fork - * so make a copy now. - * Don't worry about other pgrps, because they - * will copy if they are about to write. - */ - if(from->etab[i].chref){ - ep->env = copyenv(e, 0); - unlock(ep->env); - }else - e->pgref++; - poperror(); - unlock(e); - } - } - unlock(from); -} diff --git a/gnot/print.c b/gnot/print.c deleted file mode 100644 index ba3f95e4fb09f1a7aeac9a0c59273483b8d76682..0000000000000000000000000000000000000000 --- a/gnot/print.c +++ /dev/null @@ -1,287 +0,0 @@ -#include "u.h" -#include "lib.h" - -#define PTR sizeof(char*) -#define SHORT sizeof(int) -#define INT sizeof(int) -#define LONG sizeof(long) -#define IDIGIT 30 -#define MAXCON 30 - -static int convcount = { 10 }; - -#define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c - -static int noconv(Op*); -static int cconv(Op*); -static int dconv(Op*); -static int hconv(Op*); -static int lconv(Op*); -static int oconv(Op*); -static int sconv(Op*); -static int uconv(Op*); -static int xconv(Op*); -static int percent(Op*); - -static -int (*fmtconv[MAXCON])(Op*) = -{ - noconv, - cconv, dconv, hconv, lconv, - oconv, sconv, uconv, xconv, - percent, -}; -static -char fmtindex[128] = -{ - ['c'] 1, - ['d'] 2, - ['h'] 3, - ['l'] 4, - ['o'] 5, - ['s'] 6, - ['u'] 7, - ['x'] 8, - ['%'] 9, -}; - -int -fmtinstall(char c, int (*f)(Op*)) -{ - - c &= 0177; - if(fmtindex[c] == 0) { - if(convcount >= MAXCON) - return 1; - fmtindex[c] = convcount++; - } - fmtconv[fmtindex[c]] = f; - return 0; -} - -char* -doprint(char *p, char *ep, char *fmt, void *argp) -{ - int sf1, c; - Op o; - - o.p = p; - o.ep = ep; - o.argp = argp; - -loop: - c = *fmt++; - if(c != '%') { - if(c == 0) { - if(o.p < o.ep) - *o.p = 0; - return o.p; - } - PUT(&o, c); - goto loop; - } - o.f1 = 0; - o.f2 = -1; - o.f3 = 0; - c = *fmt++; - sf1 = 0; - if(c == '-') { - sf1 = 1; - c = *fmt++; - } - while(c >= '0' && c <= '9') { - o.f1 = o.f1*10 + c-'0'; - c = *fmt++; - } - if(sf1) - o.f1 = -o.f1; - if(c != '.') - goto l1; - c = *fmt++; - while(c >= '0' && c <= '9') { - if(o.f2 < 0) - o.f2 = 0; - o.f2 = o.f2*10 + c-'0'; - c = *fmt++; - } -l1: - if(c == 0) - fmt--; - c = (*fmtconv[fmtindex[c&0177]])(&o); - if(c < 0) { - o.f3 |= -c; - c = *fmt++; - goto l1; - } - o.argp = (char*)o.argp + c; - goto loop; -} - -int -numbconv(Op *op, int base) -{ - char b[IDIGIT]; - int i, f, n, r; - long v; - short h; - - f = 0; - switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { - case FLONG: - v = *(long*)op->argp; - r = LONG; - break; - - case FUNSIGN|FLONG: - v = *(unsigned long*)op->argp; - r = LONG; - break; - - case FSHORT: - h = *(int*)op->argp; - v = h; - r = SHORT; - break; - - case FUNSIGN|FSHORT: - h = *(int*)op->argp; - v = (unsigned short)h; - r = SHORT; - break; - - default: - v = *(int*)op->argp; - r = INT; - break; - - case FUNSIGN: - v = *(unsigned*)op->argp; - r = INT; - break; - } - if(!(op->f3 & FUNSIGN) && v < 0) { - v = -v; - f = 1; - } - b[IDIGIT-1] = 0; - for(i = IDIGIT-2;; i--) { - n = (unsigned long)v % base; - n += '0'; - if(n > '9') - n += 'a' - ('9'+1); - b[i] = n; - if(i < 2) - break; - v = (unsigned long)v / base; - if(op->f2 >= 0 && i >= IDIGIT-op->f2) - continue; - if(v <= 0) - break; - } -sout: - if(f) - b[--i] = '-'; - strconv(b+i, op, op->f1, -1); - return r; -} - -void -strconv(char *o, Op *op, int f1, int f2) -{ - int n, c; - char *p; - - n = strlen(o); - if(f1 >= 0) - while(n < f1) { - PUT(op, ' '); - n++; - } - for(p=o; c = *p++;) - if(f2 != 0) { - PUT(op, c); - f2--; - } - if(f1 < 0) { - f1 = -f1; - while(n < f1) { - PUT(op, ' '); - n++; - } - } -} - -static int -noconv(Op *op) -{ - - strconv("***", op, 0, -1); - return 0; -} - -static int -cconv(Op *op) -{ - char b[2]; - - b[0] = *(int*)op->argp; - b[1] = 0; - strconv(b, op, op->f1, -1); - return INT; -} - -static int -dconv(Op *op) -{ - - return numbconv(op, 10); -} - -static int -hconv(Op *op) -{ - return -FSHORT; -} - -static int -lconv(Op *op) -{ - - return -FLONG; -} - -static int -oconv(Op *op) -{ - - return numbconv(op, 8); -} - -static int -sconv(Op *op) -{ - - strconv(*(char**)op->argp, op, op->f1, op->f2); - return PTR; -} - -static int -uconv(Op *op) -{ - return -FUNSIGN; -} - -static int -xconv(Op *op) -{ - - return numbconv(op, 16); -} - -static int -percent(Op *op) -{ - - PUT(op, '%'); - return 0; -} diff --git a/gnot/stasync.c b/gnot/stasync.c deleted file mode 100644 index 542ac8a57d487e514476d4685eb77b65a60e5360..0000000000000000000000000000000000000000 --- a/gnot/stasync.c +++ /dev/null @@ -1,461 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" - -#define DPRINT if(asyncdebug)kprint - -/* - * configuration - */ -enum { - MAXFRAME= 256, /* also known to tsm8 code */ -}; - -/* input states */ -enum { Hunt=0, Framing, Framed, Data, Escape }; - -typedef struct Async { - QLock; - - int inuse; - Queue *wq; - - /* output state */ - - QLock xmit; /* transmit lock */ - int chan; /* current urp channel */ - Block *bp; /* current output buffer */ - int count; - ushort crc; - - /* input state */ - - int state; /* input state */ - uchar buf[MAXFRAME]; /* current input buffer */ - int icount; - ushort icrc; - - /* statistics */ - - ulong chan0; - ulong toolong; - ulong tooshort; - ulong badcrc; - ulong badescape; - ulong in; /* bytes in */ - ulong out; /* bytes out */ -} Async; - -Async *async; - -/* - * async stream module definition - */ -static void asynciput(Queue*, Block*); -static void asyncoput(Queue*, Block*); -static void asyncopen(Queue*, Stream*); -static void asyncclose(Queue*); -static void asyncreset(void); -Qinfo asyncinfo = -{ - asynciput, - asyncoput, - asyncopen, - asyncclose, - "async", - asyncreset -}; - -int asyncdebug = 0; -int asyncerror; - -static ushort crc_table[256] = { -#include "crc_16.h" -}; - -#define BOT 0050 /* begin trailer */ -#define BOTM 0051 /* begin trailer, more data follows */ -#define BOTS 0052 /* seq update alg. on this trailer */ - -#define FRAME 0x7e -#define STUF 0x9d - -#define CRCSTART (crc_table[0xff]) -#define CRCFUNC(crc,x) (crc_table[((crc)^(x))&0xff]^((crc)>>8)) - -/* - * create the async structures - */ -static void -asyncreset(void) -{ - async = (Async *)ialloc(conf.nasync*sizeof(Async), 0); -} - -/* - * allocate an async structure - */ -static void -asyncopen(Queue *q, Stream *s) -{ - Async *ap; - - DPRINT("asyncopen %d\n", s->dev); - - for(ap = async; ap < &async[conf.nasync]; ap++){ - qlock(ap); - if(ap->inuse == 0) - break; - qunlock(ap); - } - if(ap == &async[conf.nasync]) - error(Enoasync); - q->ptr = q->other->ptr = ap; - - ap->inuse = 1; - ap->bp = 0; - ap->chan = -1; - ap->count = 0; - ap->toolong = 0; - ap->tooshort = 0; - ap->badcrc = 0; - ap->badescape = 0; - ap->chan0 = 0; - ap->in = 0; - ap->out = 0; - ap->wq = WR(q); - ap->state = Hunt; - qunlock(ap); -} - -static void -asyncclose(Queue * q) -{ - Async *ap = (Async *)q->ptr; - - DPRINT("asyncstclose %d\n", ap-async); - qlock(ap); - ap->inuse = 0; - qunlock(ap); -} - -/* - * free all blocks of a message in `q', `bp' is the first block - * of the message - */ -static void -freemsg(Queue *q, Block *bp) -{ - for(; bp; bp = getq(q)){ - if(bp->flags & S_DELIM){ - freeb(bp); - return; - } - freeb(bp); - } -} - -static void -showframe(char *t, Async *ap, uchar *buf, int n) -{ - kprint("a%d %s [", ap-async, t); - while (--n >= 0) - kprint(" %2.2ux", *buf++); - kprint(" ]\n"); -} - -void -aswrite(Async *ap) -{ - if(ap->bp->rptr == ap->bp->wptr) - return; - FLOWCTL(ap->wq); - PUTNEXT(ap->wq, ap->bp); - ap->bp = 0; -} - -void -asputf(Async *ap, int frame) -{ - uchar *p; - int c; - - p = ap->bp->wptr; - if(ap->count > 0) { - if(asyncerror) - ap->crc^=1, asyncerror=0; - *p++ = c = ap->crc&0xff; - if(c == FRAME) - *p++ = 0x00; - *p++ = c = (ap->crc>>8)&0xff; - if(c == FRAME) - *p++ = 0x00; - ap->count = 0; - } - if(frame) { - *p++ = FRAME; - *p++ = FRAME; - } - ap->bp->wptr = p; - if(asyncdebug > 2) - showframe("out", ap, ap->bp->rptr, BLEN(ap->bp)); - aswrite(ap); -} - -void -asputc(Async *ap, int c) -{ - int d; - uchar *p; - - if(ap->bp == 0) - ap->bp = allocb(MAXFRAME+4); - p = ap->bp->wptr; - if(ap->count <= 0) { - *p++ = FRAME; - *p++ = FRAME; - *p++ = d = 0x80|((ap->chan>>5)&0x7e); - ap->crc = CRCFUNC(CRCSTART, d); - *p++ = d = 0x80|((ap->chan<<1)&0x7e); - ap->crc = CRCFUNC(ap->crc, d); - } - *p++ = c; - if(c == FRAME) - *p++ = 0x00; - ap->crc = CRCFUNC(ap->crc, c); - ap->bp->wptr = p; - if(++ap->count >= MAXFRAME-4) - asputf(ap, 0); - else if(ap->bp->lim - p < 8) - aswrite(ap); -} - -/* - * output a block - * - * the first 2 bytes of every message are the channel number, - * low order byte first. the third is a possible trailing control - * character. - */ -void -asyncoput(Queue *q, Block *bp) -{ - Async *ap = (Async *)q->ptr; - int c, chan, ctl; - - if(bp->type != M_DATA){ - freeb(bp); - return; - } - - /* - * get a whole message before handing bytes to the device - */ - if(!putq(q, bp)) - return; - - /* - * one transmitter at a time - */ - qlock(&ap->xmit); - - /* - * parse message - */ - bp = getq(q); - if(bp->wptr - bp->rptr < 3){ - freemsg(q, bp); - qunlock(&ap->xmit); - return; - } - chan = bp->rptr[0] | (bp->rptr[1]<<8); - ctl = bp->rptr[2]; - bp->rptr += 3; - - /* - * new frame if the channel number has changed - */ - if(chan != ap->chan && ap->count > 0) - asputf(ap, 0); - ap->chan = chan; - - /* - * send the 8 bit data - */ - for(;;){ - /* - * put in next packet - */ - while (bp->rptr < bp->wptr) { - asputc(ap, c = *bp->rptr++); - if(c == STUF) - asputc(ap, 0); - } - - /* - * get next block - */ - if(bp->flags & S_DELIM){ - freeb(bp); - break; - } - freeb(bp); - bp = getq(q); - if(bp==0) - break; - } - - /* - * send the control byte if there is one - */ - if(ctl){ - asputc(ap, STUF); - asputc(ap, ctl); - switch (ctl) { - case BOT: - case BOTM: - case BOTS: - break; - default: - asputf(ap, 1); - } - } - - qunlock(&ap->xmit); - return; -} - -/* - * Read bytes from the raw input. - */ - -void -asdeliver(Queue *q, Async *ap) -{ - int chan, c; - Block *bp = 0; - uchar *p = ap->buf; - int n = ap->icount; - - chan = *p++ & 0x7e; - chan = (chan<<5)|((*p++ & 0x7e)>>1); - if(chan==0) { - DPRINT("a%d deliver chan 0\n", ap-async); - ap->chan0++; - return; - } - for (n-=4; n>0; n--) { - if(!bp) { - bp = allocb(n+2); - bp->flags |= S_DELIM; - bp->wptr[0] = chan; - bp->wptr[1] = chan>>8; - bp->wptr[2] = 0; - bp->wptr += 3; - } - if((c = *p++) == STUF) { - --n; - if((c = *p++) != 0) { - bp->rptr[2] = c; - if(asyncdebug > 1) - kprint("a%d<-(%d)%3.3uo %d\n", - ap-async, chan, bp->rptr[2], - bp->wptr - bp->rptr - 3); - PUTNEXT(q, bp); - bp = 0; - continue; - } else - c = STUF; - } - *bp->wptr++ = c; - } - if(bp) { - if(asyncdebug > 1) - kprint("a%d<-(%d)%3.3uo %d\n", - ap-async, chan, bp->rptr[2], - bp->wptr - bp->rptr - 3); - PUTNEXT(q, bp); - } -} - -static void -asynciput(Queue *q, Block *bp) -{ - int c; - Async *ap = q->ptr; - int state = ap->state; - - while(bp->wptr > bp->rptr){ - c = *bp->rptr++; - switch(state) { - case Hunt: /* wait for framing byte */ - if(c == FRAME) - state = Framing; - break; - - case Framing: /* saw 1 framing byte after Hunt */ - if(c == FRAME) - state = Framed; - else - state = Hunt; - break; - - case Framed: /* saw 2 or more framing bytes */ - if(c == FRAME) - break; - state = Data; - ap->icrc = CRCSTART; - ap->icount = 0; - goto Datachar; - - case Data: /* mid-frame */ - if(c == FRAME) { - state = Escape; - break; - } - Datachar: - if(ap->icount >= MAXFRAME) { - DPRINT("a%d pkt too long\n", ap-async); - ap->toolong++; - state = Hunt; - break; - } - ap->icrc = CRCFUNC(ap->icrc, c); - ap->buf[ap->icount++] = c; - break; - - case Escape: /* saw framing byte in Data */ - switch (c) { - case FRAME: - if(asyncdebug > 2) - showframe("in", ap, ap->buf, ap->icount); - if(ap->icount < 5) { - DPRINT("a%d pkt too short\n", ap-async); - ap->tooshort++; - } else if(ap->icrc != 0) { - DPRINT("a%d bad crc\n", ap-async); - ap->badcrc++; - } else { - asdeliver(q, ap); - } - state = Framed; - break; - case 0: - c = FRAME; - state = Data; - goto Datachar; - default: - DPRINT("a%d bad escape\n", ap-async); - ap->badescape++; - state = Hunt; - break; - } - break; - } - } - ap->state = state; - freeb(bp); -} diff --git a/gnot/stream.c b/gnot/stream.c deleted file mode 100644 index 00ce77f3cc80389fb5a59c967b339266de2fa9fc..0000000000000000000000000000000000000000 --- a/gnot/stream.c +++ /dev/null @@ -1,1344 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "errno.h" -#include "devtab.h" -#include "fcall.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; - -/* - * All stream structures are ialloc'd at boot time - */ -Stream *slist; -Queue *qlist; -static Lock garbagelock; - -/* - * The block classes. There are Nclass block sizes, each with its own free list. - * All are ialloced at qinit() time. - */ -typedef struct { - int size; - int lim; - int made; - Blist; - QLock; /* qlock for sleepers on r */ - Rendez r; /* sleep here waiting for blocks */ -} Bclass; -Bclass bclass[Nclass]={ - { 0 }, - { 68 }, - { 260 }, - { 4096 }, -}; - -#include "stream.h" - -/* - * 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) -{ - int class, i, n; - Bclass *bcp; - - /* - * allocate queues, streams - */ - slist = (Stream *)ialloc(conf.nstream * sizeof(Stream), 0); - qlist = (Queue *)ialloc(conf.nqueue * sizeof(Queue), 0); - - /* - * set limits on blocks - */ - n = conf.nblock; - for(class = 0; class < Nclass; class++){ - if(class < Nclass-1) - n = n/2; - bcp = &bclass[class]; - bcp->lim = n; - bcp->made = 0; - } - - /* - * make stream modules available - */ - streaminit0(); -} - -/* - * make known a stream module and call its initialization routine, if - * it has one. - */ -void -newqinfo(Qinfo *qi) -{ - qi->next = lds; - lds = qi; - if(qi->reset) - (*qi->reset)(); -} - -/* - * upgrade a block 0 block to another class (called with bcp qlocked) - */ -newblock(Bclass *bcp) -{ - Page *page; - int n; - Block *bp; - uchar *cp; - - if(bcp->made > bcp->lim) - return; - - if(bcp == bclass){ - /* - * create some level zero blocks and return - */ - page = newpage(1, 0, 0); - page->va = VA(kmap(page)); - n = BY2PG/sizeof(Block); - bp = (Block *)(page->va); - while(n-- > 0){ - bp->flags = 0; - bp->base = bp->lim = bp->rptr = bp->wptr = 0; - if(bcp->first) - bcp->last->next = bp; - else - bcp->first = bp; - bcp->last = bp; - bcp->made++; - bp++; - } - } else { - /* - * create a page worth of new blocks - */ - page = newpage(1, 0, 0); - page->va = VA(kmap(page)); - n = BY2PG/bcp->size; - cp = (uchar *)(page->va); - - while(n-- > 0){ - /* - * upgrade a level 0 block - */ - bp = allocb(0); - qlock(bclass); - bclass->made--; - bcp->made++; - bp->flags = bcp - bclass; - qunlock(bclass); - - /* - * tack on the data area - */ - bp->base = bp->rptr = bp->wptr = cp; - cp += bcp->size; - bp->lim = cp; - if(bcp->first) - bcp->last->next = bp; - else - bcp->first = bp; - bcp->last = bp; - } - } - return; -} - -/* - * allocate a block - */ -static int -isblock(void *arg) -{ - Bclass *bcp; - - bcp = (Bclass *)arg; - return bcp->first!=0; -} -Block * -allocb(ulong size) -{ - Block *bp; - Bclass *bcp; - - /* - * map size to class - */ - for(bcp=bclass; bcp->sizefirst == 0){ - if(newblock(bcp) == 0) - continue; - unlock(bcp); - qlock(bcp); - if(waserror()){ - qunlock(bcp); - nexterror(); - } - tsleep(&bcp->r, isblock, (void *)bcp, 250); - qunlock(bcp); - poperror(); - lock(bcp); - } - bp = bcp->first; - bcp->first = bp->next; - if(bcp->first == 0) - bcp->last = 0; - unlock(bcp); - - /* - * return an empty block - */ - bp->rptr = bp->wptr = bp->base; - bp->next = 0; - bp->type = M_DATA; - bp->flags &= S_CLASS; - return bp; -} - -/* - * Free a block (or list of blocks). Poison its pointers so that - * someone trying to access it after freeing will cause a dump. - */ -void -freeb(Block *bp) -{ - Bclass *bcp; - int tries; - - if((bp->flags&S_CLASS) >= Nclass) - panic("freeb class"); - bcp = &bclass[bp->flags & S_CLASS]; - lock(bcp); - bp->rptr = bp->wptr = 0; - if(bcp->first) - bcp->last->next = bp; - else - bcp->first = bp; - tries = 0; - while(bp->next){ - if(++tries > 10){ - dumpstack(); - panic("freeb"); - } - bp = bp->next; - } - bcp->last = bp; - unlock(bcp); - if(bcp->r.p) - wakeup(&bcp->r); -} - -/* - * pad a block to the front with n bytes - */ -Block * -padb(Block *bp, int n) -{ - Block *nbp; - - if(bp->base && bp->rptr-bp->base>=n){ - bp->rptr -= n; - return bp; - } else { - nbp = allocb(n); - nbp->wptr = nbp->lim; - nbp->rptr = nbp->wptr - n; - nbp->next = bp; - return nbp; - } -} - -/* - * allocate a pair of queues. flavor them with the requested put routines. - * the `QINUSE' flag on the read side is the only one used. - */ -static Queue * -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"); - error(Enoqueue); - } - - q->flag = QINUSE; - q->r.p = 0; - q->info = qi; - q->put = qi->iput; - q->len = q->nb = 0; - q->ptr = 0; - wq = q->other = q + 1; - - wq->flag = QINUSE; - wq->r.p = 0; - wq->info = qi; - wq->put = qi->oput; - wq->other = q; - wq->ptr = 0; - wq->len = wq->nb = 0; - - unlock(q); - - return q; -} - -/* - * flush a queue - */ -static void -flushq(Queue *q) -{ - Block *bp; - - q = RD(q); - while(bp = getq(q)) - freeb(bp); - q = WR(q); - while(bp = getq(q)) - freeb(bp); -} - -/* - * free a queue - */ -static void -freeq(Queue *q) -{ - Block *bp; - - q = RD(q); - while(bp = getq(q)) - freeb(bp); - q = WR(q); - while(bp = getq(q)) - freeb(bp); - RD(q)->flag = 0; -} - -/* - * push a queue onto a stream referenced by the proc side write q - */ -Queue * -pushq(Stream* s, Qinfo *qi) -{ - Queue *q; - Queue *nq; - - q = RD(s->procq); - - /* - * make the new queue - */ - nq = allocq(qi); - - /* - * push - */ - RD(nq)->next = q; - RD(WR(q)->next)->next = RD(nq); - WR(nq)->next = WR(q)->next; - WR(q)->next = WR(nq); - - if(qi->open) - (*qi->open)(RD(nq), s); - - return WR(nq)->next; -} - -/* - * pop off the top line discipline - */ -static void -popq(Stream *s) -{ - Queue *q; - - if(s->procq->next == WR(s->devq)) - error(Ebadld); - q = s->procq->next; - if(q->info->close) - (*q->info->close)(RD(q)); - s->procq->next = q->next; - RD(q->next)->next = RD(s->procq); - freeq(q); -} - -/* - * add a block (or list of blocks) to the end of a queue. return true - * if one of the blocks contained a delimiter. - */ -int -putq(Queue *q, Block *bp) -{ - int delim; - - delim = 0; - lock(q); - if(q->first) - q->last->next = bp; - else - q->first = bp; - q->len += BLEN(bp); - q->nb++; - delim = bp->flags & S_DELIM; - while(bp->next) { - bp = bp->next; - q->len += BLEN(bp); - q->nb++; - delim |= bp->flags & S_DELIM; - } - q->last = bp; - if(q->len >= Streamhi || q->nb >= Streambhi) - q->flag |= QHIWAT; - unlock(q); - return delim; -} -int -putb(Blist *q, Block *bp) -{ - int delim; - - delim = 0; - if(q->first) - q->last->next = bp; - else - q->first = bp; - q->len += BLEN(bp); - delim = bp->flags & S_DELIM; - while(bp->next) { - bp = bp->next; - q->len += BLEN(bp); - delim |= bp->flags & S_DELIM; - } - q->last = bp; - return delim; -} - -/* - * add a block to the start of a queue - */ -void -putbq(Blist *q, Block *bp) -{ - lock(q); - if(q->first) - bp->next = q->first; - else - q->last = bp; - q->first = bp; - q->len += BLEN(bp); - q->nb++; - unlock(q); -} - -/* - * remove the first block from a queue - */ -Block * -getq(Queue *q) -{ - Block *bp; - - lock(q); - bp = q->first; - if(bp) { - q->first = bp->next; - if(q->first == 0) - q->last = 0; - q->len -= BLEN(bp); - q->nb--; - if((q->flag&QHIWAT) && q->lennbother->next->other->r); - q->flag &= ~QHIWAT; - } - bp->next = 0; - } - unlock(q); - return bp; -} - -/* - * remove the first block from a list of blocks - */ -Block * -getb(Blist *q) -{ - Block *bp; - - 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) { - memcpy(bp->wptr, nbp->rptr, n); - bp->wptr += n; - nbp->rptr += n; - return bp; - } else { - memcpy(bp->wptr, nbp->rptr, i); - bp->wptr += i; - bp->next = nbp->next; - nbp->next = 0; - freeb(nbp); - } - } - freeb(bp); - return 0; -} - -/* - * 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) -{ - if(bp->type == M_HANGUP) - freeb(bp); - else { - freeb(bp); - error(Ehungup); - } -} - -/* - * find the info structure for line discipline 'name' - */ -static Qinfo * -qinfofind(char *name) -{ - Qinfo *qi; - - if(name == 0) - error(Ebadld); - for(qi = lds; qi; qi = qi->next) - if(strcmp(qi->name, name)==0) - return qi; - error(Ebadld); -} - -/* - * 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); -} - -/* - * 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; - return 1; - } - return 0; -} - -/* - * the per stream directory structure - */ -Dirtab streamdir[]={ - "data", {Sdataqid}, 0, 0600, - "ctl", {Sctlqid}, 0, 0600, -}; - -/* - * A stream device consists of the contents of streamdir plus - * any directory supplied by the actual device. - * - * values of s: - * 0 to ntab-1 apply to the auxiliary directory. - * ntab to ntab+Shighqid-Slowqid+1 apply to streamdir. - */ -int -streamgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) -{ - Proc *p; - char buf[NAMELEN]; - - if(s < ntab) - tab = &tab[s]; - else if(s < ntab + Shighqid - Slowqid + 1) - tab = &streamdir[s - ntab]; - else - return -1; - - devdir(c, (Qid){STREAMQID(STREAMID(c->qid.path),tab->qid.path), 0}, tab->name, tab->length, - tab->perm, dp); - return 1; -} - -/* - * create a new stream, if noopen is non-zero, don't increment the open count - */ -Stream * -streamnew(ushort type, ushort dev, ushort id, Qinfo *qi, int noopen) -{ - Stream *s; - Queue *q; - - /* - * find a free stream struct - */ - for(s = slist; s < &slist[conf.nstream]; s++) { - if(s->inuse == 0){ - if(canqlock(s)){ - if(s->inuse == 0) - break; - qunlock(s); - } - } - } - if(s == &slist[conf.nstream]){ - print("no more streams\n"); - error(Enostream); - } - if(waserror()){ - qunlock(s); - streamclose1(s); - nexterror(); - } - - /* - * identify the stream - */ - s->type = type; - s->dev = dev; - s->id = id; - - /* - * 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); - s->procq = WR(q); - q = allocq(qi); - s->devq = RD(q); - WR(s->procq)->next = WR(s->devq); - RD(s->procq)->next = 0; - RD(s->devq)->next = RD(s->procq); - WR(s->devq)->next = 0; - - if(qi->open) - (*qi->open)(RD(s->devq), s); - - qunlock(s); - poperror(); - return s; -} - -/* - * (Re)open a stream. If this is the first open, create a stream. - */ -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. - */ -int -streamenter(Stream *s) -{ - qlock(s); - if(s->opens == 0){ - qunlock(s); - return -1; - } - s->inuse++; - qunlock(s); - return 0; -} - -/* - * Decrement the reference count on a stream. If the count is - * zero, free the stream. - */ -int -streamexit(Stream *s, int locked) -{ - Queue *q; - Queue *nq; - int rv; - char *name; - - if(!locked) - qlock(s); - if(s->inuse == 1){ - if(s->opens != 0) - panic("streamexit %d %s\n", s->opens, s->devq->info->name); - - /* - * ascend the stream freeing the queues - */ - for(q = s->devq; q; q = nq){ - nq = q->next; - freeq(q); - } - s->id = s->dev = s->type = 0; - } - s->inuse--; - rv = s->inuse; - if(!locked) - qunlock(s); - return rv; -} - -/* - * On the last close of a stream, for each queue on the - * stream release its blocks and call its close routine. - */ -int -streamclose1(Stream *s) -{ - Queue *q, *nq; - Block *bp; - int rv; - - /* - * decrement the reference count - */ - qlock(s); - if(s->opens == 1){ - /* - * descend the stream closing the queues - */ - for(q = s->procq; q; q = q->next){ - if(!waserror()){ - if(q->info->close) - (*q->info->close)(q->other); - poperror(); - } - WR(q)->put = nullput; - - /* - * this may be 2 streams joined device end to device end - */ - if(q == s->devq->other) - break; - } - - /* - * ascend the stream flushing the queues - */ - for(q = s->devq; q; q = nq){ - nq = q->next; - flushq(q); - } - } - rv = --(s->opens); - - /* - * leave it and free it - */ - streamexit(s, 1); - qunlock(s); - return rv; -} -int -streamclose(Chan *c) -{ - /* - * if no stream, ignore it - */ - if(!c->stream) - return; - return streamclose1(c->stream); -} - -/* - * put a block to be read into the queue. wakeup any waiting reader - */ -void -stputq(Queue *q, Block *bp) -{ - int delim; - - if(bp->type == M_HANGUP){ - freeb(bp); - q->flag |= QHUNGUP; - q->other->flag |= QHUNGUP; - wakeup(&q->other->r); - delim = 1; - } else { - delim = 0; - lock(q); - if(q->first) - q->last->next = bp; - else - q->first = bp; - q->len += BLEN(bp); - q->nb++; - delim = bp->flags & S_DELIM; - while(bp->next) { - bp = bp->next; - q->len += BLEN(bp); - q->nb++; - delim |= bp->flags & S_DELIM; - } - q->last = bp; - if(q->len >= Streamhi || q->nb >= Streambhi){ - q->flag |= QHIWAT; - delim = 1; - } - unlock(q); - } - if(delim) - wakeup(&q->r); -} - -/* - * read a string. update the offset accordingly. - */ -long -stringread(Chan *c, uchar *buf, long n, char *str) -{ - long i; - - i = strlen(str); - i -= c->offset; - if(ioffset, n); - return n; -} - -/* - * return the stream id - */ -long -streamctlread(Chan *c, void *vbuf, long n) -{ - uchar *buf = vbuf; - char num[32]; - Stream *s; - - s = c->stream; - if(STREAMTYPE(c->qid.path) == Sctlqid){ - sprint(num, "%d", s->id); - return stringread(c, buf, n, num); - } else { - if(CHDIR & c->qid.path) - return devdirread(c, vbuf, n, 0, 0, streamgen); - else - panic("streamctlread"); - } -} - -/* - * return true if there is an output buffer available - */ -static int -isinput(void *x) -{ - Queue *q; - - q = (Queue *)x; - return (q->flag&QHUNGUP) || q->first!=0; -} - -/* - * read until we fill the buffer or until a DELIM is encountered - */ -long -streamread(Chan *c, void *vbuf, long n) -{ - Block *bp; - Stream *s; - Queue *q; - int left, i; - uchar *buf = vbuf; - - if(STREAMTYPE(c->qid.path) != Sdataqid) - return streamctlread(c, vbuf, n); - - /* - * one reader at a time - */ - s = c->stream; - qlock(&s->rdlock); - if(waserror()){ - qunlock(&s->rdlock); - nexterror(); - } - - /* - * sleep till data is available - */ - q = RD(s->procq); - left = n; - while(left){ - bp = getq(q); - if(bp == 0){ - if(q->flag & QHUNGUP){ - if(s->hread++ < 3) - break; - else - error(Ehungup); - } - sleep(&q->r, &isinput, (void *)q); - continue; - } - - i = BLEN(bp); - if(i <= left){ - memcpy(buf, bp->rptr, i); - left -= i; - buf += i; - if(bp->flags & S_DELIM){ - freeb(bp); - break; - } else - freeb(bp); - } else { - memcpy(buf, bp->rptr, left); - bp->rptr += left; - putbq(q, bp); - left = 0; - } - }; - - qunlock(&s->rdlock); - poperror(); - return n - left; -} - -/* - * look for an instance of the line discipline `name' on - * the stream `s' - */ -void -qlook(Stream *s, char *name) -{ - Queue *q; - - for(q = s->procq; q; q = q->next){ - if(strcmp(q->info->name, name) == 0) - return; - - /* - * this may be 2 streams joined device end to device end - */ - if(q == s->devq->other) - break; - } - errors("not found"); -} - -/* - * Handle a ctl request. Streamwide requests are: - * - * hangup -- send an M_HANGUP up the stream - * push ldname -- push the line discipline named ldname - * pop -- pop a line discipline - * look ldname -- look for a line discipline - * - * This routing is entrered with s->wrlock'ed and must unlock. - */ -static long -streamctlwrite(Chan *c, void *a, long n) -{ - Qinfo *qi; - Block *bp; - Stream *s; - - if(STREAMTYPE(c->qid.path) != Sctlqid) - panic("streamctlwrite %lux", c->qid); - s = c->stream; - - /* - * package - */ - bp = allocb(n+1); - memcpy(bp->wptr, a, n); - bp->wptr[n] = 0; - bp->wptr += n + 1; - - /* - * check for standard requests - */ - if(streamparse("hangup", bp)){ - hangup(s); - freeb(bp); - } else if(streamparse("push", bp)){ - qi = qinfofind((char *)bp->rptr); - pushq(s, qi); - freeb(bp); - } else if(streamparse("pop", bp)){ - popq(s); - freeb(bp); - } else if(streamparse("look", bp)){ - qlook(s, (char *)bp->rptr); - freeb(bp); - } else { - bp->type = M_CTL; - bp->flags |= S_DELIM; - PUTNEXT(s->procq, bp); - } - - return n; -} - -/* - * wait till there's room in the next stream - */ -static int -notfull(void *arg) -{ - return !QFULL((Queue *)arg); -} -void -flowctl(Queue *q) -{ - qlock(&q->rlock); - if(waserror()){ - qunlock(&q->rlock); - nexterror(); - } - sleep(&q->r, notfull, q->next); - qunlock(&q->rlock); - poperror(); -} - -/* - * send the request as a single delimited block - */ -long -streamwrite(Chan *c, void *a, long n, int docopy) -{ - Stream *s; - Block *bp; - Queue *q; - long rem; - int i; - - s = c->stream; - - /* - * decode the qid - */ - if(STREAMTYPE(c->qid.path) != Sdataqid) - return streamctlwrite(c, a, n); - - /* - * No writes allowed on hungup channels - */ - q = s->procq; - if(q->other->flag & QHUNGUP) - error(Ehungup); - - if(!docopy && GLOBAL(a)){ - /* - * `a' is global to the whole system, just create a - * pointer to it and pass it on. - */ - FLOWCTL(q); - bp = allocb(0); - bp->rptr = bp->base = (uchar *)a; - bp->wptr = bp->lim = (uchar *)a+n; - bp->flags |= S_DELIM; - bp->type = M_DATA; - PUTNEXT(q, bp); - } else { - /* - * `a' is in the user's address space, copy it into - * system buffers and pass the buffers on. - */ - for(rem = n; ; rem -= i) { - FLOWCTL(q); - bp = allocb(rem); - i = bp->lim - bp->wptr; - if(i >= rem){ - memcpy(bp->wptr, a, rem); - bp->flags |= S_DELIM; - bp->wptr += rem; - bp->type = M_DATA; - PUTNEXT(q, bp); - break; - } else { - memcpy(bp->wptr, a, i); - bp->wptr += i; - bp->type = M_DATA; - PUTNEXT(q, bp); - a = ((char*)a) + i; - } - } - } - return n; -} - -/* - * like andrew's getmfields but no hidden state - */ -int -getfields(char *lp, /* to be parsed */ - char **fields, /* where to put pointers */ - int n, /* number of pointers */ - char sep /* separator */ -) -{ - int i; - - for(i=0; lp && *lp && istream; - if(s == 0) - n = 0; - else { - q = RD(s->procq); - lock(q); - for(n=0, bp=q->first; bp; bp = bp->next){ - n += BLEN(bp); - if(bp->flags&S_DELIM) - break; - } - unlock(q); - } - - devdir(c, c->qid, name, n, 0, &dir); - convD2M(&dir, db); -} - -/* - * Dump all block information of how many blocks are in which queues - */ -void -dumpblocks(Queue *q, char c) -{ - Block *bp; - uchar *cp; - - lock(q); - for(bp = q->first; bp; bp = bp->next){ - print("%c%d%c", c, bp->wptr-bp->rptr, (bp->flags&S_DELIM)?'D':' '); - for(cp = bp->rptr; cpwptr && cprptr+10; cp++) - print(" %uo", *cp); - print("\n"); - } - unlock(q); -} - -void -dumpqueues(void) -{ - Queue *q; - int count; - Block *bp; - Bclass *bcp; - - print("\n"); - for(q = qlist; q < qlist + conf.nqueue; q++, q++){ - if(!(q->flag & QINUSE)) - continue; - print("%s %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\n", WR(q)->nb, WR(q)->len, WR(q)->flag, - &(WR(q)->r)); - dumpblocks(q, 'R'); - dumpblocks(WR(q), 'W'); - } - print("\n"); - for(bcp=bclass; bcp<&bclass[Nclass]; bcp++){ - lock(bcp); - for(count = 0, bp = bcp->first; bp; count++, bp = bp->next) - ; - unlock(bcp); - print("%d blocks of size %d\n", count, bcp->size); - } - print("\n"); -} diff --git a/gnot/sturp.c b/gnot/sturp.c deleted file mode 100644 index ed99aea02ef32ca92b4d748dbcf4ceaf99c0bb72..0000000000000000000000000000000000000000 --- a/gnot/sturp.c +++ /dev/null @@ -1,987 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "errno.h" - -enum { - MSrexmit= 1000, - Nmask= 0x7, -}; - -#define DPRINT if(q->flag&QDEBUG)print - -typedef struct Urp Urp; - -#define NOW (MACHP(0)->ticks*MS2HZ) - -/* - * URP status - */ -struct urpstat { - ulong input; /* bytes read from urp */ - ulong output; /* bytes output to urp */ - ulong rxmit; /* retransmit rejected urp msg */ - ulong rjtrs; /* reject, trailer size */ - ulong rjpks; /* reject, packet size */ - ulong rjseq; /* reject, sequence number */ - ulong levelb; /* unknown level b */ - ulong enqsx; /* enqs sent */ - ulong enqsr; /* enqs rcved */ -} urpstat; - -struct Urp { - QLock; - short state; /* flags */ - Rendez r; /* process waiting for output to finish */ - - /* input */ - QLock ack; /* ack lock */ - Queue *rq; /* input queue */ - uchar iseq; /* last good input sequence number */ - uchar lastecho; /* last echo/rej sent */ - uchar trbuf[3]; /* trailer being collected */ - short trx; /* # bytes in trailer being collected */ - int blocks; - - /* output */ - QLock xmit; /* output lock, only one process at a time */ - Queue *wq; /* output queue */ - int maxout; /* maximum outstanding unacked blocks */ - int maxblock; /* max block size */ - int next; /* next block to send */ - int unechoed; /* first unechoed block */ - int unacked; /* first unacked block */ - int nxb; /* next xb to use */ - Block *xb[8]; /* the xmit window buffer */ - QLock xl[8]; - ulong timer; /* timeout for xmit */ - int rexmit; -}; -Urp *urp; - -Rendez urpkr; -QLock urpkl; -int urpkstarted; - -#define WINDOW(u) ((u)->unechoed>(u)->next ? (u)->unechoed+(u)->maxout-(u)->next-8 :\ - (u)->unechoed+(u)->maxout-(u)->next) -#define IN(x, f, n) (f<=n ? (x>=f && x=f)) -#define NEXT(x) (((x)+1)&Nmask) - -/* - * Protocol control bytes - */ -#define SEQ 0010 /* sequence number, ends trailers */ -#undef ECHO -#define ECHO 0020 /* echos, data given to next queue */ -#define REJ 0030 /* rejections, transmission error */ -#define ACK 0040 /* acknowledgments */ -#define BOT 0050 /* beginning of trailer */ -#define BOTM 0051 /* beginning of trailer, more data follows */ -#define BOTS 0052 /* seq update algorithm on this trailer */ -#define SOU 0053 /* start of unsequenced trailer */ -#define EOU 0054 /* end of unsequenced trailer */ -#define ENQ 0055 /* xmitter requests flow/error status */ -#define CHECK 0056 /* xmitter requests error status */ -#define INITREQ 0057 /* request initialization */ -#define INIT0 0060 /* disable trailer processing */ -#define INIT1 0061 /* enable trailer procesing */ -#define AINIT 0062 /* response to INIT0/INIT1 */ -#undef DELAY -#define DELAY 0100 /* real-time printing delay */ -#define BREAK 0110 /* Send/receive break (new style) */ - -#define REJECTING 0x1 -#define INITING 0x2 -#define HUNGUP 0x4 -#define OPEN 0x8 -#define CLOSING 0x10 - -/* - * predeclared - */ -static void urpreset(void); -static void urpciput(Queue*, Block*); -static void urpiput(Queue*, Block*); -static void urpoput(Queue*, Block*); -static void urpopen(Queue*, Stream*); -static void urpclose(Queue *); -static void output(Urp*); -static void sendblock(Urp*, int); -static void rcvack(Urp*, int); -static void flushinput(Urp*); -static void sendctl(Urp*, int); -static void sendack(Urp*); -static void sendrej(Urp*); -static void initoutput(Urp*, int); -static void initinput(Urp*, int); -static void urpkproc(void *arg); -static void urpvomit(char*, Urp*); - -Qinfo urpinfo = -{ - urpciput, - urpoput, - urpopen, - urpclose, - "urp", - urpreset -}; - -static void -urpreset(void) -{ - urp = (Urp *)ialloc(conf.nurp*sizeof(Urp), 0); -} - -static void -urpopen(Queue *q, Stream *s) -{ - Urp *up; - int i; - char name[128]; - - if(!urpkstarted){ - qlock(&urpkl); - if(!urpkstarted){ - urpkstarted = 1; - kproc("urpkproc", urpkproc, 0); - } - qunlock(&urpkl); - } - - /* - * find a free urp structure - */ - for(up = urp; up < &urp[conf.nurp]; up++){ - qlock(up); - if(up->state == 0) - break; - qunlock(up); - } - if(up == &urp[conf.nurp]){ - q->ptr = 0; - WR(q)->ptr = 0; - error(Egreg); - } - - q->ptr = q->other->ptr = up; - up->rq = q; - up->wq = q->other; - up->state = OPEN; - qunlock(up); - initinput(up, 0); - initoutput(up, 0); -} - -/* - * Shut down the connection and kill off the kernel process - */ -static int -isflushed(void *a) -{ - Urp *up; - - up = (Urp *)a; - return (up->state&HUNGUP) || (up->unechoed==up->nxb && up->wq->len==0); -} -static void -urpclose(Queue *q) -{ - Block *bp; - Urp *up; - int i; - - up = (Urp *)q->ptr; - if(up == 0) - return; - - /* - * wait for all outstanding messages to drain, tell kernel - * process we're closing. - * - * if 2 minutes elapse, give it up - */ - up->state |= CLOSING; - tsleep(&up->r, isflushed, up, 2*60*1000); - up->state |= HUNGUP; - - qlock(&up->xmit); - /* - * ack all outstanding messages - */ - i = up->next - 1; - if(i < 0) - i = 7; - rcvack(up, ECHO+i); - - /* - * free all staged but unsent messages - */ - for(i = 0; i < 7; i++) - if(up->xb[i]){ - freeb(up->xb[i]); - up->xb[i] = 0; - } - qunlock(&up->xmit); - - qlock(up); - up->state = 0; - qunlock(up); -} - -/* - * upstream control messages - */ -static void -urpctliput(Urp *up, Queue *q, Block *bp) -{ - switch(bp->type){ - case M_HANGUP: - up->state |= HUNGUP; - wakeup(&up->r); - break; - } - PUTNEXT(q, bp); -} - -/* - * character mode input. - * - * the first byte in every message is a ctl byte (which belongs at the end). - */ -void -urpciput(Queue *q, Block *bp) -{ - Urp *up; - int i; - int ctl; - - up = (Urp *)q->ptr; - if(bp->type != M_DATA){ - urpctliput(up, q, bp); - return; - } - - /* - * get the control character - */ - ctl = *bp->rptr++; - if(ctl < 0) - return; - - /* - * take care of any data - */ - if(BLEN(bp)>0 && q->next->len<2*Streamhi && q->next->nb<2*Streambhi){ - bp->flags |= S_DELIM; - PUTNEXT(q, bp); - } else - freeb(bp); - - /* - * handle the control character - */ - switch(ctl){ - case 0: - break; - case ENQ: - urpstat.enqsr++; - sendctl(up, up->lastecho); - sendctl(up, ACK+up->iseq); - break; - - case CHECK: - sendctl(up, ACK+up->iseq); - break; - - case AINIT: - up->state &= ~INITING; - flushinput(up); - wakeup(&urpkr); - break; - - case INIT0: - case INIT1: - sendctl(up, AINIT); - if(ctl == INIT1) - q->put = urpiput; - initinput(up, 0); - break; - - case INITREQ: - initoutput(up, 0); - break; - - case BREAK: - break; - - case REJ+0: case REJ+1: case REJ+2: case REJ+3: - case REJ+4: case REJ+5: case REJ+6: case REJ+7: - rcvack(up, ctl); - break; - - case ACK+0: case ACK+1: case ACK+2: case ACK+3: - case ACK+4: case ACK+5: case ACK+6: case ACK+7: - case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: - case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: - rcvack(up, ctl); - break; - - case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: - case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: - qlock(&up->ack); - i = ctl & Nmask; - if(!QFULL(q->next)) - sendctl(up, up->lastecho = ECHO+i); - up->iseq = i; - qunlock(&up->ack); - break; - } -} - -/* - * block mode input. - * - * the first byte in every message is a ctl byte (which belongs at the end). - * - * Simplifying assumption: one put == one message && the control byte - * is in the first block. If this isn't true, strange bytes will be - * used as control bytes. - */ -void -urpiput(Queue *q, Block *bp) -{ - Urp *up; - int i; - int ctl; - - up = (Urp *)q->ptr; - if(bp->type != M_DATA){ - urpctliput(up, q, bp); - return; - } - - /* - * get the control character - */ - ctl = *bp->rptr++; - - /* - * take care of any block count(trx) - */ - while(up->trx){ - if(BLEN(bp)<=0) - break; - switch (up->trx) { - case 1: - case 2: - up->trbuf[up->trx++] = *bp->rptr++; - continue; - default: - up->trx = 0; - break; - } - } - - /* - * queue the block(s) - */ - if(BLEN(bp) > 0){ - bp->flags &= ~S_DELIM; - putq(q, bp); - if(q->len > 4*1024){ - flushinput(up); - return; - } - } else - freeb(bp); - - /* - * handle the control character - */ - switch(ctl){ - case 0: - break; - case ENQ: - DPRINT("rENQ %d %uo %uo\n", up->blocks, up->lastecho, ACK+up->iseq); - up->blocks = 0; - urpstat.enqsr++; - sendctl(up, up->lastecho); - sendctl(up, ACK+up->iseq); - flushinput(up); - break; - - case CHECK: - sendctl(up, ACK+up->iseq); - break; - - case AINIT: - up->state &= ~INITING; - flushinput(up); - wakeup(&urpkr); - break; - - case INIT0: - case INIT1: - sendctl(up, AINIT); - if(ctl == INIT0) - q->put = urpciput; - initinput(up, 0); - break; - - case INITREQ: - initoutput(up, 0); - break; - - case BREAK: - break; - - case BOT: - case BOTM: - case BOTS: - DPRINT("rBOT%d...", ctl-BOT); - up->trx = 1; - up->trbuf[0] = ctl; - break; - - case REJ+0: case REJ+1: case REJ+2: case REJ+3: - case REJ+4: case REJ+5: case REJ+6: case REJ+7: - DPRINT("rREJ\n"); - rcvack(up, ctl); - break; - - case ACK+0: case ACK+1: case ACK+2: case ACK+3: - case ACK+4: case ACK+5: case ACK+6: case ACK+7: - case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: - case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: - DPRINT("rACK %ux\n", ctl); - rcvack(up, ctl); - break; - - /* - * if the sequence number is the next expected - * and the trailer length == 3 - * and the block count matches the bytes received - * then send the bytes upstream. - */ - case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: - case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: - i = ctl & Nmask; - if(up->trx != 3){ - urpstat.rjtrs++; - sendrej(up); - break; - } else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){ - urpstat.rjpks++; - sendrej(up); - break; - } else if(i != ((up->iseq+1)&Nmask)) { - urpstat.rjseq++; - sendrej(up); - break; - } else if(q->next->len > (3*Streamhi)/2 - || q->next->nb > (3*Streambhi)/2) { - flushinput(up); - break; - } - DPRINT("rSEQ%d accept %d\n", i, q->len); - - /* - * send data upstream - */ - if(q->first) { - if(up->trbuf[0] != BOTM) - q->last->flags |= S_DELIM; - while(bp = getq(q)) - PUTNEXT(q, bp); - } else { - bp = allocb(0); - if(up->trbuf[0] != BOTM) - bp->flags |= S_DELIM; - PUTNEXT(q, bp); - } - up->trx = 0; - - /* - * acknowledge receipt - */ - qlock(&up->ack); - up->iseq = i; - if(!QFULL(q->next)) - sendctl(up, up->lastecho = ECHO|i); - qunlock(&up->ack); - break; - } -} - -/* - * downstream control - */ -static void -urpctloput(Urp *up, Queue *q, Block *bp) -{ - char *fields[2]; - int n; - int inwin=0, outwin=0; - - switch(bp->type){ - case M_CTL: - if(streamparse("init", bp)){ - switch(getfields((char *)bp->rptr, fields, 2, ' ')){ - case 2: - inwin = strtoul(fields[1], 0, 0); - case 1: - outwin = strtoul(fields[0], 0, 0); - } -/* initinput(up, inwin); */ - initoutput(up, outwin); - freeb(bp); - return; - } - if(streamparse("debug", bp)){ - switch(getfields((char *)bp->rptr, fields, 2, ' ')){ - case 1: - if (strcmp(fields[0], "on") == 0) { - q->flag |= QDEBUG; - q->other->flag |= QDEBUG; - } - if (strcmp(fields[0], "off") == 0) { - q->flag &= ~QDEBUG; - q->other->flag &= ~QDEBUG; - } - } - freeb(bp); - return; - } - } - PUTNEXT(q, bp); -} - -/* - * accept data from a writer - */ -static void -urpoput(Queue *q, Block *bp) -{ - Urp *up; - - up = (Urp *)q->ptr; - - if(bp->type != M_DATA){ - urpctloput(up, q, bp); - return; - } - - urpstat.output += BLEN(bp); - putq(q, bp); - output(up); -} - -/* - * start output - */ -static void -output(Urp *up) -{ - Block *bp, *nbp; - ulong now; - Queue *q; - int n; - int i; - - if(!canqlock(&up->xmit)) - return; - - if(waserror()){ - print("urp output error\n"); - qunlock(&up->xmit); - nexterror(); - } - - /* - * if still initing and it's time to rexmit, send an INIT1 - */ - now = NOW; - if(up->state & INITING){ - if(now > up->timer){ - sendctl(up, INIT1); - up->timer = now + MSrexmit; - } - goto out; - } - - /* - * fill the transmit buffers, `nxb' can never overtake `unechoed' - */ - q = up->wq; - i = NEXT(up->nxb); - if(i != up->unechoed) { - for(bp = getq(q); bp && i!=up->unechoed; i = NEXT(i)){ - if(up->xb[up->nxb] != 0) - urpvomit("output", up); - if(BLEN(bp) > up->maxblock){ - nbp = up->xb[up->nxb] = allocb(0); - nbp->rptr = bp->rptr; - nbp->wptr = bp->rptr = bp->rptr + up->maxblock; - } else { - up->xb[up->nxb] = bp; - bp = getq(q); - } - up->nxb = i; - } - if(bp) - putbq(q, bp); - } - - /* - * retransmit cruft - */ - if(up->rexmit){ - /* - * if a retransmit is requested, move next back to - * the unacked blocks - */ - up->rexmit = 0; - up->next = up->unacked; - } else if(up->unechoed!=up->next && NOW>up->timer){ - /* - * if a retransmit time has elapsed since a transmit, - * send an ENQ - */ - up->timer = NOW + MSrexmit; - up->state &= ~REJECTING; - sendctl(up, ENQ); - goto out; - } - - /* - * if there's a window open, push some blocks out - * - * the lock is to synchronize with acknowledges that free - * blocks. - */ - while(WINDOW(up)>0 && up->next!=up->nxb){ - i = up->next; - qlock(&up->xl[i]); - if(waserror()){ - qunlock(&up->xl[i]); - nexterror(); - } - sendblock(up, i); - qunlock(&up->xl[i]); - up->next = NEXT(up->next); - poperror(); - } -out: - qunlock(&up->xmit); - poperror(); -} - -/* - * send a control byte, put the byte at the end of the allocated - * space in case a lower layer needs header room. - */ -static void -sendctl(Urp *up, int ctl) -{ - Block *bp; - Queue *q; - - q = up->wq; - if(QFULL(q->next)) - return; - bp = allocb(1); - bp->wptr = bp->lim; - bp->rptr = bp->lim-1; - *bp->rptr = ctl; - bp->flags |= S_DELIM; - PUTNEXT(q, bp); - DPRINT("sCTL %ulx\n", ctl); -} - -/* - * send a reject - */ -static void -sendrej(Urp *up) -{ - Queue *q = up->wq; - flushinput(up); - qlock(&up->ack); - if((up->lastecho&~Nmask) == ECHO){ - DPRINT("REJ %d\n", up->iseq); - sendctl(up, up->lastecho = REJ|up->iseq); - } - qunlock(&up->ack); -} - -/* - * send an acknowledge - */ -static void -sendack(Urp *up) -{ - Block *bp; - - /* - * check the precondition for acking - */ - if(QFULL(up->rq->next) || (up->lastecho&Nmask)==up->iseq) - return; - - if(!canqlock(&up->ack)) - return; - - /* - * check again now that we've locked - */ - if(QFULL(up->rq->next) || (up->lastecho&Nmask)==up->iseq){ - qunlock(&up->ack); - return; - } - - /* - * send the ack - */ - sendctl(up, up->lastecho = ECHO|up->iseq); - qunlock(&up->ack); -} - -/* - * send a block. - */ -static void -sendblock(Urp *up, int bn) -{ - Block *bp, *m, *nbp; - int n; - Queue *q; - - q = up->wq; - up->timer = NOW + MSrexmit; - if(QFULL(q->next)) - return; - - /* - * message 1, the BOT and the data - */ - bp = up->xb[bn]; - if(bp == 0) - return; - m = allocb(1); - m->rptr = m->lim - 1; - m->wptr = m->lim; - *m->rptr = (bp->flags & S_DELIM) ? BOT : BOTM; - nbp = m->next = allocb(0); - nbp->rptr = bp->rptr; - nbp->wptr = bp->wptr; - nbp->flags |= S_DELIM; - PUTNEXT(q, m); - - /* - * message 2, the block length and the SEQ - */ - m = allocb(3); - m->rptr = m->lim - 3; - m->wptr = m->lim; - n = BLEN(bp); - m->rptr[0] = SEQ | bn; - m->rptr[1] = n; - m->rptr[2] = n<<8; - m->flags |= S_DELIM; - PUTNEXT(q, m); - DPRINT("sb %d\n", bn); -} - -/* - * receive an acknowledgement - */ -static void -rcvack(Urp *up, int msg) -{ - int seqno; - int next; - int i; - - seqno = msg&Nmask; - next = NEXT(seqno); - - /* - * release any acknowledged blocks - */ - if(IN(seqno, up->unacked, up->next)){ - for(; up->unacked != next; up->unacked = NEXT(up->unacked)){ - i = up->unacked; - qlock(&up->xl[i]); - if(up->xb[i]) - freeb(up->xb[i]); - else - urpvomit("rcvack", up); - up->xb[i] = 0; - qunlock(&up->xl[i]); - } - } - - switch(msg & 0370){ - case ECHO: - if(IN(seqno, up->unechoed, up->next)) { - up->unechoed = next; - } - /* - * the next reject at the start of a window starts a - * retransmission. - */ - up->state &= ~REJECTING; - break; - case REJ: - if(IN(seqno, up->unechoed, up->next)) - up->unechoed = next; - /* - * ... FALL THROUGH ... - */ - case ACK: - /* - * start a retransmission if we aren't retransmitting - * and this is the start of a window. - */ - if(up->unechoed==next && !(up->state & REJECTING)){ - up->state |= REJECTING; - up->rexmit = 1; - } - break; - } - - wakeup(&urpkr); -} - -/* - * throw away any partially collected input - */ -static void -flushinput(Urp *up) -{ - Block *bp; - - while (bp = getq(up->rq)) - freeb(bp); - up->trx = 0; -} - -/* - * initialize output - */ -static void -initoutput(Urp *up, int window) -{ - int i; - - /* - * set output window - */ - up->maxblock = window/4; - if(up->maxblock < 64) - up->maxblock = 64; - up->maxblock -= 4; - up->maxout = 3; - - /* - * set sequence varialbles - */ - up->unechoed = 1; - up->unacked = 1; - up->next = 1; - up->nxb = 1; - up->rexmit = 0; - - /* - * free any outstanding blocks - */ - for(i = 0; i < 8; i++){ - qlock(&up->xl[i]); - if(up->xb[i]) - freeb(up->xb[i]); - up->xb[i] = 0; - qunlock(&up->xl[i]); - } - - /* - * tell the other side we've inited - */ - up->state |= INITING; - up->timer = NOW + MSrexmit; - sendctl(up, INIT1); -} - -/* - * initialize input - */ -static void -initinput(Urp *up, int window) -{ - /* - * restart all sequence parameters - */ - up->blocks = 0; - up->trx = 0; - up->iseq = 0; - up->lastecho = ECHO+0; - flushinput(up); -} - -static void -urpkproc(void *arg) -{ - Urp *up, *eup; - - if(waserror()) - ; - - eup = urp + conf.nurp; - for(;;){ - for(up = urp; up < eup; up++){ - if(up->state==0 || (up->state&HUNGUP)) - break; - if(!canqlock(up)) - continue; - if(up->state==0 || (up->state&HUNGUP)) - break; - if(up->iseq!=(up->lastecho&7) && !QFULL(up->rq->next)) - sendack(up); - output(up); - qunlock(up); - } - tsleep(&urpkr, return0, 0, 1000); - } -} - -/* - * urp got very confused, complain - */ -static void -urpvomit(char *msg, Urp* up) -{ - print("urpvomit: %s %ux next %d unechoed %d unacked %d nxb %d\n", - msg, up, up->next, up->unechoed, up->unacked, up->nxb); - print("\txb: %ux %ux %ux %ux %ux %ux %ux %ux\n", - up->xb[0], up->xb[1], up->xb[2], up->xb[3], up->xb[4], - up->xb[5], up->xb[6], up->xb[7]); - print("\tiseq: %uo lastecho: %uo trx: %d trbuf: %uo %uo %uo\n", - up->iseq, up->lastecho, up->trx, up->trbuf[0], up->trbuf[1], - up->trbuf[2]); - print("\tupq: %ux %d %d\n", &up->rq->next->r, up->rq->next->nb, - up->rq->next->len); -} - -int -urpdump(void) -{ - Urp *up; - - for(up = urp; up < &urp[conf.nurp]; up++) - if(up->rq) - urpvomit("", up); -} diff --git a/gnot/sysfile.c b/gnot/sysfile.c deleted file mode 100644 index b15a6b8b2e49d466ca84fdd71565caa102ee98a5..0000000000000000000000000000000000000000 --- a/gnot/sysfile.c +++ /dev/null @@ -1,508 +0,0 @@ -#include "u.h" -#include "lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "errno.h" -#include "fcall.h" - -/* - * The sys*() routines needn't poperror() as they return directly to syscall(). - */ - -int -newfd(void) -{ - int i; - - for(i=0; ifd[i] == 0){ - if(i > u->maxfd) - u->maxfd = i; - return i; - } - error(Enofd); -} - -Chan* -fdtochan(int fd, int mode) -{ - Chan *c; - - c = 0; /* set */ - if(fd<0 || NFD<=fd || (c=u->fd[fd])==0) - error(Ebadfd); - if(mode<0 || c->mode==ORDWR) - return c; - if((mode&OTRUNC) && c->mode==OREAD) - err: - error(Ebadusefd); - if((mode&~OTRUNC) != c->mode) - goto err; - return c; -} - -int -openmode(ulong o) -{ - if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC)) - Err: - error(Ebadarg); - o &= ~(OTRUNC|OCEXEC|ORCLOSE); - if(o > OEXEC) - goto Err; - if(o == OEXEC) - return OREAD; - return o; -} - -long -syspipe(ulong *arg) -{ - int fd[2]; - Chan *c[2]; - Dev *d; - - validaddr(arg[0], 2*BY2WD, 1); - evenaddr(arg[0]); - d = &devtab[devno('|', 0)]; - c[0] = (*d->attach)(0); - c[1] = 0; - fd[0] = -1; - fd[1] = -1; - if(waserror()){ - close(c[0]); - if(c[1]) - close(c[1]); - if(fd[0] >= 0) - u->fd[fd[0]]=0; - if(fd[1] >= 0) - u->fd[fd[1]]=0; - nexterror(); - } - c[1] = (*d->clone)(c[0], 0); - (*d->walk)(c[0], "data"); - (*d->walk)(c[1], "data1"); - c[0] = (*d->open)(c[0], ORDWR); - c[1] = (*d->open)(c[1], ORDWR); - fd[0] = newfd(); - u->fd[fd[0]] = c[0]; - fd[1] = newfd(); - u->fd[fd[1]] = c[1]; - ((long*)arg[0])[0] = fd[0]; - ((long*)arg[0])[1] = fd[1]; - poperror(); - return 0; -} - -long -sysdup(ulong *arg) -{ - int fd; - Chan *c, *oc; - - /* - * Close after dup'ing, so date > #d/1 works - */ - c = fdtochan(arg[0], -1); - fd = arg[1]; - if(fd != -1) - oc = u->fd[fd]; - else{ - oc = 0; - fd = newfd(); - } - u->fd[fd] = c; - incref(c); - if(oc) - close(oc); - return fd; -} - -long -sysopen(ulong *arg) -{ - int fd; - Chan *c; - - openmode(arg[1]); /* error check only */ - fd = newfd(); - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Aopen, arg[1], 0); - u->fd[fd] = c; - return fd; -} - -void -fdclose(int fd) -{ - int i; - - u->fd[fd] = 0; - if(fd == u->maxfd) - for(i=fd; --i>=0 && u->fd[i]==0; ) - u->maxfd = i; -} - -long -sysclose(ulong *arg) -{ - Chan *c; - - c = fdtochan(arg[0], -1); - close(c); - fdclose(arg[0]); - return 0; -} - -long -unionread(Chan *c, void *va, long n) -{ - Mount *mnt; - Chan *mc, *nc; - Pgrp *pg = u->p->pgrp; - long nr; - - mnt = c->mnt; - lock(pg); - if(c->mountid != mnt->mountid){ - pprint("unionread: changed underfoot?\n"); - unlock(pg); - return 0; - } - Again: - mc = mnt->c; - incref(mc); - unlock(pg); - if(waserror()){ - close(mc); - nexterror(); - } - nc = clone(mc, 0); - close(mc); - poperror(); - if(waserror()){ - close(nc); - nexterror(); - } - nc = (*devtab[nc->type].open)(nc, OREAD); - nc->offset = c->offset; - nr = (*devtab[nc->type].read)(nc, va, n); - c->offset = nc->offset; /* devdirread e.g. changes it */ - close(nc); - poperror(); - if(nr > 0) - return nr; - /* - * Advance to next element - */ - lock(pg); - mnt = c->mnt; - if(c->mountid != mnt->mountid){ - print("unionread: changed underfoot?\n"); - unlock(pg); - return 0; - } - if(mnt->term){ - unlock(pg); - return 0; - } - mnt = mnt->next; - c->mnt = mnt; - c->mountid = mnt->mountid; - c->offset = 0; - goto Again; -} - -long -sysread(ulong *arg) -{ - Chan *c; - long n; - - c = fdtochan(arg[0], OREAD); - validaddr(arg[1], arg[2], 1); - qlock(c); - if(waserror()){ - qunlock(c); - nexterror(); - } - n = arg[2]; - if(c->qid.path & CHDIR){ - n -= n%DIRLEN; - if(c->offset%DIRLEN || n==0) - error(Ebaddirread); - } - if((c->qid.path&CHDIR) && (c->flag&CMOUNT)) - n = unionread(c, (void*)arg[1], n); - else - n = (*devtab[c->type].read)(c, (void*)arg[1], n); - c->offset += n; - qunlock(c); - return n; -} - -long -syswrite(ulong *arg) -{ - Chan *c; - long n; - - c = fdtochan(arg[0], OWRITE); - validaddr(arg[1], arg[2], 0); - qlock(c); - if(waserror()){ - qunlock(c); - nexterror(); - } - if(c->qid.path & CHDIR) - error(Eisdir); - n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2]); - c->offset += n; - qunlock(c); - return n; -} - -long -sysseek(ulong *arg) -{ - Chan *c; - char buf[DIRLEN]; - Dir dir; - long off; - - c = fdtochan(arg[0], -1); - if(c->qid.path & CHDIR) - error(Eisdir); - qlock(c); - if(waserror()){ - qunlock(c); - nexterror(); - } - switch(arg[2]){ - case 0: - c->offset = arg[1]; - break; - - case 1: - c->offset += (long)arg[1]; - break; - - case 2: - (*devtab[c->type].stat)(c, buf); - convM2D(buf, &dir); - c->offset = dir.length + (long)arg[1]; - break; - } - off = c->offset; - qunlock(c); - poperror(); - return off; -} - -long -sysfstat(ulong *arg) -{ - Chan *c; - long n; - - validaddr(arg[1], DIRLEN, 1); - evenaddr(arg[1]); - c = fdtochan(arg[0], -1); - (*devtab[c->type].stat)(c, (char*)arg[1]); - return 0; -} - -long -sysstat(ulong *arg) -{ - Chan *c; - long n; - - validaddr(arg[1], DIRLEN, 1); - evenaddr(arg[1]); - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Aaccess, 0, 0); - if(waserror()){ - close(c); - nexterror(); - } - (*devtab[c->type].stat)(c, (char*)arg[1]); - poperror(); - close(c); - return 0; -} - -long -syschdir(ulong *arg) -{ - Chan *c; - - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Atodir, 0, 0); - close(u->dot); - u->dot = c; - return 0; -} - -long -bindmount(ulong *arg, int ismount) -{ - Chan *c0, *c1; - ulong flag; - long ret; - char *p; - int t; - struct{ - Chan *chan; - char *spec; - char *auth; - }bogus; - - flag = arg[2]; - if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER)) - error(Ebadarg); - if(ismount){ - bogus.chan = fdtochan(arg[0], 2); - validaddr(arg[3], 1, 0); - p = (char*)arg[3]; - t = BY2PG-((ulong)p&(BY2PG-1)); - while(vmemchr(p, 0, t) == 0){ - p += t; - t = BY2PG; - } - bogus.spec = (char*)arg[3]; - validaddr(arg[4], 1, 0); - p = (char*)arg[4]; - t = BY2PG-((ulong)p&(BY2PG-1)); - while(vmemchr(p, 0, t) == 0){ - p += t; - t = BY2PG; - } - bogus.auth = (char*)arg[4]; - ret = devno('M', 0); - c0 = (*devtab[ret].attach)((char*)&bogus); - }else{ - validaddr(arg[0], 1, 0); - c0 = namec((char*)arg[0], Aaccess, 0, 0); - } - if(waserror()){ - close(c0); - nexterror(); - } - validaddr(arg[1], 1, 0); - c1 = namec((char*)arg[1], Amount, 0, 0); - if(waserror()){ - close(c1); - nexterror(); - } - if((c0->qid.path^c1->qid.path) & CHDIR) - error(Ebadmount); - if(flag && !(c0->qid.path&CHDIR)) - error(Ebadmount); - ret = mount(c0, c1, flag); - close(c0); - close(c1); - if(ismount){ - close(bogus.chan); - fdclose(arg[0]); - } - return ret; -} - -long -sysbind(ulong *arg) -{ - return bindmount(arg, 0); -} - -long -sysmount(ulong *arg) -{ - return bindmount(arg, 1); -} - -long -syscreate(ulong *arg) -{ - int fd; - Chan *c; - - openmode(arg[1]); /* error check only */ - fd = newfd(); - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Acreate, arg[1], arg[2]); - u->fd[fd] = c; - return fd; -} - -long -sysremove(ulong *arg) -{ - Chan *c; - - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Aaccess, 0, 0); - if(waserror()){ - c->type = 0; /* see below */ - close(c); - nexterror(); - } - (*devtab[c->type].remove)(c); - /* - * Remove clunks the fid, but we need to recover the Chan - * so fake it up. rootclose() is known to be a nop. - */ - c->type = 0; - close(c); - return 0; -} - -long -syswstat(ulong *arg) -{ - Chan *c; - long n; - - validaddr(arg[1], DIRLEN, 0); - evenaddr(arg[1]); - validaddr(arg[0], 1, 0); - c = namec((char*)arg[0], Aaccess, 0, 0); - if(waserror()){ - close(c); - nexterror(); - } - (*devtab[c->type].wstat)(c, (char*)arg[1]); - poperror(); - close(c); - return 0; -} - -long -sysfwstat(ulong *arg) -{ - Chan *c; - long n; - - validaddr(arg[1], DIRLEN, 0); - evenaddr(arg[1]); - c = fdtochan(arg[0], -1); - (*devtab[c->type].wstat)(c, (char*)arg[1]); - return 0; -} - -#ifdef asdf -long -sysfilsys(ulong *arg) -{ - Chan *cin, *cout; - - cin = fdtochan(arg[0], OREAD); - cout = fdtochan(arg[1], OWRITE); - validaddr(arg[2], 1, 0); - if((cin->qid.path&CHDIR) || (cout->qid.path&CHDIR)) - error(Ebadarg); - service((char *)arg[2], cin, cout, filsys); - return 0; -} -#endif diff --git a/port/devdk.c b/port/devdk.c index a8f8a6595d21c237d1a5ddbc8c94ba97ed78eabc..872c534862bfd0fc4ca9a9a923da91ecdcd92ccb 100644 --- a/port/devdk.c +++ b/port/devdk.c @@ -128,8 +128,8 @@ struct Dk { int restart; int urpwindow; Rendez timer; - Rendez rallclosed; - int allclosedp; /* true once a closeall has been seen */ + int closeall; /* set when we receive a closeall message */ + Rendez closeallr; /* wait here for a closeall */ }; static Dk dk[Ndk]; static Lock dklock; @@ -528,12 +528,12 @@ dkoput(Queue *q, Block *bp) * we can configure only once */ static int -allclosed(void *arg) +haveca(void *arg) { Dk *dp; dp = arg; - return dp->allclosedp; + return dp->closeall; } static void dkmuxconfig(Queue *q, Block *bp) @@ -610,6 +610,7 @@ dkmuxconfig(Queue *q, Block *bp) * open csc here so that boot, dktimer, and dkcsckproc aren't * all fighting for it at once. */ + dp->closeall = 0; dp->csc = dkopenline(dp, dp->ncsc); /* @@ -617,11 +618,7 @@ dkmuxconfig(Queue *q, Block *bp) */ sprint(buf, "csc.%s.%d", dp->name, dp->ncsc); kproc(buf, dkcsckproc, dp); - - /* - * wait for first possible closeall (may not come) - */ - tsleep(&dp->rallclosed, allclosed, dp, 2000); + tsleep(&dp->closeallr, haveca, dp, 5000); /* wait for initial closeall */ /* * tell datakit we've rebooted. It should close all channels. @@ -629,7 +626,9 @@ dkmuxconfig(Queue *q, Block *bp) */ if(dp->restart) { DPRINT("dktimer: restart %s\n", dp->name); + dp->closeall = 0; dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0); + tsleep(&dp->closeallr, haveca, dp, 5000); /* wait for restart closeall */ } /* @@ -637,12 +636,6 @@ dkmuxconfig(Queue *q, Block *bp) */ sprint(buf, "timer.%s.%d", dp->name, dp->ncsc); kproc(buf, dktimer, dp); - - /* - * wait for closeall in response to D_RESTART - */ - if(dp->restart) - tsleep(&dp->rallclosed, allclosed, dp, 10000); } /* @@ -1585,8 +1578,8 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) break; } } - dp->allclosedp = 1; - wakeup(&dp->rallclosed); + dp->closeall = 1; + wakeup(&dp->closeallr); break; default: diff --git a/port/devmnt.c b/port/devmnt.c index ae0c1ee728eaa07ce6473c7c290b7fe8256bd4c3..d026eaf296f0badd4b3c59cdc1f26c3d8c13d3ae 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -37,7 +37,6 @@ struct Mntbuf { Mntbuf *next; char buf[BUFSIZE]; - int n; }; struct @@ -666,20 +665,6 @@ mntreadreply(void *a) return ((Mnthdr *)a)->readreply; } -/* - * print out first few bytes of the message - */ -dumpmsg(Mntbuf *mb) -{ - int i; - char *x; - - x = mb->buf; - for(i = 0; i < mb->n; i++) - print("%.2ux ", *x++); - print("\n"); -} - void mntxmit(Mnt *m, Mnthdr *mh) { @@ -792,10 +777,8 @@ mntxmit(Mnt *m, Mnthdr *mh) mh->mbr = mballoc(); n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE); poperror(); /* 3 */ - mh->mbr->n = n; if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){ print("bad reply message\n"); - dumpmsg(mh->mbr); mnterrdequeue(m, mh); error(Ebadmsg); } @@ -823,7 +806,6 @@ mntxmit(Mnt *m, Mnthdr *mh) */ if(tag<0 || tag>=conf.nmnthdr){ print("unknown tag %d\n", tag); - dumpmsg(mh->mbr); goto Read; } w = &mnthdralloc.arena[tag]; @@ -871,7 +853,6 @@ mntxmit(Mnt *m, Mnthdr *mh) error(Eshutdown); }else if(mh->rhdr.type != mh->thdr.type+1){ print("bad type %d not %d in mntxmit\n", mh->rhdr.type, mh->thdr.type+1); - dumpmsg(mh->mbr); error(Ebadmsg); } /* diff --git a/port/devnonet.c b/port/devnonet.c new file mode 100644 index 0000000000000000000000000000000000000000..c79f3c9fbaec0e68b9bc13ed58afefb1c5456010 --- /dev/null +++ b/port/devnonet.c @@ -0,0 +1,1233 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" + +#define DPRINT if(0) +#define NOW (MACHP(0)->ticks*MS2HZ) + +static Noifc *noifc; + +enum { + /* + * tuning parameters + */ + MSrexmit = 500, /* retranmission interval in ms */ + MSack = 50, /* ms to sit on an ack */ + + /* + * relative or immutable + */ + Nsubdir = 5, /* entries in the nonet directory */ + Nmask = Nnomsg - 1, /* mask for log(Nnomsg) bits */ +}; + +/* predeclared */ +static void hangup(Noconv*); +static Block* mkhdr(Noconv*, int); +static void listen(Chan*, Noifc*); +static void announce(Chan*, char*); +static void connect(Chan*, char*); +static void rcvack(Noconv*, int); +static void sendctlmsg(Noconv*, int, int); +static void sendmsg(Noconv*, Nomsg*); +static void startconv(Noconv*, int, char*, int); +static void queueack(Noconv*, int); + +static void nonetiput(Queue*, Block*); +static void nonetoput(Queue*, Block*); +static void nonetstclose(Queue*); +static void nonetstopen(Queue*, Stream*); + +extern Qinfo noetherinfo; +extern Qinfo nonetinfo; + +/* + * nonet directory and subdirectory + */ +enum { + /* + * per conversation + */ + Naddrqid, + Nlistenqid, + Nraddrqid, + Nruserqid, + Nstatsqid, + Nchanqid, + + /* + * per noifc + */ + Ncloneqid, +}; + +Dirtab *nonetdir; +Dirtab nosubdir[]={ + "addr", {Naddrqid}, 0, 0600, + "listen", {Nlistenqid}, 0, 0600, + "raddr", {Nraddrqid}, 0, 0600, + "ruser", {Nruserqid}, 0, 0600, + "stats", {Nstatsqid}, 0, 0600, +}; + +/* + * Nonet conversation states (for Noconv.state) + */ +enum { + Cclosed, + Copen, + Cannounced, + Cconnected, + Cconnecting, + Chungup, + Cclosing, +}; + +/* + * nonet file system. most of the calls use dev.c to access the nonet + * directory and stream.c to access the nonet devices. + * create the nonet directory. the files are `clone' and stream + * directories '1' to '32' (or whatever conf.noconv is in decimal) + */ +void +nonetreset(void) +{ + int i; + + /* + * allocate the interfaces + */ + noifc = (Noifc *)ialloc(sizeof(Noifc) * conf.nnoifc, 0); + for(i = 0; i < conf.nnoconv; i++) + noifc[i].conv = (Noconv *)ialloc(sizeof(Noconv) * conf.nnoconv, 0); + + /* + * create the directory. + */ + nonetdir = (Dirtab *)ialloc(sizeof(Dirtab) * (conf.nnoconv+1), 0); + + /* + * the circuits + */ + for(i = 0; i < conf.nnoconv; i++) { + sprint(nonetdir[i].name, "%d", i); + nonetdir[i].qid.path = CHDIR|STREAMQID(i, Nchanqid); + nonetdir[i].qid.vers = 0; + nonetdir[i].length = 0; + nonetdir[i].perm = 0600; + } + + /* + * the clone device + */ + strcpy(nonetdir[i].name, "clone"); + nonetdir[i].qid.path = Ncloneqid; + nonetdir[i].qid.vers = 0; + nonetdir[i].length = 0; + nonetdir[i].perm = 0600; +} + +void +nonetinit(void) +{ +} + +/* + * find an noifc and increment its count + */ +Chan* +nonetattach(char *spec) +{ + Noifc *ifc; + Chan *c; + + /* + * find an noifc with the same name + */ + if(*spec == 0) + spec = "nonet"; + for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){ + lock(ifc); + if(strcmp(spec, ifc->name)==0 && ifc->wq) { + ifc->ref++; + unlock(ifc); + break; + } + unlock(ifc); + } + if(ifc == &noifc[conf.nnoifc]) + error(Enoifc); + c = devattach('n', spec); + c->dev = ifc - noifc; + return c; +} + +/* + * up the reference count to the noifc + */ +Chan* +nonetclone(Chan *c, Chan *nc) +{ + Noifc *ifc; + + c = devclone(c, nc); + ifc = &noifc[c->dev]; + lock(ifc); + ifc->ref++; + unlock(ifc); + return c; +} + +int +nonetwalk(Chan *c, char *name) +{ + if(c->qid.path == CHDIR) + return devwalk(c, name, nonetdir, conf.nnoconv+1, devgen); + else + return devwalk(c, name, nosubdir, Nsubdir, streamgen); +} + +void +nonetstat(Chan *c, char *dp) +{ + if(c->qid.path == CHDIR) + devstat(c, dp, nonetdir, conf.nnoconv+1, devgen); + else if(c->qid.path == Ncloneqid) + devstat(c, dp, nonetdir, 1, devgen); + else + devstat(c, dp, nosubdir, Nsubdir, streamgen); +} + +/* + * opening a nonet device allocates a Noconv. Opening the `clone' + * device is a ``macro'' for finding a free Noconv and opening + * it's ctl file. + */ +Noconv * +nonetopenclone(Chan *c, Noifc *ifc) +{ + Noconv *cp; + Noconv *ep; + + ep = &ifc->conv[conf.nnoconv]; + for(cp = &ifc->conv[0]; cp < ep; cp++){ + if(cp->state == Cclosed && canqlock(cp)){ + if(cp->state != Cclosed){ + qunlock(cp); + continue; + } + c->qid.path = CHDIR|STREAMQID(cp-ifc->conv, Nchanqid); + devwalk(c, "ctl", 0, 0, streamgen); + streamopen(c, &nonetinfo); + qunlock(cp); + break; + } + } + if(cp == ep) + error(Enodev);; + return cp; +} + +Chan* +nonetopen(Chan *c, int omode) +{ + Stream *s; + Noconv *cp; + Noifc *ifc; + int line; + + if(c->qid.path & CHDIR){ + /* + * directories are read only + */ + if(omode != OREAD) + error(Ebadarg); + } else switch(STREAMTYPE(c->qid.path)){ + case Ncloneqid: + /* + * get an unused device and open it's control file + */ + ifc = &noifc[c->dev]; + cp = nonetopenclone(c, ifc); + break; + case Nlistenqid: + /* + * listen for a call and open the control file for the + * channel on which the call arrived. + */ + line = STREAMID(c->qid.path); + ifc = &noifc[c->dev]; + if(ifc->conv[line].state != Cannounced) + error(Enoannounce); + listen(c, ifc); + break; + case Nraddrqid: + /* + * read only files + */ + if(omode != OREAD) + error(Ebadarg); + break; + default: + /* + * open whatever c points to + */ + streamopen(c, &nonetinfo); + break; + } + + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +nonetcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(Eperm); +} + +void +nonetclose(Chan *c) +{ + Noifc *ifc; + + /* + * real closing happens in nonetstclose + */ + if(c->qid.path != CHDIR) + streamclose(c); + + /* + * let go of the multiplexor + */ + nonetfreeifc(&noifc[c->dev]); +} + +long +nonetread(Chan *c, void *a, long n) +{ + int t; + Noconv *cp; + char stats[256]; + + /* + * pass data/ctl reads onto the stream code + */ + t = STREAMTYPE(c->qid.path); + if(t >= Slowqid) + return streamread(c, a, n); + + if(c->qid.path == CHDIR) + return devdirread(c, a, n, nonetdir, conf.nnoconv+1, devgen); + if(c->qid.path & CHDIR) + return devdirread(c, a, n, nosubdir, Nsubdir, streamgen); + + cp = &noifc[c->dev].conv[STREAMID(c->qid.path)]; + switch(t){ + case Nraddrqid: + return stringread(c, a, n, cp->raddr); + case Naddrqid: + return stringread(c, a, n, cp->addr); + case Nruserqid: + return stringread(c, a, n, cp->ruser); + case Nstatsqid: + sprint(stats, "sent: %d\nrcved: %d\nrexmit: %d\nbad: %d\n", + cp->sent, cp->rcvd, cp->rexmit, cp->bad); + return stringread(c, a, n, stats); + } + error(Eperm); +} + +long +nonetwrite(Chan *c, void *a, long n) +{ + int t; + int m; + char buf[256]; + char *field[5]; + + t = STREAMTYPE(c->qid.path); + + /* + * get data dispatched as quickly as possible + */ + if(t == Sdataqid) + return streamwrite(c, a, n, 0); + + /* + * easier to do here than in nonetoput + */ + if(t == Sctlqid){ + strncpy(buf, a, sizeof buf); + m = getfields(buf, field, 5, ' '); + if(strcmp(field[0], "connect")==0){ + if(m < 2) + error(Ebadarg); + connect(c, field[1]); + } else if(strcmp(field[0], "announce")==0){ + announce(c, field[1]); + } else if(strcmp(field[0], "accept")==0){ + /* ignore */; + } else if(strcmp(field[0], "reject")==0){ + /* ignore */; + } else + return streamwrite(c, a, n, 0); + return n; + } + + error(Eperm); +} + +void +nonetremove(Chan *c) +{ + error(Eperm); +} + +void +nonetwstat(Chan *c, char *dp) +{ + error(Eperm); +} + +/* + * the device stream module definition + */ +Qinfo nonetinfo = +{ + nonetiput, + nonetoput, + nonetstopen, + nonetstclose, + "nonet" +}; + +/* + * store the device end of the stream so that the multiplexor can + * send blocks upstream. + */ +static void +nonetstopen(Queue *q, Stream *s) +{ + Noifc *ifc; + Noconv *cp; + + ifc = &noifc[s->dev]; + cp = &ifc->conv[s->id]; + cp->s = s; + cp->ifc = ifc; + cp->rq = RD(q); + cp->state = Copen; + RD(q)->ptr = WR(q)->ptr = (void *)cp; +} + +/* + * wait until a hangup is received. + * then send a hangup message (until one is received). + */ +static int +ishungup(void *a) +{ + Noconv *cp; + + cp = (Noconv *)a; + return cp->state == Chungup; +} +static void +nonetstclose(Queue *q) +{ + Noconv *cp; + Nomsg *mp; + int i; + + cp = (Noconv *)q->ptr; + + if(waserror()){ + cp->rcvcircuit = -1; + cp->state = Cclosed; + nexterror(); + } + + /* + * send hangup messages to the other side + * until it hangs up or we get tired. + */ + if(cp->state >= Cconnected){ + sendctlmsg(cp, NO_HANGUP, 1); + for(i=0; i<10 && !ishungup(cp); i++){ + sendctlmsg(cp, NO_HANGUP, 1); + tsleep(&cp->r, ishungup, cp, MSrexmit); + } + } + + cp->rcvcircuit = -1; + cp->state = Cclosed; + poperror(); +} + +/* + * send all messages up stream. this should only be control messages + */ +static void +nonetiput(Queue *q, Block *bp) +{ + Noconv *cp; + + if(bp->type == M_HANGUP){ + cp = (Noconv *)q->ptr; + cp->state = Chungup; + } + PUTNEXT(q, bp); +} + +/* + * queue a block + */ +static int +windowopen(void *a) +{ + Noconv *cp; + + cp = (Noconv *)a; + return cp->out[cp->next].inuse == 0; +} +static int +acked(void *a) +{ + Nomsg *mp; + + mp = (Nomsg *)a; + return mp->acked; +} +static void +nonetoput(Queue *q, Block *bp) +{ + Noconv *cp; + int next; + Nomsg *mp; + + cp = (Noconv *)(q->ptr); + + /* + * do all control functions + */ + if(bp->type != M_DATA){ + freeb(bp); + error(Ebadctl); + } + + /* + * collect till we see a delim + */ + qlock(&cp->mlock); + if(!putb(q, bp)){ + qunlock(&cp->mlock); + return; + } + + mp = 0; + if(waserror()){ + if(mp){ + if(mp->first){ + freeb(mp->first); + mp->first = 0; + } + mp->inuse = 0; + } else + qunlock(&cp->mlock); + } + + /* + * block till we get a buffer + */ + while(cp->out[cp->next].inuse) + sleep(&cp->r, windowopen, cp); + mp = &cp->out[cp->next]; + mp->inuse = 1; + cp->next = (cp->next+1)%Nnomsg; + + /* + * stick the message in a Nomsg structure + */ + mp->time = NOW + MSrexmit; + mp->first = q->first; + mp->last = q->last; + mp->len = q->len; + mp->mid ^= Nnomsg; + mp->acked = 0; + + /* + * init the queue for new messages + */ + q->len = 0; + q->first = q->last = 0; + cp->sent++; + qunlock(&cp->mlock); + + /* + * wait for acknowledgement + */ + while(!mp->acked && cp->state!=Chungup){ + sendmsg(cp, mp); + tsleep(&mp->r, acked, mp, MSrexmit); + } + + /* + * free buffer + */ + freeb(mp->first); + mp->first = 0; + mp->inuse = 0; + wakeup(&cp->r); + poperror(); +} + +/* + * start a new conversation. start an ack/retransmit process if + * none already exists for this circuit. + */ +void +startconv(Noconv *cp, int circuit, char *raddr, int state) +{ + int i; + char name[32]; + Noifc *ifc; + + ifc = cp->ifc; + + /* + * allocate the prototype header + */ + cp->media = allocb(ifc->hsize + NO_HDRSIZE); + cp->media->wptr += ifc->hsize + NO_HDRSIZE; + cp->hdr = (Nohdr *)(cp->media->rptr + ifc->hsize); + + /* + * fill in the circuit number + */ + cp->hdr->flag = NO_NEWCALL|NO_ACKME; + cp->hdr->circuit[2] = circuit>>16; + cp->hdr->circuit[1] = circuit>>8; + cp->hdr->circuit[0] = circuit; + + /* + * set the state variables + */ + cp->state = state; + for(i = 1; i < Nnomsg; i++){ + cp->in[i].mid = i; + cp->in[i].acked = 0; + cp->in[i].rem = 0; + cp->out[i].mid = i | Nnomsg; + cp->out[i].acked = 1; + cp->out[i].rem = 0; + cp->out[i].inuse = 0; + } + cp->in[0].mid = Nnomsg; + cp->in[0].acked = 0; + cp->in[0].rem = 0; + cp->out[0].mid = 0; + cp->out[0].acked = 1; + cp->out[0].rem = 0; + cp->first = cp->next = 1; + cp->rexmit = cp->bad = cp->sent = cp->rcvd = cp->lastacked = 0; + + /* + * used for demultiplexing + */ + cp->rcvcircuit = circuit ^ 1; + + /* + * media dependent header + */ + (*ifc->connect)(cp, raddr); + + /* + * status files + */ + strncpy(cp->raddr, raddr, sizeof(cp->raddr)); + strcpy(cp->ruser, "none"); +} + +/* + * announce willingness to take calls + */ +static void +announce(Chan *c, char *addr) +{ + Noconv *cp; + + cp = (Noconv *)(c->stream->devq->ptr); + if(cp->state != Copen) + error(Einuse); + cp->state = Cannounced; +} + +/* + * connect to the destination whose name is pointed to by bp->rptr. + * + * a service is separated from the destination system by a '!' + */ +static void +connect(Chan *c, char *addr) +{ + Noifc *ifc; + Noconv *cp; + char *service; + char buf[2*NAMELEN+2]; + + cp = (Noconv *)(c->stream->devq->ptr); + if(cp->state != Copen) + error(Einuse); + ifc = cp->ifc; + service = strchr(addr, '!'); + if(service){ + *service++ = 0; + if(strchr(service, ' ')) + error(Ebadctl); + if(strlen(service) > NAMELEN) + error(Ebadctl); + } + + startconv(cp, 2*(cp - ifc->conv), addr, Cconnecting); + + if(service){ + /* + * send service name and user name + */ + cp->hdr->flag |= NO_SERVICE; + sprint(buf, "%s %s", service, u->p->pgrp->user); + c->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid); + streamwrite(c, buf, strlen(buf), 1); + c->qid.path = STREAMQID(STREAMID(c->qid.path), Sctlqid); + } +} + +/* + * listen for a call. There can be many listeners, but only one can sleep + * on the circular queue at a time. ifc->listenl lets only one at a time into + * the sleep. + */ +static int +iscall(void *a) +{ + Noifc *ifc; + + ifc = (Noifc *)a; + return ifc->rptr != ifc->wptr; +} +static void +listen(Chan *c, Noifc *ifc) +{ + Noconv *cp, *ep; + Nocall call; + int f; + char buf[2*NAMELEN+4]; + char *user; + long n; + + call.msg = 0; + + if(waserror()){ + if(call.msg) + freeb(call.msg); + qunlock(&ifc->listenl); + nexterror(); + } + + for(;;){ + /* + * one listener at a time + */ + qlock(&ifc->listenl); + + /* + * wait for a call + */ + sleep(&ifc->listenr, iscall, ifc); + call = ifc->call[ifc->rptr]; + ifc->rptr = (ifc->rptr+1) % Nnocalls; + qunlock(&ifc->listenl); + + /* + * make sure we aren't already using this circuit + */ + ep = &ifc->conv[conf.nnoconv]; + for(cp = &ifc->conv[0]; cp < ep; cp++){ + if(cp->state>Cannounced && call.circuit==cp->rcvcircuit + && strcmp(call.raddr, cp->raddr)==0) + break; + } + if(cp != ep){ + freeb(call.msg); + call.msg = 0; + continue; + } + + /* + * get a free channel + */ + cp = nonetopenclone(c, ifc); + c->qid.path = STREAMQID(cp - ifc->conv, Sctlqid); + + /* + * start the protocol and + * stuff the connect message into it + */ + f = ((Nohdr *)(call.msg->rptr))->flag; + startconv(cp, call.circuit, call.raddr, Cconnecting); + print("rcving %d byte message\n", call.msg->wptr - call.msg->rptr); + nonetrcvmsg(cp, call.msg); + call.msg = 0; + + /* + * if a service and remote user were specified, + * grab them + */ + if(f & NO_SERVICE){ + print("reading service\n"); + c->qid.path = STREAMQID(cp - ifc->conv, Sdataqid); + n = streamread(c, buf, sizeof(buf)); + c->qid.path = STREAMQID(cp - ifc->conv, Sctlqid); + print("read %d bytes\n", n); + if(n <= 0) + error(Ebadctl); + buf[n] = 0; + print("read %s\n", buf); + user = strchr(buf, ' '); + if(user){ + *user++ = 0; + strncpy(cp->ruser, user, NAMELEN); + } else + strcpy(cp->ruser, "none"); + strncpy(cp->addr, buf, NAMELEN); + } + break; + } + poperror(); +} + +/* + * send a hangup signal up the stream to get all line disciplines + * to cease and desist + */ +static void +hangup(Noconv *cp) +{ + Block *bp; + Queue *q; + + cp->state = Chungup; + bp = allocb(0); + bp->type = M_HANGUP; + q = cp->rq; + PUTNEXT(q, bp); + wakeup(&cp->r); +} + +/* + * process a message acknowledgement. if the message + * has any xmit buffers queued, free them. + */ +static void +rcvack(Noconv *cp, int mid) +{ + Nomsg *mp; + Block *bp; + int i; + + mp = &cp->out[mid & Nmask]; + + /* + * if already acked, ignore + */ + if(mp->acked || mp->mid != mid) + return; + + /* + * wakeup the sender + */ + mp->acked = 1; + wakeup(&mp->r); + cp->lastacked = mid; +} + +/* + * queue an acknowledgement to be sent. ignore it if we already have Nnomsg + * acknowledgements queued. + */ +static void +queueack(Noconv *cp, int mid) +{ + int next; + ulong now; + + now = NOW; + next = (cp->anext + 1)&Nmask; + if(next != cp->afirst){ + cp->ack[cp->anext] = mid; + cp->anext = next; + } +} + +/* + * make a packet header + */ +Block * +mkhdr(Noconv *cp, int rem) +{ + Block *bp; + Nohdr *hp; + + bp = allocb(cp->ifc->hsize + NO_HDRSIZE + cp->ifc->mintu); + memcpy(bp->wptr, cp->media->rptr, cp->ifc->hsize + NO_HDRSIZE); + bp->wptr += cp->ifc->hsize + NO_HDRSIZE; + hp = (Nohdr *)(bp->rptr + cp->ifc->hsize); + hp->remain[1] = rem>>8; + hp->remain[0] = rem; + hp->sum[0] = hp->sum[1] = 0; + return bp; +} + +/* + * transmit a message. this involves breaking a possibly multi-block message into + * a train of packets on the media. + * + * called by nonetoput(). the qlock(mp) synchronizes these two + * processes. + */ +static void +sendmsg(Noconv *cp, Nomsg *mp) +{ + Noifc *ifc; + Queue *wq; + int msgrem; + int pktrem; + int n; + Block *bp, *pkt, *last; + uchar *rptr; + + ifc = cp->ifc; + if(ifc == 0) + return; + wq = ifc->wq->next; + + /* + * one transmitter at a time + */ + qlock(&cp->xlock); + + if(waserror()){ + qunlock(&cp->xlock); + return; + } + + /* + * get the next acknowledge to use if the next queue up + * is not full. + */ + if(cp->afirst != cp->anext && cp->rq->next->len < 16*1024){ + cp->hdr->ack = cp->ack[cp->afirst]; + cp->afirst = (cp->afirst+1)&Nmask; + } + cp->hdr->mid = mp->mid; + + if(ifc->mintu > mp->len) { + /* + * short message: + * copy the whole message into the header block + */ + last = pkt = mkhdr(cp, mp->len); + for(bp = mp->first; bp; bp = bp->next){ + memcpy(pkt->wptr, bp->rptr, n = BLEN(bp)); + pkt->wptr += n; + } + memset(pkt->wptr, 0, n = ifc->mintu - mp->len); + pkt->wptr += n; + } else { + /* + * long message: + * break up the message into noifc packets and send them. + * once around this loop for each non-header block generated. + */ + msgrem = mp->len; + pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem; + bp = mp->first; + if(bp) + rptr = bp->rptr; + last = pkt = mkhdr(cp, msgrem); + while(bp){ + /* + * if pkt full, send and create new header block + */ + if(pktrem == 0){ + nonetcksum(pkt, ifc->hsize); + last->flags |= S_DELIM; + (*wq->put)(wq, pkt); + last = pkt = mkhdr(cp, -msgrem); + pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem; + } + n = bp->wptr - rptr; + if(n > pktrem) + n = pktrem; + last = last->next = allocb(0); + last->rptr = rptr; + last->wptr = rptr = rptr + n; + msgrem -= n; + pktrem -= n; + if(rptr >= bp->wptr){ + bp = bp->next; + if(bp) + rptr = bp->rptr; + } + } + } + nonetcksum(pkt, ifc->hsize); + last->flags |= S_DELIM; + (*wq->put)(wq, pkt); + mp->time = NOW + MSrexmit; + qunlock(&cp->xlock); + poperror(); +} + +/* + * send a control message (hangup or acknowledgement). + */ +static void +sendctlmsg(Noconv *cp, int flag, int new) +{ + cp->ctl.len = 0; + cp->ctl.first = 0; + cp->ctl.acked = 0; + if(new) + cp->ctl.mid = Nnomsg^cp->out[cp->next].mid; + else + cp->ctl.mid = cp->lastacked; + cp->hdr->flag |= flag; + sendmsg(cp, &cp->ctl); +} + +/* + * receive a message (called by the multiplexor; noetheriput, nofddiiput, ...) + */ +void +nonetrcvmsg(Noconv *cp, Block *bp) +{ + Block *nbp; + Nohdr *h; + short r; + int c; + Nomsg *mp; + int f; + Queue *q; + + q = cp->rq; + + /* + * grab the packet header, push the pointer past the nonet header + */ + h = (Nohdr *)bp->rptr; + bp->rptr += NO_HDRSIZE; + mp = &cp->in[h->mid & Nmask]; + r = (h->remain[1]<<8) | h->remain[0]; + f = h->flag; + + /* + * if a new call request comes in on a connected channel, hang up the call + */ + if(h->mid==0 && (f & NO_NEWCALL) && cp->state==Cconnected){ + freeb(bp); + hangup(cp); + return; + } + + /* + * ignore old messages and process the acknowledgement + */ + if(h->mid != mp->mid){ + DPRINT("old msg %d instead of %d\n", h->mid, mp->mid); + if(r == 0){ + rcvack(cp, h->ack); + if(f & NO_HANGUP) + hangup(cp); + } else { + if(r>0) + queueack(cp, h->mid); + cp->bad++; + } + freeb(bp); + return; + } + + if(r>=0){ + /* + * start of message packet + */ + if(mp->first){ + DPRINT("mp->mid==%d mp->rem==%d buf r==%d\n", mp->mid, mp->rem, r); + cp->bad++; + freeb(bp); + return; + } + mp->rem = r; + } else { + /* + * a continuation + */ + if(-r != mp->rem) { + DPRINT("mp->mid==%d mp->rem==%d buf r==%d\n", mp->mid, mp->rem, r); + cp->bad++; + freeb(bp); + return; + } + } + + /* + * take care of packets that were padded up + */ + mp->rem -= BLEN(bp); + if(mp->rem < 0){ + if(-mp->rem <= BLEN(bp)){ + bp->wptr += mp->rem; + mp->rem = 0; + } else + panic("nonetrcvmsg: short packet"); + } + putb(mp, bp); + + /* + * if the last chunk - pass it up the stream and wake any + * waiting process. + * + * if not, strip off the delimiter. + */ + if(mp->rem == 0){ + rcvack(cp, h->ack); + if(f & NO_ACKME) + queueack(cp, h->mid); + mp->last->flags |= S_DELIM; + PUTNEXT(q, mp->first); + mp->first = mp->last = 0; + mp->len = 0; + cp->rcvd++; + + /* + * cycle bufffer to next expected mid + */ + mp->mid ^= Nnomsg; + + /* + * stop xmitting the NO_NEWCALL flag + */ + if(cp->state==Cconnecting && !(f & NO_NEWCALL)) + cp->state = Cconnected; + } else + mp->last->flags &= ~S_DELIM; + +} + +/* + * noifc + */ +/* + * Create an ifc. + */ +Noifc * +nonetnewifc(Queue *q, Stream *s, int maxtu, int mintu, int hsize, + void (*connect)(Noconv *, char *)) +{ + Noifc *ifc; + int i; + + for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){ + if(ifc->ref == 0){ + lock(ifc); + if(ifc->ref) { + /* someone was faster than us */ + unlock(ifc); + continue; + } + RD(q)->ptr = WR(q)->ptr = (void *)ifc; + for(i = 0; i < conf.nnoconv; i++) + ifc->conv[i].rcvcircuit = -1; + ifc->maxtu = maxtu - hsize - NO_HDRSIZE; + ifc->mintu = mintu - hsize - NO_HDRSIZE; + ifc->hsize = hsize; + ifc->connect = connect; + ifc->name[0] = 0; + ifc->wq = WR(q); + ifc->ref = 1; + unlock(ifc); + return ifc; + } + } + error(Enoifc); +} + +/* + * Free an noifc. + */ +void +nonetfreeifc(Noifc *ifc) +{ + lock(ifc); + ifc->ref--; + if(ifc->ref == 0) + ifc->wq = 0; + unlock(ifc); +} + +/* + * calculate the checksum of a list of blocks. ignore the first `offset' bytes. + */ +int +nonetcksum(Block *bp, int offset) +{ + Block *nbp = bp; + uchar *ep, *p; + int n; + ulong s; + Nohdr *hp; + + s = 0; + p = bp->rptr + offset; + n = bp->wptr - p; + hp = (Nohdr *)p; + hp->sum[0] = hp->sum[1] = 0; + for(;;){ + ep = p+(n&~0x7); + while(p < ep) { + s = s + s + p[0]; + s = s + s + p[1]; + s = s + s + p[2]; + s = s + s + p[3]; + s = s + s + p[4]; + s = s + s + p[5]; + s = s + s + p[6]; + s = s + s + p[7]; + s = (s&0xffff) + (s>>16); + p += 8; + } + ep = p+(n&0x7); + while(p < ep) { + s = s + s + *p; + p++; + } + s = (s&0xffff) + (s>>16); + bp = bp->next; + if(bp == 0) + break; + p = bp->rptr; + n = BLEN(bp); + } + s = (s&0xffff) + (s>>16); + hp->sum[1] = s>>8; + hp->sum[0] = s; + return s & 0xffff; +} diff --git a/port/filsys.c b/port/filsys.c new file mode 100644 index 0000000000000000000000000000000000000000..bebe542dca38a73c59c5eabf6ac6c3d83aa52f5c --- /dev/null +++ b/port/filsys.c @@ -0,0 +1,250 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +#include "fcall.h" + +#define PRINT print + +enum { + Rreadhlen = 8, /* number of chars in Rread message hdr */ +}; + +typedef struct Ftrans Ftrans; + +struct Ftrans{ + long fid; + Chan *c; + Chan *pc; +}; + +static Ftrans *fsyshash; +static Lock fsyslock; + +static void fsysnewchan(Chan *, long, Chan *); +static Chan *fsyschan(Chan *, long); +static int fsyserr(void); + +void +filsysinit(void) +{ + fsyshash = ialloc(conf.nfsyschan * sizeof(Ftrans), 0); +} + +void +filsys(Chan *protoc, char *msg, long msgn) +{ + Fcall r, t, *rf, *tf; + Chan *c, *c0; + long fid, n; + + if(!convM2S(msg, &r, msgn)){ + error(Ebadmsg); + } + rf = &r; + tf = &t; + if(waserror()){ + tf->type = Rerror; + strncpy(tf->ename, u->error, sizeof(tf->ename)); + goto Errret; + } + fid = rf->fid; + if(rf->type != Tattach) + c = fsyschan(protoc, fid); + switch(rf->type){ + case Tattach: + c = clone(u->slash, 0); + fsysnewchan(protoc, fid, c); + break; + case Tclone: + c0 = clone(c, 0); + c0 = domount(c0); + fsysnewchan(protoc, rf->newfid, c0); + break; + case Twalk: + if((c0 = walk(c, rf->name, 1)) == 0) + error(Enonexist); + if(c != c0) + fsysnewchan(protoc, fid, c0); + tf->qid = c0->qid; + break; + case Topen: + c0 = (*devtab[c->type].open)(c, rf->mode); + if(c != c0) + fsysnewchan(protoc, fid, c0); + if(rf->mode & OCEXEC) + c0->flag |= CCEXEC; + break; + case Tcreate: + if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) + c0 = createdir(c); + (*devtab[c->type].create)(c, rf->name, rf->mode, rf->perm); + if(rf->mode & OCEXEC) + c->flag |= CCEXEC; + break; + case Tread: + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + n = rf->count; + tf->count = 0; + /* overwrite the input msg -- assumes buffer is big enough */ + tf->data = msg+Rreadhlen; + if(c->qid.path&CHDIR){ + n -= n%DIRLEN; + if(c->offset%DIRLEN || n==0) + error(Ebaddirread); + } + if((c->qid.path&CHDIR) && (c->flag&CMOUNT)) + n = unionread(c, tf->data, n); + else + n = (*devtab[c->type].read)(c, tf->data, n); + c->offset += n; + qunlock(c); + poperror(); + tf->count = n; + break; + case Twrite: + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + if(c->qid.path & CHDIR) + error(Eisdir); + n = rf->count; + tf->count = 0; + n = (*devtab[c->type].write)(c, rf->data, n); + c->offset += n; + qunlock(c); + poperror(); + tf->count = n; + break; + case Tclunk: + close(c); + fsysnewchan(protoc, rf->fid, 0); + break; + case Tremove: + (*devtab[c->type].remove)(c); + break; + case Tstat: + (*devtab[c->type].stat)(c, tf->stat); + break; + case Twstat: + (*devtab[c->type].wstat)(c, rf->stat); + break; + case Tflush: + /* really, this message has to be handled by caller */ + break; + default: + error(Ebadmsg); + } + poperror(); + tf->type = rf->type+1; + Errret: + tf->fid = rf->fid; + tf->tag = rf->tag; + /* assume can reuse msg buf */ + n = convS2M(tf, msg); + qlock(protoc); + if(waserror()){ + qunlock(protoc); + nexterror(); + } + (*devtab[protoc->type].write)(protoc, msg, n); + qunlock(protoc); + poperror(); +} + +/* + * hash table discipline: linear probe + * a fid of 0 means 'free'; a fid of -1 means 'deleted' + * use a function as per Knuth + * only a function of fid, but protoc checked for match + */ +static int +fhash(long fid) +{ + long x; + + x = fid*29128; + if(x < 0) + x = -x; + x %= 262143; + return x % conf.nfsyschan; +} + +/* + * Register channel c for fid (if c!= 0). + * If c==0, unregister. + * The protoc argument is used to disambiguate + * identical fids from different attaches. + */ +static void +fsysnewchan(Chan *protoc, long fid, Chan *c) +{ + int i, m; + Ftrans *f, *fstop, *fend; + + i = fhash(fid); + f = fsyshash+i; + m = conf.nfsyschan; + fstop = f+(i+m-1)%m; + fend = fsyshash+m; + lock(&fsyslock); + while(f != fstop){ + if(f->fid == fid && f->pc == protoc){ + if(c) + f->c = c; + else + f->fid = -1; + break; + } + if(f->fid <= 0){ + f->c = c; + f->fid = fid; + f->pc = protoc; + break; + } + if(++f == fend) + f = fsyshash; + } + unlock(&fsyslock); + if(f == fstop) + error(Enofilsys); +} + +/* Return the channel registered for fid */ +static Chan* +fsyschan(Chan *protoc, long fid) +{ + int i, m; + Ftrans *f, *fstop, *fend; + + i = fhash(fid); + f = fsyshash+i; + if(f->fid == fid && f->pc == protoc) + return f->c; + m = conf.nfsyschan; + fstop = f; + if(++f == fend) + f = fsyshash; + fend = fsyshash+m; + while(f != fstop){ + if(f->fid == fid && f->pc == protoc) + return f->c; + if(f->fid == 0) + break; + if(++f == fend) + f = fsyshash; + } + error(Egreg); +} + diff --git a/port/malloc.c b/port/malloc.c new file mode 100644 index 0000000000000000000000000000000000000000..fb601c6d388d8e7f67afac47f66777312a1d1b93 --- /dev/null +++ b/port/malloc.c @@ -0,0 +1,430 @@ +/* compile-time features + IALLOC use all blocks given to ifree, otherwise ignore unordered blocks + MSTATS enable statistics + debug enable assertion checking + longdebug full arena checks at every transaction +*/ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +#define INT int +#define ALIGN int +#define NALIGN 1 +#define WORD sizeof(union store) +#define BLOCK 4096 +#define BUSY 1 +#define NULL 0 +#define testbusy(p) ((INT)(p)&BUSY) +#define setbusy(p) (union store *)((INT)(p)|BUSY) +#define clearbusy(p) (union store *)((INT)(p)&~BUSY) +#define IALLOC + +typedef +union store +{ + union store *ptr; + ALIGN dummy[NALIGN]; + int calloc; /*calloc clears an array of integers*/ +} Store; + +static int draincache(void); +static void* stdmalloc(long); +static int stdfree(Store*); +static void ifree(char*, long); + +#ifdef longdebug +#define debug 1 +#endif +#ifdef debug +#define ASSERT(p) if(!(p))botch("p");else +static +botch(char *s) +{ + char *c; + + c = "assertion botched: "; + write(2, c, strlen(c)); + write(2, s, strlen(s)); + write(2, "\n", 1); + abort(); +} +static int allock(Store*); +#else +#define ASSERT(p) +#endif + +/* C storage allocator + * circular first-fit strategy + * works with noncontiguous, but monotonically linked, arena + * each block is preceded by a ptr to the (pointer of) + * the next following block + * blocks are exact number of words long + * aligned to the data type requirements of ALIGN + * pointers to blocks must have BUSY bit 0 + * bit in ptr is 1 for busy, 0 for idle + * gaps in arena are merely noted as busy blocks + * last block of arena is empty and + * has a pointer to first + * idle blocks are coalesced during space search + * + * a different implementation may need to redefine + * ALIGN, NALIGN, BLOCK, BUSY, INT + * where INT is integer type to which a pointer can be cast + */ + + +/* alloca should have type union store. + * The funny business gets it initialized without complaint + */ +#define addr(a) (Store*)&a +static char *alloca; +static char *alloca = (char*)&alloca + BUSY; /* initial arena */ +static Store *allocs = addr(alloca); /*arena base*/ +static Store *allocc = addr(alloca); /*all prev blocks known busy*/ +static Store *allocp = addr(alloca); /*search ptr*/ +static Store *alloct = addr(alloca); /*top cell*/ +static Store *allocx; /*for benefit of realloc*/ + +/* a cache list of frequently-used sizes is maintained. From each + * cache entry hangs a chain of available blocks + * malloc(0) shuts off caching (to keep freed data clean) + */ + +#define CACHEMAX 256 /* largest block to be cached (in words) */ +#define CACHESIZ 53 /* number of entries (prime) */ + +static Store *cache[CACHESIZ]; +static int cachemax = CACHEMAX; + +#ifdef MSTATS +#define Mstats(e) e +static long nmalloc, nrealloc, nfree; /* call statistics */ +static long walloc, wfree; /* space statistics */ +static long chit, ccoll, cdrain, cavail; /* cache statistics */ +#else +#define Mstats(e) +#endif + +static QLock mlock; + +void* +malloc(ulong nbytes) +{ + Store *p; + long nw; + Store **cp; + void *mem; + + nw = (nbytes+WORD+WORD-1)/WORD; + qlock(&mlock); + Mstats((nmalloc++, walloc += nw)); + if(nw= 2) { + cp = &cache[nw%CACHESIZ]; + p = *cp; + if(p && nw == clearbusy(p->ptr)-p) { + ASSERT(testbusy(p->ptr)); + *cp = (++p)->ptr; + Mstats((chit++, cavail--)); + qunlock(&mlock); + return (char*)p; + } + } else { + draincache(); + cachemax = 0; + } + } + p = stdmalloc(nw); + qunlock(&mlock); + return p; +} + +static void* +stdmalloc(long nw) +{ + Store *p, *q; + int temp; + Page *page; + + ASSERT(allock(allocp)); + for(;;) { /* done at most thrice */ + p = allocp; + for(temp=0; ; ) { + if(!testbusy(p->ptr)) { + allocp = p; + while(!testbusy((q=p->ptr)->ptr)) { + ASSERT(q>p); + p->ptr = q->ptr; + } + if(q>=p+nw && p+nw>=p) + goto found; + } + q = p; + p = clearbusy(p->ptr); + if(p <= q) { + ASSERT(p == allocs && q == alloct); + if(++temp>1) + break; + ASSERT(allock(allocc)); + p = allocc; + } + } + + /* No memory in the free list. Call newpage and kmap to get + * some more, and ifree to put it in the list. + */ + page = newpage(1, 0, 0); + page->va = VA(kmap(page)); + draincache(); + ifree((char *) page->va, 1 << PGSHIFT); + } +found: + allocp += nw; + if(q>allocp) { + allocx = allocp->ptr; + allocp->ptr = p->ptr; + } + p->ptr = setbusy(allocp); + if(p<=allocc) { + ASSERT(p==allocc); + while(testbusy(allocc->ptr) + && (q=clearbusy(allocc->ptr))>allocc) + allocc = q; + } + return(p+1); +} + +void +free(void *ap) +{ + Store *p = ap, *q; + long nw; + Store **cp; + + if(p==NULL) + return; + --p; + qlock(&mlock); + ASSERT(allock(p)); + ASSERT(testbusy(p->ptr)); + ASSERT(!cached(p)); + nw = clearbusy(p->ptr) - p; + Mstats((nfree++, wfree += nw)); + ASSERT(nw>0); + if(nw=2) { + cp = &cache[nw%CACHESIZ]; + q = *cp; + if(!q || nw==clearbusy(q->ptr)-q) { + p[1].ptr = q; + *cp = p; + Mstats(cavail++); + qunlock(&mlock); + return; + } else Mstats(q && ccoll++); + } + stdfree(p+1); + qunlock(&mlock); +} + +/* freeing strategy tuned for LIFO allocation +*/ +static +stdfree(Store *p) +{ + allocp = --p; + if(p < allocc) + allocc = p; + ASSERT(allock(allocp)); + p->ptr = clearbusy(p->ptr); + ASSERT(p->ptr > allocp); +} + +static +draincache(void) +{ + Store **cp = cache+CACHESIZ; + Store *q; + int anyfreed = 0; + + while(--cp>=cache) { + while(q = *cp) { + ASSERT(testbusy(q->ptr)); + ASSERT((clearbusy(q->ptr)-q)%CACHESIZ==cp-cache); + ASSERT(q>=allocs&&q<=alloct); + stdfree(++q); + anyfreed++; + *cp = q->ptr; + } + } + Mstats((cdrain+=anyfreed, cavail=0)); + return anyfreed; +} + +/* ifree(q, nbytes) inserts a block that did not come + * from malloc into the arena + * + * q points to new block + * r points to last of new block + * p points to last cell of arena before new block + * s points to first cell of arena after new block +*/ + +static +void +ifree(char *qq, long nbytes) +{ + Store *p, *q, *r, *s; + + q = (Store *)qq; + r = q + (nbytes/WORD) - 1; + q->ptr = r; + if(q > alloct) { + p = alloct; + s = allocs; + alloct = r; + } else { +#ifdef IALLOC + /* useful only in small address spaces */ + for(p=allocs; ; p=s) { + s = clearbusy(p->ptr); + if(s==allocs) + break; + ASSERT(s>p); + if(s>r) { + if(pr); + } + } + if(allocs > q) + allocs = q; + if(allocc > q) + allocc = q; + allocp = allocc; +#else + return; +#endif + } + p->ptr = q==p+1? q: setbusy(q); + r->ptr = s==r+1? s: setbusy(s); + while(testbusy(allocc->ptr)) + allocc = clearbusy(allocc->ptr); +} + +/* realloc(p, nbytes) reallocates a block obtained from malloc() + * and freed since last call of malloc() + * to have new size nbytes, and old content + * returns new location, or 0 on failure +*/ + +void* +realloc(void *pp, ulong nbytes) +{ + Store *p = pp; + Store *s, *t; + Store *q; + long nw, onw; + + if(p==NULL) + return malloc(nbytes); + qlock(&mlock); + Mstats(nrealloc++); + ASSERT(allock(p-1)); + if(testbusy(p[-1].ptr)) + stdfree(p); + onw = p[-1].ptr - p; + nw = (nbytes+WORD-1)/WORD; + q = (Store *)stdmalloc(nw+1); + if(q!=NULL && q!=p) { + ASSERT(qp[-1].ptr); + if(nw=p) + (q+(q+nw-p))->ptr = allocx; + ASSERT(allock(q-1)); + } + qunlock(&mlock); + return q; +} + +#ifdef debug +static +allock(Store *q) +{ +#ifdef longdebug + register Store *p, *r; + register Store **cp; + int x, y; + for(cp=cache+CACHESIZ; --cp>=cache; ) { + if((p= *cp)==0) + continue; + x = clearbusy(p->ptr) - p; + ASSERT(x%CACHESIZ==cp-cache); + for( ; p; p = p[1].ptr) { + ASSERT(testbusy(p->ptr)); + ASSERT(clearbusy(p->ptr)-p==x); + } + } + x = 0, y = 0; + p = allocs; + for( ; (r=clearbusy(p->ptr)) > p; p=r) { + if(p==allocc) + y++; + ASSERT(y||testbusy(p->ptr)); + if(p==q) + x++; + } + ASSERT(r==allocs); + ASSERT(x==1||p==q); + ASSERT(y||p==allocc); + return(1); +#else + ASSERT((unsigned)q/WORD*WORD==(unsigned)q); + ASSERT(q>=allocs&&q<=alloct); +#endif +} +#endif + +mstats(void) +{ +#ifdef MSTATS + fprint(2, "Malloc statistics, including overhead bytes\n"); + fprint(2, "Arena: bottom %ld, top %ld\n", + (long)clearbusy(alloca), (long)alloct); + fprint(2, "Calls: malloc %ld, realloc %ld, free %ld\n", + nmalloc, nrealloc, nfree); + fprint(2, "Bytes: allocated or extended %ld, ", + walloc*WORD); + fprint(2, "freed or cut %ld\n", wfree*WORD); + fprint(2,"Cache: hits %ld, collisions %ld, discards %ld, avail %ld\n", + chit, ccoll, cdrain, cavail); +#endif +} + +#ifdef debug +cached(Store *p) +{ + Store *q = cache[(clearbusy(p->ptr)-p)%CACHESIZ]; + for( ; q; q=q[1].ptr) + ASSERT(p!=q); + return 0; +} +#endif + +void *calloc(ulong n, ulong size){ + void *p; + + size *= n; + p = malloc(size); + memset(p, 0, size); + return p; +} diff --git a/port/service.c b/port/service.c new file mode 100644 index 0000000000000000000000000000000000000000..8da9e8bd3a60203df4884b23b1ace0a695349486 --- /dev/null +++ b/port/service.c @@ -0,0 +1,222 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "fcall.h" + +#define BUFSIZE (MAXFDATA+500) /* BUG */ +typedef struct Buffer Buffer; +struct Buffer +{ + Buffer *next; + char buf[BUFSIZE]; +}; + +struct Servalloc { + Lock; + Service *all; + Service *freel; + Buffer *ball; + Buffer *bfreel; +} servalloc; + + +/* + * allocate the taks force structures and put them + * on the free list + */ +void +serviceinit(void) +{ + Service *s; + Buffer *b; + + servalloc.all = ialloc(conf.nservice * sizeof(Service), 0); + servalloc.freel = servalloc.all; + for(s = servalloc.all; s < &servalloc.all[conf.nservice-1]; s++) + s->next = s+1; + + servalloc.ball = ialloc(2*conf.nservice * sizeof(Service), 0); + servalloc.bfreel = servalloc.ball; + for(b = servalloc.ball; b < &servalloc.ball[2*conf.nservice-1]; b++) + b->next = b+1; +} + +/* + * Add a process to a service + */ +static Proc * +reinforce(Service *s) +{ + int i; + Proc *p; + + /* + * don't start one up if we already have too many, + * return our own process number + */ + lock(s); + if(s->ref == NSTUB){ + unlock(s); + return u->p; + } + s->ref++; + unlock(s); + + /* + * create it + */ + return kproc(s->name, 0, 0); +} + +/* + * resign from a service + */ +static void +resign(Service *s) +{ + int i; + + print("%lux resigning\n", u->p); + if(decref(s) == 0){ + print("freeing service\n"); + close(s->inc); + close(s->outc); + lock(&servalloc); + s->next = servalloc.freel; + servalloc.freel = s; + unlock(&servalloc); + } + pexit(0, 1); +} + +/* + * Create a service of kernel processes to handle file system requests. + * (*doit)() is a function that handles that event. Service + * dynamicly creates new processes (up to MAXTASK) to ensure that 1 process + * is always awaiting while others are doing. + */ +void +service(char *name, Chan *cin, Chan *cout, void (*doit)(Chan*, char*, long)) +{ + void *a; + Service *s; + Buffer *b; + long n; + + b = 0; + + /* + * allocate a service + */ + lock(&servalloc); + s = servalloc.freel; + if(s == 0) + panic("no more services"); + servalloc.freel = s->next; + unlock(&servalloc); + memset(s, 0, sizeof(Service)); + if(name==0 || *name==0) + strcpy(name, "filsys"); + else + strncpy(s->name, name, sizeof(s->name)); + s->inc = cin; + s->outc = cout; + s->die = 0; + incref(cin); + incref(cout); + + if(waserror()){ + /* + * tell everyone else to die + */ + s->die = 1; + + /* + * wake up the next guy + */ + qunlock(&s->alock); + + /* + * free the buffer if we have one + */ + if(b){ + lock(&servalloc); + b->next = servalloc.bfreel; + servalloc.bfreel = b; + unlock(&servalloc); + } + resign(s); + } + + /* + * Create the first process in the service. The + * caller returns. + */ + if(reinforce(s)){ + poperror(); + return; + } + + /* + * first process enters the infinite loop + */ + for(;;){ + b = 0; + qlock(&s->alock); + + /* + * if there's more than 1 process waiting, we're + * superfluous + */ + if(s->die || s->alock.head && s->alock.head!=s->alock.tail){ + qunlock(&s->alock); + resign(s); + } + + /* + * get a buffer + */ + lock(&servalloc); + b = servalloc.bfreel; + if(b == 0){ + print("no serv buffers\n"); + unlock(&servalloc); + continue; + } + servalloc.bfreel = b->next; + unlock(&servalloc); + + /* + * wait for something to happen + */ + n = (*devtab[cin->type].read)(cin, b->buf, sizeof(b->buf)); + if(n <= 0) + error(Ehungup); + + /* + * create a new process if none are waiting to + * take over + */ + if(s->alock.head == 0) + if(reinforce(s) == 0) + continue; + qunlock(&s->alock); + + /* + * process an event + */ + (*doit)(cout, b->buf, n); + + /* + * release the buffer + */ + lock(&servalloc); + b->next = servalloc.bfreel; + servalloc.bfreel = b; + unlock(&servalloc); + } +} diff --git a/port/stnoether.c b/port/stnoether.c new file mode 100644 index 0000000000000000000000000000000000000000..ee819e9c6e9b94fecc673cf65afa9d450898bad9 --- /dev/null +++ b/port/stnoether.c @@ -0,0 +1,218 @@ +/* + * ethernet specific multiplexor for nonet + * + * this line discipline gets pushed onto an ethernet channel + * to demultiplex/multiplex nonet conversations. + */ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" + +static void etherparse(uchar*, char*); +static void noetherclose(Queue*); +static void noetheriput(Queue*, Block*); +static void noetheropen(Queue*, Stream*); +static void noetheroput(Queue*, Block*); + +/* + * ethernet header of a packet + */ +typedef struct Etherhdr Etherhdr; + +struct Etherhdr { + uchar d[6]; + uchar s[6]; + uchar type[2]; + uchar circuit[3]; /* circuit number */ + uchar flag; + uchar mid; /* message id */ + uchar ack; /* piggy back ack */ + uchar remain[2]; /* count of remaing bytes of data */ + uchar sum[2]; /* checksum (0 means none) */ +}; +#define EHDRSIZE 24 +#define EMAXBODY (1514-HDRSIZE) /* maximum ethernet packet body */ +#define ETHER_TYPE 0x900 /* most significant byte last */ + +/* + * the ethernet multiplexor stream module definition + */ +Qinfo noetherinfo = +{ + noetheriput, + noetheroput, + noetheropen, + noetherclose, + "noether" +}; + +/* + * perform the ether specific part of nonetconnect. just stick + * the address into the prototype header. + */ +void +noetherconnect(Noconv *cp, char *ea) +{ + Etherhdr *eh; + + eh = (Etherhdr *)cp->media->rptr; + etherparse(eh->d, ea); + eh->type[0] = ETHER_TYPE>>8; + eh->type[1] = ETHER_TYPE; +} + +/* + * set up an ether interface + */ +static void +noetheropen(Queue *q, Stream *s) +{ + nonetnewifc(q, s, 1514, 60, 14, noetherconnect); +} + +/* + * tear down an ether interface + */ +static void +noetherclose(Queue *q) +{ + Noifc *ifc; + + ifc = (Noifc *)(q->ptr); + nonetfreeifc(ifc); +} + +/* + * configure the system + */ +static void +noetheroput(Queue *q, Block *bp) +{ + Noifc *ifc; + + ifc = (Noifc *)(q->ptr); + if(bp->type != M_DATA){ + if(streamparse("config", bp)){ + if(*bp->rptr == 0) + strcpy(ifc->name, "nonet"); + else + strncpy(ifc->name, (char *)bp->rptr, sizeof(ifc->name)); + } else + PUTNEXT(q, bp); + return; + } + PUTNEXT(q, bp); +} + +/* + * Input a packet and use the ether address to select the correct + * nonet device to pass it to. + * + * Simplifying assumption: one put == one packet && the complete header + * is in the first block. If this isn't true, demultiplexing will not work. + */ +static void +noetheriput(Queue *q, Block *bp) +{ + Noifc *ifc; + int circuit; + Noconv *cp, *ep; + Etherhdr *h; + Etherhdr *ph; + ulong s; + Block *nbp; + int next; + Nocall *clp; + + if(bp->type != M_DATA){ + PUTNEXT(q, bp); + return; + } + + ifc = (Noifc *)(q->ptr); + h = (Etherhdr *)(bp->rptr); + circuit = (h->circuit[2]<<16) | (h->circuit[1]<<8) | h->circuit[0]; + s = (h->sum[1]<<8) | h->sum[0]; + if(s && s!=nonetcksum(bp, 14)){ + print("checksum error %ux %ux\n", s, (h->sum[1]<<8) | h->sum[0]); + freeb(bp); + return; + } + + /* + * look for an existing circuit. + */ + ep = &ifc->conv[conf.nnoconv]; + for(cp = &ifc->conv[0]; cp < ep; cp++){ + if(circuit==cp->rcvcircuit && canqlock(cp)){ + ph = (Etherhdr *)(cp->media->rptr); + if(circuit == cp->rcvcircuit + && memcmp(ph->d, h->s, sizeof(h->s)) == 0){ + cp->hdr->flag &= ~NO_NEWCALL; + bp->rptr += ifc->hsize; + nonetrcvmsg(cp, bp); + qunlock(cp); + return; + } + qunlock(cp); + } + } + + /* + * if not a new call, then its misaddressed + */ + if((h->flag & NO_NEWCALL) == 0) { + freeb(bp); + return; + } + + /* + * Queue call in a circular queue and wakeup a listener. + */ + lock(&ifc->lock); + next = (ifc->wptr + 1) % Nnocalls; + if(next == ifc->rptr){ + /* no room in the queue */ + unlock(&ifc->lock); + freeb(bp); + return; + } + clp = &ifc->call[ifc->rptr]; + sprint(clp->raddr, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux", + h->s[0], h->s[1], h->s[2], h->s[3], h->s[4], h->s[5]); + clp->circuit = circuit^1; + bp->rptr += ifc->hsize; + clp->msg = bp; + ifc->wptr = next; + unlock(&ifc->lock); + wakeup(&ifc->listenr); +} + +/* + * parse an ethernet address (assumed to be 12 ascii hex digits) + */ +static void +etherparse(uchar *to, char *from) +{ + int tdig; + int fdig; + int i; + + if(strlen(from) != 12) + error(Ebadnet); + + for(i = 0; i < 6; i++){ + fdig = *from++; + tdig = fdig > 'a' ? (fdig - 'a' + 10) + : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0')); + fdig = *from++; + tdig <<= 4; + tdig |= fdig > 'a' ? (fdig - 'a' + 10) + : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0')); + *to++ = tdig; + } +} diff --git a/port/sturp.c b/port/sturp.c index ed99aea02ef32ca92b4d748dbcf4ceaf99c0bb72..109696ab52a52ef5abebc60e880397201f9a079a 100644 --- a/port/sturp.c +++ b/port/sturp.c @@ -206,7 +206,10 @@ urpclose(Queue *q) * if 2 minutes elapse, give it up */ up->state |= CLOSING; - tsleep(&up->r, isflushed, up, 2*60*1000); + if(!waserror()){ + tsleep(&up->r, isflushed, up, 2*60*1000); + poperror(); + } up->state |= HUNGUP; qlock(&up->xmit); @@ -944,15 +947,23 @@ urpkproc(void *arg) for(;;){ for(up = urp; up < eup; up++){ if(up->state==0 || (up->state&HUNGUP)) - break; + continue; if(!canqlock(up)) continue; - if(up->state==0 || (up->state&HUNGUP)) - break; + if(waserror()){ + qunlock(up); + continue; + } + if(up->state==0 || (up->state&HUNGUP)){ + qunlock(up); + poperror(); + continue; + } if(up->iseq!=(up->lastecho&7) && !QFULL(up->rq->next)) sendack(up); output(up); qunlock(up); + poperror(); } tsleep(&urpkr, return0, 0, 1000); } diff --git a/port/sysfile.c b/port/sysfile.c index c34e9eb0997458b6f7fefa8ea0ea5917437e1ac6..b15a6b8b2e49d466ca84fdd71565caa102ee98a5 100644 --- a/port/sysfile.c +++ b/port/sysfile.c @@ -29,7 +29,7 @@ fdtochan(int fd, int mode) { Chan *c; - c = 0; /* set */ + c = 0; /* set */ if(fd<0 || NFD<=fd || (c=u->fd[fd])==0) error(Ebadfd); if(mode<0 || c->mode==ORDWR) @@ -490,3 +490,19 @@ sysfwstat(ulong *arg) (*devtab[c->type].wstat)(c, (char*)arg[1]); return 0; } + +#ifdef asdf +long +sysfilsys(ulong *arg) +{ + Chan *cin, *cout; + + cin = fdtochan(arg[0], OREAD); + cout = fdtochan(arg[1], OWRITE); + validaddr(arg[2], 1, 0); + if((cin->qid.path&CHDIR) || (cout->qid.path&CHDIR)) + error(Ebadarg); + service((char *)arg[2], cin, cout, filsys); + return 0; +} +#endif