## diffname gnot/devenv.c 1990/03091 ## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/devenv.c 0a #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("compactpte 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(0, 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(0, 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, s+1, 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&CHDIR)){ pg = u->p->pgrp; lock(pg); pg->etab[c->qid-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&CHDIR)){ pg = u->p->pgrp; lock(pg); pg->etab[c->qid-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 & CHDIR) error(0, Eperm); pg = u->p->pgrp; lock(pg); ep = &pg->etab[c->qid-1]; e = ep->env; if(!e){ unlock(pg); error(0, 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 != CHDIR) error(0, 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(0,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(0, Enoenv); } }else i = pg->nenv++; c->qid = 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 & CHDIR) error(0, Eperm); pg = u->p->pgrp; lock(pg); ep = &pg->etab[c->qid-1]; e = ep->env; if(!e){ unlock(pg); error(0, 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(0, Egreg); } void envclose(Chan * c) { Pgrp *pg; if(c->qid & CHDIR) return; pg = u->p->pgrp; lock(pg); pg->etab[c->qid-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 & CHDIR) return devdirread(c, a, n, 0, 0, envgen); pg = u->p->pgrp; lock(pg); e = pg->etab[c->qid-1].env; if(!e){ unlock(pg); error(0, 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-1].env; /* caller checks for CHDIR */ if(!e){ unlock(pg); error(0, 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(0, 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)); } void envuserstr(Error *e, char *buf) { consuserstr(e, buf); } void enverrstr(Error *e, char *buf) { rooterrstr(e, buf); } . ## diffname gnot/devenv.c 1990/0802 ## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/devenv.c /n/bootesdump/1990/0802/sys/src/9/68020/devenv.c 146c panic("compactenv copying too much"); . ## diffname gnot/devenv.c 1990/11211 ## diff -e /n/bootesdump/1990/0802/sys/src/9/68020/devenv.c /n/bootesdump/1990/11211/sys/src/9/68020/devenv.c 546,558d 503c error(Egreg); /* perhaps should zero fill */ . 487c error(Eio); . 484c e = pg->etab[c->qid.path-1].env; /* caller checks for CHDIR */ . 454c error(Eio); . 451c e = pg->etab[c->qid.path-1].env; . 447c if(c->qid.path & CHDIR) . 416c pg->etab[c->qid.path-1].chref--; . 412c if(c->qid.path & CHDIR) . 404c error(Egreg); . 391c error(Enonexist); . 387c ep = &pg->etab[c->qid.path-1]; . 383,384c if(c->qid.path & CHDIR) error(Eperm); . 365c c->qid.path = i+1; . 361c error(Enoenv); . 349c error(Enoenv); . 336,337c if(c->qid.path != CHDIR) error(Eperm); . 295c error(Egreg); . 291c ep = &pg->etab[c->qid.path-1]; . 287,288c if(c->qid.path & CHDIR) error(Eperm); . 265c pg->etab[c->qid.path-1].chref++; . 262c if(!(c->qid.path&CHDIR)){ . 250c pg->etab[c->qid.path-1].chref++; . 247c if(!(c->qid.path&CHDIR)){ . 227c devdir(c, (Qid){s+1,0}, e->name, e->val? e->val->len : 0, 0666, dp); . 176c error(Enoenv); . 158c error(Enoenv); . ## diffname gnot/devenv.c 1990/1210 # deleted ## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/devenv.c /n/bootesdump/1990/1210/sys/src/9/68020/devenv.c 1,545d