## 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; i<conf.nenv-1; i++)
envalloc.earena[i].next = &envalloc.earena[i+1];
envalloc.earena[conf.nenv-1].next = 0;
}
void
envinit(void)
{
}
/*
* Make sure e->val 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 || 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; i<pg->nenv; 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; i<pg->nenv; 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; ev<envalloc.vfree; ev+=ev->n)
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
|