Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/gnot/devenv.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## 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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.